可以在PHP中取消引用引用吗?

时间:2012-05-15 15:40:59

标签: php

我有一个数组,我用作堆栈来存储树中的路径。每个元素都指向树中的一个节点,我想关闭最后一个元素,然后将该元素引用的对象设置为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]上使用& -operator。事实证明,罪魁祸首是? - 操作者,如

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 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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

这是不可能的

P.S。我仍然对你想要做的事感到困惑。 Rocket的解释有帮助,但是什么是$path,它与第二个块有什么关系呢?

答案 2 :(得分: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)
}

答案 3 :(得分:0)

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

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

var_dump($two);
// NULL

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