2012-05-15 19 views
13

Mam tablica używam jako stos do przechowywania ścieżki przez drzewo. Każdy element wskazuje na węzeł w drzewie i chcę usunąć ostatni element, a następnie ustawić obiekt, do którego odnosi się ten element, na wartość null.Czy można wyrejestrować odwołanie w PHP?

Zasadniczo:

$node = array_pop($path); 
*$node = null; 

zakładając, że PHP miał operator '*' jako języki C-owski zrobić. Teraz mam brzydkie rozwiązanie zaczynając od węzła nadrzędnego i zapamiętywania, które dziecko wziąłem, a następnie ustawiając że null jak w:

if($goLeft) { 
    $parent->left = null; 
} else { 
    $parent->right = null; 
} 

powiedzieć, że jest brzydki, ponieważ tablica zawierająca ścieżkę tworzony jest przez funkcja publiczna w mojej klasie drzewa. Chciałbym wystawić możliwość pracy bezpośrednio na węzłach w ścieżce przez drzewo bez ujawniania szczegółów implementacji, które adresują idiosynkrazę (cechę?) W PHP. ATM Muszę dołączyć wartość boolean do wartości zwracanej (w tym przypadku $ goLeft), aby uniknąć obejścia problemu z dereferencją odniesienia.

To już drugi raz, kiedy napotkałem ten problem, więc jeśli ktoś wie, w jaki sposób mogę zrobić coś podobnego do pierwszego bloku kodu, proszę udostępnij!

(EDIT)

Po eksperymentach z wielu permutacji & „s i tablic, okazuje się, że podstawowym problemem było to, że błędnie zinterpretowała przyczynę błędu ja trafiałem.

Próbowałem

$a = ($x > $y) ? &$foo[$bar] : $blah; 

i got "błąd składni, niespodziewany '&'". Zinterpretowałam to jako oznaczający, że problem polegał na użyciu & -operatora na $foo[$bar]. W rzeczywistości okazuje się, że sprawcą jest? -operator, ponieważ działa doskonale. Poszedłem więc w dzikim pościgu za szukaniem rozwiązania problemu, który nie istniał. Dopóki nie zerwam łańcucha &, PHP robi to, co chcę, czyli operuje na obiekcie, do którego odnosi się zmienna (nie sama zmienna). Przykład

$a1 = new SomeClass; 
$a2 = &$a1; 
$a3 = &$a2; 
$a4 = &$a3; 

$a4 = 42; // This actually sets $a1 to 42 
var_dump($a1); // Emits 42 

Co zawiedli mnie jest to, że myślałem, że obiekty są przekazywane przez odniesienie i tak dookoła (to źle), więc nie sądzę & było konieczne, jeśli wyrażenie rozwiązany do obiektu. To znaczy:

class A { 
    public $b; 
} 

class B {} 

$a = new A; 
$a->b = new B; 

$c1 = $a->b; 
$c2 = &$a->b; 

$c1 = 42; // Merely assigns 42 to $c1 
$c2 = 42; // Assigns 42 to $a->b 

Okazuje się, że dokładna tego problemu polega na http://www.php.net/manual/en/language.oop5.references.php. Żałuję, że nie zatonął po raz pierwszy czytałem!

+1

Nie jestem pewien, tego właśnie chcesz, ale możesz użyć 'unset ($ parent-> left);' zamiast '$ parent-> left = null;' – Leri

+4

@PLB: Myślę, że masz na myśli ' unset', a nie 'unlink'. –

+1

@Rocket Jasne, robię. Jestem bardzo zmęczony. – Leri

Odpowiedz

7

Bardzo interesujące pytanie! Możliwe, że znalazłem obejście: jeśli zapełnisz tablicę odwołaniami do obiektów, operatorem &, możesz zniszczyć oryginalny obiekt, ustawiając tę ​​wartość tablicy na NULL. Musisz operować bezpośrednio na tablicy, zamiast używać zmiennej zwróconej przez array_pop. Następnie można pop tablicy, aby zwolnić tę pozycję (która następnie zawiera wartość NULL).

To co mi chodzi (na podstawie kodu Rocketa):

$a=(object)'a'; 
$b=array(&$a); 
$b[0] = NULL; 
// array still contains an element 
array_pop($b); 
// now array is empty 
var_dump($a); // NULL 

http://codepad.org/3D7Lphde

+0

Woah, schludny. To faktycznie działa! –

