基本设置。我有一个classA
实例,它是classX
的子类...在构造(或其他时候),我希望它加载另一个类classB
,它也是{{的子类1}}并用classX
原位替换自己。有点像工厂,但有一个透明地取代自己。如果需要,我可以用classB
包裹classB
,如果有办法(在运行时)更改对象的子类。
目前我使用classA
模仿MRO魔法,但看起来非常不优雅。这需要对classA::__call()
的调用者透明地完成,以便外部世界不会意识到classA/B
在构建之后已经用classA
替换了自己(或其他任何地方)物质)。
我知道在做这样的事情时PHP可能有点薄......我怀疑我们做不到,但这对我的情况会很方便。
另外,5.3但理想情况下(yuck)5.2 / x
提前致谢(希望我用Python编写代码)
答案 0 :(得分:1)
目前在PHP中无法实现......
没有做蠢事。
如果对象的每个实例都是一个引用,并且这些引用可以在$GLOBALS
中找到,并且对象知道每个实例都被调用了什么,那么你可以用新对象替换旧对象的每个引用。外界不会知道差异。
__call
魔法可能是实现目标最不疯狂的方式。
编辑:始终有runkit,它可以让您执行添加和删除类中方法的操作。但是,它是PECL扩展,甚至可能无法正常工作......
答案 1 :(得分:1)
好的,我对这个问题感兴趣,因为我已经达到了我想要发现PHP的确切限制的程度,包括像这样的小黑客。希望我能在深夜和我身上喝几杯啤酒。由于丑陋的hackishness,我实际上期待被投票。
显然,你不能$this = $that
。您也无法将正在尝试创建的全局变量更改为正在构造的对象,并且将尝试这样做将被忽略。正如查尔斯先前所说,这是不可能合理完成的。不是clone
,不是serialize()
,__construct()
内没有。
所以,如果你想让$ a首先成为A类的对象,然后将mid-creation转换为B类,尝试这种伪方法是不合理的:你必须连续两次调用A类的__construct。第一次处理A类的构造。第二次完成将对象转换为B类的对象.A类处理构造的前半部分,B类处理后半部分:
class A { function __construct() { $args = func_get_args(); // just to tell us the first round of __construct already occured if (array_key_exists(0, $args) AND $args[0]) { $GLOBALS['a'] = new B($GLOBALS['a']); // stop because "reconstruction" has stopped. Nothing else you can do to $a in this scope. $this->aprop2 = "yay"; // Seriously, stop. Don't bother putting more code at this point, you're wasting your time. Consider $a 'converted and returned' already. } // build on an object of class a here } } class B { function __construct($var) { // maybe you'd like to do something with old $a? If so, here's $var for you // continue constructing where A left off. } } $a = new A(); // object of class A $a->__construct(true); // object of class B
也许让A类的另一个方法更重要的是发声,它将全局$ a转换为B类的对象也是一样的,只是因为它看起来不像我的例子那么愚蠢。换句话说,你可能已经像PHP允许的那样做了。
编辑:但实际上,上述仅仅是$a = new A(); $a = new B($a);
。为了更好的代码可读性和可维护性,您可能希望不使用我的示例,而是选择实现为您创建和处理这些对象的工厂或处理程序类。我找到了一篇简短而富有洞察力的www.ibm.com文章,解释了工厂如何在PHP中应用它们的概念。从概念上讲,你可能想要一个像cd转换器一样的静态类,这就是Return by Reference - 处理任何范围内对象的变量引用 - 而Variable Objects(参见:midir的评论)该页面) - 动态设置或使用对象 - 派上用场。