2012-05-15 2 views
13

У меня есть массив, который я использую в качестве стека для хранения пути через дерево. Каждый элемент указывает на узел в дереве, и я хочу вынуть последний элемент, а затем установить для объекта, упомянутого этим элементом, значение null.Можно ли разыменовать ссылку в PHP?

В основном:

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

при условии, что PHP был '*' оператор, как C-иш языками. Сейчас у меня есть уродливое решение, начиная с родительским узлом и запоминанием, какой ребенком я взял и затем установить, что в нуль, как в:

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

Я говорю, что это некрасиво, так как массив, содержащий путь создается с помощью public function в моем древовидном классе. Я хотел бы показать возможность работать непосредственно с узлами в пути через дерево, не подвергая детализации реализации, которая обращается к идиосинкразии (функции?) В PHP. ATM Мне нужно включить логическое значение в возвращаемом значении ($ goLeft в этом случае), чтобы я мог обанкротить невозможность разыменовать ссылку.

Это второй раз, когда я столкнулся с этой проблемой, поэтому, если кто-нибудь знает способ, я могу сделать что-то похожее на первый блок кода, пожалуйста, поделитесь!

(EDIT)

После экспериментов со многими перестановками & х и массивов, то получается, что основная проблема заключалась в том, что я неправильно истолковал причину ошибки я получал.

Я попытался

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

и получил "ошибка синтаксиса, неожиданный '&'". Я интерпретировал это как означающее, что проблема заключалась в использовании & -оператора на $foo[$bar]. На самом деле получается, что виновником является? -оператор, так как

if($x > $y) { 
    $a = &$foo[$bar]; 
} else { 
    $a = null; 
} 

работает отлично. Таким образом, я пошел на дикую охоту на гусей, пытаясь найти обходной путь для проблемы, которой не было. Пока я не нарушаю цепочку &, PHP делает то, что я хочу, чтобы работать с объектом, на который ссылается переменная (а не сама переменная). Пример

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

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

Что испортило меня, что я думал, что объекты передаются вокруг по ссылке в любом случае (это не так), так что я не думаю, что & было необходимо, если выражение разрешено к объекту. Я имею в виду:

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 

Оказывается, что эта точная проблема решается на http://www.php.net/manual/en/language.oop5.references.php. Хотелось, чтобы в первый раз я его прочитал!

+1

Я не уверен, это то, что вы хотите, но вы можете использовать 'unset ($ parent-> left);' вместо '$ parent-> left = null;' – Leri

+4

@PLB: Я думаю, вы имеете в виду ' unset', а не 'unlink'. –

+1

@Rocket Конечно, делаю. Я очень устал. – Leri

ответ

7

Очень интересный вопрос! Возможно, я нашел обходное решение: если вы заполнили массив ссылками на объекты, с оператором &, вы можете уничтожить исходный объект, установив для этого значения массива значение NULL. Вы должны работать с массивом напрямую, вместо использования переменной, возвращаемой array_pop. После этого вы можете вывести массив, чтобы освободить эту позицию (которая затем будет содержать значение NULL).

Это то, что я имею в виду (на основе кода ракеты):

$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, аккуратный. Это действительно работает! –

+0

@bfavaretto: Ты решил это! Удивительно и так просто! Я рад, что есть более красивый способ сделать то, что я хотел. Спасибо за помощь всем парням, правилам переполнения стека! – kahulio

+0

Хех - это было почти так же просто, как я думал, это должно быть ... знал, что кто-то доберется туда до того, как я вернусь домой: D Трюк использует ссылки в массиве. – CD001

0

Только не присваивайте возвращаемое значение 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

Не совсем. Он хочет, чтобы «исходный» объект был отменен ('$ test [2]'). Почему имеет значение return 'array_pop'? Вы изменяете '$ test2' в любом случае. –

+0

Ну ... это трудно найти из описания. :) – Narf

1

Мне жаль, что я не помню, где я это читал, но PHP работает, поддерживая счетчик ссылок на данный объект. У вас есть некоторый объект (например, Tree), который имеет ссылку на некоторые узлы. Когда вы используете array_pop, возвращается ссылка на объект узла (т. Е. Создается дополнительная ссылка), но исходная ссылка все еще существует.Когда вы unset выскочил ссылкой, который разрушен, но исходный объект не уничтожен, потому что Tree все еще имеет эту ссылку. Единственный способ освободить память об этом объекте состоит в том, чтобы он Tree уничтожил его лично (что похоже на то, что вы делаете во втором блоке кода).

PHP, похоже, не имеет способа для принудительного извлечения памяти или сбора мусора, поэтому, если вы тщательно не обрабатываете свои ссылки, вы застряли.

Это не возможно

P.S. Я все еще очень смущен тем, что вы пытаетесь сделать. Объяснение Rocket помогает, но что такое $path и как оно относится ко второму блоку?

+0

Я думаю, что мой оригинальный вопрос был слишком конкретным. Мне даже не кажется, что я работаю со стеклом или пытаюсь установить что-то нулевое. Мне нужно лучше объяснить себя. Предположим, у меня есть переменная, которая содержит ссылку на что-то - объект, другую переменную, это не имеет значения. Пример: '$ a = &$b;' Теперь я хочу выполнить операцию над вещью, называемой '$ a', которая в этом случае' $ b'. Возможно, я хочу установить '$ b' значение null, строку" alice "или другой объект. Не имеет значения. Во всяком случае, это то, чего я пытаюсь достичь. – kahulio

+0

@kahulio это немного сложно объяснить. В принципе, '$ a = & $ b' создает псевдоним таблицы символов от' $ a' до '$ b'. То есть все, что вы делаете с '$ a', напрямую влияет на' $ b'. Если '$ b' - это объект, то' $ a = $ b' копирует ссылку на объект из '$ b' в' $ a'. Операции над объектом '$ a' имеют тот же эффект, что и на объекте' $ b', но это отдельная запись таблицы символов. Если вы пишете в '$ a' (' $ a = 'blah'; '), это никак не влияет на' $ b'. 'array_pop' does * not * возвращает ссылку (псевдоним) и не может, поэтому запись в возвращаемое значение никак не влияет на исходный объект и не может. –

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

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

var_dump($two); 
// NULL 

Ссылка в PHP позволяет изменять объект.

Смежные вопросы