+0

@bfavaretto: Rozwiązałeś to! Niesamowite i takie proste! Jestem podekscytowany, że istnieje ładniejszy sposób robienia tego, co chciałem. Dzięki za wszystkich pomocników, zasady przepełnienia stosu! – kahulio

+0

Heh - to było prawie tak proste, jak myślałem, że powinno być ... wiedziałem, że ktoś dostanie się tam zanim wróciłem do domu: D Trik polega na użyciu odniesień w tablicy. – CD001

0

Po prostu nie przypisuj wartości zwracanej array_pop().

php > $test = array(1, 2, 3); 
php > $test2 = array(0 => &$test[0], 1 => &$test[1], 2 => &$test[2]); 
php > array_pop($test2); 
php > var_dump($test); 
array(3) { 
    [0]=> 
    &int(1) 
    [1]=> 
    &int(2) 
    [2]=> 
    int(3) 
} 
php > var_dump($test2); 
array(2) { 
    [0]=> 
    &int(1) 
    [1]=> 
    &int(2) 
} 
+0

Niezupełnie. To, czego chce, to "unset" ("$ test [2]"). Dlaczego zwracana jest wartość 'array_pop'? Modyfikujesz '$ test2' w obu kierunkach. –

+0

Cóż ... trudno jest uzyskać z opisu. :) – Narf

1

Chciałbym zapamiętać, gdzie to czytam, ale PHP działa poprzez utrzymywanie licznika odniesień do danego obiektu. Masz jakiś obiekt (np. Tree), który ma odniesienie do niektórych węzłów. Podczas korzystania z array_pop zwracane jest odwołanie do obiektu węzła (to jest tworzone dodatkowe odwołanie), ale pierwotne odwołanie nadal istnieje.Kiedy pojawi się unset, jest to zniszczone, ale oryginalny obiekt nie jest niszczony, ponieważ nadal ma to odniesienie. Jedynym sposobem na uwolnienie pamięci tego obiektu jest zniszczenie go osobiście (co wydaje się być tym, co robisz w drugim bloku kodu).

Wygląda na to, że PHP nie ma żadnej metody wymuszania deallokacji pamięci lub usuwania śmieci, więc jeśli nie będziesz ostrożnie obsługiwał swoich referencji, utkniesz.

To nie jest możliwe

PS: Wciąż jestem zdezorientowany tym, co próbujesz zrobić. Wyjaśnienie rakiety pomaga, ale co to jest $path i jak odnosi się do drugiego bloku?

+0

Myślę, że moje pierwotne pytanie było zbyt szczegółowe. To naprawdę nie ma znaczenia, że ​​pracuję ze stosem lub próbuję ustawić coś pustego. Muszę się lepiej tłumaczyć. Załóżmy, że mam zmienną, która zawiera odniesienie do czegoś - obiektu, innej zmiennej, to nie ma znaczenia. Przykład: '$ a = &$b;' Teraz chcę wykonać operację na rzeczy określonej przez '$ a', która w tym przypadku jest' $ b'. Może chcę ustawić '$ b' na wartość null, ciąg" alice "lub na inny obiekt. Nie ma znaczenia. W każdym razie to właśnie próbuję osiągnąć. – kahulio

+0

@kahulio jest to trochę trudne do wytłumaczenia. Zasadniczo, '$ a = & $ b' tworzy alias tablicy symboli od' $ a' do '$ b'. Oznacza to, że wszystko, co robisz, aby '$ a' wpłynęło bezpośrednio na' $ b'. Jeśli '$ b' jest obiektem, to' $ a = $ b' kopiuje odniesienie do obiektu z '$ b' do' $ a'. Operacje na obiekcie '$ a' mają taki sam efekt jak na obiekcie' $ b', ale jest to oddzielna pozycja tablicy symboli. Jeśli napiszesz do '$ a' (' $ a = 'blah'; ') to nie wpływa to w ogóle na' $ b'. 'array_pop' nie * nie * zwraca referencję (alias) i nie może, więc zapis do jej wartości zwracanej w żaden sposób nie wpływa na oryginalny obiekt, ani nie może tego zrobić. –

0
$one = 1; 
$two = 2; 
$array = array(&$one, &$two); 

// magic 
end($array); 
$array[key($array)] = NULL; 

var_dump($two); 
// NULL 

odniesienia w PHP umożliwia zmianę obiektu.

Powiązane problemy