15

我有一个数组用作堆栈来存储通过树的路径。每个元素都指向树中的一个节点,我想弹出最后一个元素,然后将该元素引用的对象设置为 null。

基本上:

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

假设 PHP 像 C-ish 语言一样有一个 '*' 运算符。现在我有一个丑陋的解决方案,从父节点开始并记住我带了哪个孩子,然后将其设置为 null,如下所示:

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

我说这很难看,因为包含路径的数组是由我的树类中的公共函数创建的。我想公开直接在通过树的路径中的节点上工作的能力,而不公开解决 PHP 中的特质(功能?)的实现细节。ATM 我需要在返回值中包含一个布尔值(在本例中为 $goLeft),这样我就可以解决无法取消引用引用的问题。

这是我第二次遇到这个问题,所以如果有人知道我可以做类似于第一块代码的方法,请分享!

(编辑)

在尝试了 & 和数组的许多排列之后,事实证明,基本问题是我误解了我得到错误的原因。

我试过

$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得到了解决。希望在我第一次阅读时就沉没了!

4

4 回答 4

7

非常有趣的问题!我可能找到了一种解决方法:如果您使用对象引用填充数组,使用&运算符,您可以通过将该数组值设置为来销毁原始对象NULL。您必须直接对数组进行操作,而不是使用array_pop. 之后,您可以弹出数组以释放该位置(然后将包含一个NULL值)。

这就是我的意思(基于 Rocket 的代码):

$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

于 2012-05-15T16:47:43.667 回答
1

我希望我能记住我在哪里读到的,但是 PHP 通过维护一个给定对象的引用计数器来工作。您有一些对象(例如 a Tree)引用了某些节点。使用 时array_pop,会返回对节点对象的引用(即创建附加引用),但原始引用仍然存在。当您unset弹出引用时,该引用已被破坏,但原始对象并未被破坏,因为Tree仍然具有该引用。释放该对象内存的唯一方法是Tree亲自销毁它(这似乎是您在第二个代码块中所做的事情)。

PHP 似乎没有任何强制内存释放或垃圾回收的方法,所以除非你仔细处理你的引用,否则你会被卡住。

这是不可能的

PS我仍然对你想要做什么感到困惑。Rocket 的解释很有帮助,但什么是$path,以及它与第二块有何关系?

于 2012-05-15T16:31:53.670 回答
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)
}
于 2012-05-15T16:27:31.333 回答
0
$one = 1;
$two = 2;
$array = array(&$one, &$two);

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

var_dump($two);
// NULL

php 中的引用允许您更改对象。

于 2012-05-15T17:03:15.823 回答