如何在PHP中获得对根对象的迭代对象引用?
我有一个类,它接受一些基本的HTML5,并通过一些DOM魔法将其转换为一个扩展simpleXMLElement的类。这一切都始于一个名为XPage的“工厂”(我可能会稍微滥用这个术语)类 因此,我们可能有如何在PHP中获得对根对象的迭代对象引用?,php,oop,design-patterns,simplexml,Php,Oop,Design Patterns,Simplexml,我有一个类,它接受一些基本的HTML5,并通过一些DOM魔法将其转换为一个扩展simpleXMLElement的类。这一切都始于一个名为XPage的“工厂”(我可能会稍微滥用这个术语)类 因此,我们可能有 <?php $MyPage = new XPage($HTML); 理想情况下,我希望能够去 $MyPage->page()->body->header->RememberThisBitAs("foo"); 或者直觉上相似的东西。接下来应该发生的是,对象$My
<?php
$MyPage = new XPage($HTML);
理想情况下,我希望能够去
$MyPage->page()->body->header->RememberThisBitAs("foo");
或者直觉上相似的东西。接下来应该发生的是,对象$MyPage(类型为XPage)应该被传递为的引用,在本例中是html/body/header(这可能不是正确的XPath表示法,但希望您可以遵循)
其想法是,最常见的访问区域可以得到更顺利。这就是SimpleXML类(即使有我的扩展)遇到的问题,如果没有另一个工厂,它就无法做到这一点,同时也使XPage成为一个单例
然而,XPage类($MyPage)保存了“书签”数组。据我所知,没有办法在SimpleXML的迭代过程中传递引用,这样孩子或孩子的孩子就不能告诉工厂“请为我添加书签”
这会让我做一些讨厌的事情,比如:
$MyPage->addBookmark("foo",
$MyPage->page()->body->header->getChildren() );
这似乎是不对的
或
这不是很糟糕,但仍然“感觉”不对
如何在没有过度对象耦合或丑陋的自引用的情况下实现这一点
更新
我想知道是否可以使用debug_backtrace反向遍历类,但答案似乎是否定的
其他类似的测试向我表明,在可遍历堆栈中的任何其他元素上都无法访问在元素上设置类变量的值
我将把重点放在包装建议上
更新
SimpleXML实际上不是一个真正的对象,而是一个系统资源。这可以解释我的痛苦是从哪里来的。说出注释:
因此,对于所有对象来说,感觉就像是一个对象链在互相调用,事实并非如此。选项1:引用根
您可以修改XPage类的方法以返回XPage对象,而不是simplexmlements(或另一个扩展simplexmlement的类)。然后,该类可以有一个附加属性来保存对“root”元素的引用
因此,基本上您的“包装器类”看起来是这样的(前面是伪代码!):
因此,上面的用例如下所示:
$MyPage->page()->body->header->addReference("foo");
$MyPage->getReference("foo")->addChild('p',$MyParagraph);
选项2:添加一个id
或者,您可以只向元素添加一个id属性,并通过以下方式检索它:
$MyPage->page()->body->header->addAttribute("id", "foo");
$MyPage->xpath("//*[@id='foo']")->addChild('p',$MyParagraph);
考虑到Lars Ebert的答案的巨大推动,在考虑了许多疯狂的(不可行的)想法之后,我想到了这些想法,这让我明白了我需要的设计模式是一个委托类 由于我可能无法将专家函数添加到SimpleXMLElement扩展中,因此我使用神奇的方法创建了一个委托包装器。缺点是,这在我的IDE中并不能很好地发挥作用,但它在初始测试时完全可以工作。我已经拿出了一些只与我自己的项目有关的东西,但除此之外,这里是我正在使用的解决方案 它需要XPage对象实现一些相同的接口元素(我可能会定义一个接口),并且它使用我的扩展和指向自身的指针将SimpleXML元素传递到该委托包装器中,该委托包装器的行为类似于SimpleXML,但实际上是一个对象,可以将调试消息和自引用传递回XPage
<?php
/**
* A Delegation extension of SimpleXMLElement
*
* Designed to act like SimpleXML but builds a back traceable tree that expects
* XPage (or some other parent factory) to catch references and debug messages.
*
* @author Lord Matt
*
* @license
* Copyright (C) 2015 Matthew Brown
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
class AEWrapper {
protected $mother = null;
protected $MyAE = null;
public function __construct($MyAE,$mother) {
$this->MyAE = $MyAE;
$this->mother = $mother;
return $this;
}
public function __call($name, $arguments) {
try {
$result = call_user_method_array($name, $this->MyAE, $arguments);
} catch (Exception $e) {
$this->log_error('AEWrapper caught exception: ', $e->getMessage());
return FALSE;
}
if(is_object($result)){
return new AEWrapper($result,$this);
}
return $result;
}
public function __get($name) {
try {
$result = $this->MyAE->{$name};
} catch (Exception $e) {
$this->log_error('AEWrapper caught exception: ', $e->getMessage());
return FALSE;
}
if(is_object($result)){
return new AEWrapper($result,$this);
}
return $result;
}
public function &actual_simpleXML_obj_please(){
return $this->MyAE;
}
// methods exists in XPage
public function register_as($name,$what=null){
if($what===null){
$what = $this;
}
$this->mother->register_as($name,$what);
}
// [SNIP]
// Other project specific stuff here
// [/SNIP]
// methods exists in XPage
protected function log_error($error){
$this->mother->log_error('/'.$error);
}
}
MyAE=$MyAE;
$this->mother=$mother;
退还$this;
}
公共函数调用($name,$arguments){
试一试{
$result=调用\用户\方法\数组($name,$this->MyAE,$arguments);
}捕获(例外$e){
$this->log_错误('AEWrapper捕获异常:',$e->getMessage());
返回FALSE;
}
if(is_object($result)){
返回新的AEWrapper($result,$this);
}
返回$result;
}
公共函数获取($name){
试一试{
$result=$this->MyAE->{$name};
}捕获(例外$e){
$this->log_错误('AEWrapper捕获异常:',$e->getMessage());
返回FALSE;
}
if(is_object($result)){
返回新的AEWrapper($result,$this);
}
返回$result;
}
公共功能和实际操作(请参见){
返回$this->MyAE;
}
//方法存在于XPage中
公共函数寄存器\u as($name,$what=null){
如果($what==null){
$what=$this;
}
$this->mother->register\u as($name,$what);
}
//[剪报]
//这里还有其他特定于项目的东西
//[SNIP]
//方法存在于XPage中
受保护函数日志错误($error){
$this->mother->log_错误('/'.$error);
}
}
我想我在这个问题上做错了什么?除非得到指示,否则我无法学习。请稍等,你可能会得到答案。remembertisbitas(“foo”)是什么意思代码>?在每个元素中保留对顶级工厂的引用对您有用吗?@MatthewBrown这正是我回答的选项1。使用选项1,我们可能会遇到问题,我想我们可能会遇到这个问题-我不确定如何让扩展的simpleXML对象在迭代链中传递父引用,并且不确定是否需要包装每个simpleXML方法完全正确。我想我可以使用_call()-我只需要试试看。看起来我真正需要做的不仅仅是扩展SimpleXMLElement(我已经完成了),而是创建一个委托类,我想这就是你一直在说的。
$MyPage->page()->body->header->addReference("foo");
$MyPage->getReference("foo")->addChild('p',$MyParagraph);
$MyPage->page()->body->header->addAttribute("id", "foo");
$MyPage->xpath("//*[@id='foo']")->addChild('p',$MyParagraph);
<?php
/**
* A Delegation extension of SimpleXMLElement
*
* Designed to act like SimpleXML but builds a back traceable tree that expects
* XPage (or some other parent factory) to catch references and debug messages.
*
* @author Lord Matt
*
* @license
* Copyright (C) 2015 Matthew Brown
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
class AEWrapper {
protected $mother = null;
protected $MyAE = null;
public function __construct($MyAE,$mother) {
$this->MyAE = $MyAE;
$this->mother = $mother;
return $this;
}
public function __call($name, $arguments) {
try {
$result = call_user_method_array($name, $this->MyAE, $arguments);
} catch (Exception $e) {
$this->log_error('AEWrapper caught exception: ', $e->getMessage());
return FALSE;
}
if(is_object($result)){
return new AEWrapper($result,$this);
}
return $result;
}
public function __get($name) {
try {
$result = $this->MyAE->{$name};
} catch (Exception $e) {
$this->log_error('AEWrapper caught exception: ', $e->getMessage());
return FALSE;
}
if(is_object($result)){
return new AEWrapper($result,$this);
}
return $result;
}
public function &actual_simpleXML_obj_please(){
return $this->MyAE;
}
// methods exists in XPage
public function register_as($name,$what=null){
if($what===null){
$what = $this;
}
$this->mother->register_as($name,$what);
}
// [SNIP]
// Other project specific stuff here
// [/SNIP]
// methods exists in XPage
protected function log_error($error){
$this->mother->log_error('/'.$error);
}
}