如何在PHP中获取对根对象的迭代对象引用?

Mat*_*att 8 php oop design-patterns simplexml

我有一个类,它需要一些基本的HTML5,并且有一些DOM魔术将它变成一个类,它是一个扩展的simpleXMLElement.这一切都始于一个名为XPage的"工厂"(我可能会略微滥用这个术语).

因此,我们可能会

<?php
$MyPage = new XPage($HTML);
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.我现在需要做的是选择XML文档的某些部分,以便它们可以"加入书签"(我确信它有一个更好的名称)所以你可以这样做

$MyPage->ThatBit("foo")->addChild('p',$MyParagraph);
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望能够去

$MyPage->page()->body->header->RememberThisBitAs("foo");
Run Code Online (Sandbox Code Playgroud)

或者直观相似的东西.然后应该发生的是对象$ MyPage(类型为XPage)应该传递参考,在这种情况下是html/body/header(可能不是正确的XPath表示法,但希望你可以遵循).

这个想法是最常见的访问区域可以更顺利地获得.这就是SimpleXML类(即使是我的扩展名)遇到的东西,如果没有另一个工厂,它也无法做到,而且XPage也是单例.

然而,它是XPage类($ MyPage),它包含"书签"数组.据我所知,没有办法在SimpleXML的迭代中传递引用,这样孩子或孩子的孩子就不能告诉工厂"请给我加书签".

这会让我做一些讨厌的事情:

$MyPage->addBookmark("foo", 
$MyPage->page()->body->header->getChildren() );
Run Code Online (Sandbox Code Playgroud)

这似乎不对.

要么

$MyPage->page()->body->header->RememberThisBitAs("foo",$MyPage);
Run Code Online (Sandbox Code Playgroud)

这不是那么糟糕但仍然"感觉"错了.

如何在没有过多的对象耦合或丑陋的自我引用的情况下处理这个问题?

更新

我想知道是否可以使用debug_backtrace反向遍历一个类,但答案似乎是否定的.

在PHP中,是否可以反向遍历Traversable类以查找根对象?

其他类似的测试表明,在可遍历堆栈中的任何其他元素上都无法访问在元素上设置类变量的值.

我将专注于包装器的建议.

更新

SimpleXML实际上不是真正的对象,而是系统资源.这可以解释我的痛苦来自哪里.说说明:http://php.net/manual/en/class.simplexmlelement.php

因此,对于所有对象感觉就像一串对象相互调用,实际上并非如此.

Lar*_*ert 4

选项 1:引用 root

您可以修改 XPage 类的方法以返回 XPage 对象而不是 simpleXMLElements(或扩展 simpleXMLElement 的另一个类)。然后,该类可以有一个附加属性,保存对“根”元素的引用。

所以基本上你的“包装类”看起来像这样(前面有伪代码!):

class Wrap extends simpleXMLElement
{
    private $root = null;
    private $refs = array();

    public function addReference($name, $element = null) {
        if($element === null) {
            $element = $this;
        }
        if($this->root === null) {
            $this->refs[$name] = $this;
        } else {
            $this->root->addReference($name, $this);
        }
    }

    public function getReference($name) {
        if($this->root === null) {
            return $this->refs[$name];
        } else {
            return $this->root->getReference($name);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以上面的用例看起来像这样:

$MyPage->page()->body->header->addReference("foo");

$MyPage->getReference("foo")->addChild('p',$MyParagraph);
Run Code Online (Sandbox Code Playgroud)

选项 2:添加 ID

或者,您可以只向元素添加一个 id 属性并通过以下方式检索它:

$MyPage->page()->body->header->addAttribute("id", "foo");

$MyPage->xpath("//*[@id='foo']")->addChild('p',$MyParagraph);
Run Code Online (Sandbox Code Playgroud)