foo(array(...))和foo($ x = array(...))之间有什么区别?

时间:2012-04-20 13:09:28

标签: php

见这个例子:

此类扩展DOMElement。每个DOMElement都必须是其中的一部分 任何DOMDocuement都可以修改。

class Xmlrize  extends DOMElement
{
    private static $dom;

    public function __construct(/*. string .*/ $name,$value =null) {
        parent::__construct($name,$value,null);
    if(!self::$dom) {
            self::$dom = new DOMDocument('1.0','UTF-8');
        }
        self::$dom->appendChild($this);
    }
}

用于将数组添加到DOM中。如果数组的值不是Xmlrize,那么我忽略它。

class Attributes extends Xmlrize {

    public function __construct(array $attributes)
    {
        parent::__construct('Attributes');

        foreach($attributes as $name => $value) {
            $element = new Xmlrize($name);
            if($value instanceof Xmlrize)
                $element->appendChild($value);
            $this->appendChild($element);
        }
    }
}

您可以在构造函数

中添加属性实例
class Html extends Xmlrize {

    public function __construct(Attributes $obj) {
        parent::__construct('html');
        $this->addAttributes($obj);
    }

此方法显示if属性是否为Xmlrize的实例。

    protected function addAttributes(Attributes $attributes)
    {
        foreach($attributes->childNodes as $attribut) {
           if($attribut->childNodes->length == 1) {
                $item = $attribut->childNodes->item(0);
            echo $attribut->nodeName.': ';
            echo $item->nodeName.' has value '.$item->nodeValue.'. ';
            echo 'Is it DomElement? ';
            echo ($item instanceof DomElement) ? 'true' : 'false';
            echo '. Is it Xmlrize? ';
            echo ($item instanceof Xmlrize) ? 'true' : 'false';
            echo '.'.PHP_EOL;
           }
        }
        return null;
    }
}

按阵列启动属性的示例。看到差异!

/* works as expected */
$like = new Html(new Attributes(
            $xx =  array('XXX'=> new Xmlrize('foo', 'baar'))
));

/* do not work as exptected */
$like = new Html(new Attributes(
              array('XXX'=> new Xmlrize('foo', 'baar'))
));
?>

上面的示例返回:

XXX: foo has value baar. Is it DomElement? true. Is it Xmlrize? true.
XXX: foo has value baar. Is it DomElement? true. Is it Xmlrize? false.

为什么我添加'$ xx ='该元素被视为Xmlrize,如果不是,则不是?

2 个答案:

答案 0 :(得分:1)

恭喜,您在PHP的DOM实现中发现了一个错误。我花了一些时间处理你的代码,我能够将错误的行为缩小到这个简单的测试用例:

class MyElement extends DOMElement { }

// #1 - okay
$dom = new DOMDocument();
$e = new MyElement("e");
$dom->appendChild($e);
echo get_class($dom->childNodes->item(0)) . "\n";

// #2 - wrong
$dom = new DOMDocument();
$dom->appendChild(new MyElement("e"));
echo get_class($dom->childNodes->item(0)) . "\n";

// #3 - wrong
$dom = new DOMDocument();
$e = new MyElement("e");
$dom->appendChild($e);
$e = null;
echo get_class($dom->childNodes->item(0)) . "\n";

这显然是PHP中的一个错误,但这就是为什么会发生这种情况。 PHP中的每个对象都有一个引用计数(在任何地方有多少引用此对象)。当你调用$dom->appendChild(...)时,这个函数应该在内部增加对象的引用计数,但事实并非如此。当您运行示例#1时,一切似乎都很好,但在示例#2中,对象是“临时”创建的(仅用于调用),引用计数为1.当appendChild完成时,PHP将引用减少为0因此从内存中删除对象。

现在出现了棘手的部分:你现在应该想“哇,这意味着有一些指向解除分配(死机)内存的指针,程序应该严重崩溃”。但这并不仅仅是因为PHP的内存管理器并没有真正解除分配未使用的内存,而只是将其标记为已释放。所以你仍然可以从中读取,虽然内存的内容可能已经被另一个分配改变了。这才是真正发生的事情。我用调试器检查了对象是否真的被释放了(显然不应该,它应该有来自DOM层次结构的引用)。

现在你应该做的是1)向PHP的网站提交一个错误报告,2)要么停止使用DOMElement类,要么确保你“追加”到DOM层次结构的每个对象都是其他地方的引用。 / p>

此外,如果还不清楚,这就是为什么您在foo(array(...))foo($x = array(...))之间遇到不同的行为:第二个将数组分配给全局(或本地,取决于您调用它的位置) )变量,它将保存数组,在数组中,有一个对象的引用。因此不会被释放,并且DOM中的层次结构是可以的。

如果您要提交错误报告,请告诉我。如果你愿意,我会这样做,但是,嘿,这是你的错误:)

答案 1 :(得分:0)

foo(array(…))foo($x=array(…))之间的区别仅在于:

foo(array(…))只将数组作为参数传递给foo方法。

foo($x=array(…))将数组保存到$ x变量并将相同的变量$ x传递给foo方法。