PHP 和运行时子类化/对象重新分类

发布于 2024-09-08 21:52:21 字数 558 浏览 0 评论 0 原文

基本设置。我有一个 classA 实例,它是 classX 的子类...在构造时(或其他时候),我希望它加载另一个类 classB > 它也是 classX 的子类,并就地用 classB 替换它自己。有点像工厂,但可以透明地自我更换。如果需要,如果有办法(在运行时)更改对象的子类,我可以用 classA 包装 classB

目前我正在使用 classA::__call() 来模拟 MRO 魔法,但这看起来非常不优雅。这需要对 classA/B 的调用者透明地完成,以便外界不知道 classA 已将其自身替换为 classB< /code> 构建后(或其他任何地方)。

我知道 PHP 在做这样的事情时可能会有点薄……我怀疑我们不能,但这对我的情况来说会很方便。

另外,5.3,但理想情况下(恶心)5.2/x

提前致谢(希望我用 Python 编码)

Basic setup. I have a classA instance which is a subclass of classX ... On construction (or sometime else), I want it to load another class classB which is also a subclass of classX and replace itself with classB in situ. Sort of like a factory, but one that replaces itself transparently. If need be, I can wrap classB with classA if there is a way to (at runtime) change the subclass of an object.

Currently I am using classA::__call() to emulate MRO magic, but is seems very inelegant. This needs to be done transparently to the caller of classA/B so that to the outside world, it isn't aware that classA has replaced itself with classB after construction (or anywhere else for that matter).

I know PHP can be a bit thin when doing things like this ... I am suspecting we can't, but it would be handy for my situation.

Also, 5.3 but ideally (yuck) 5.2/x

Thanks in advance (wishing I was coding in Python)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

愛放△進行李 2024-09-15 21:52:21

好吧,我对这个问题很感兴趣,因为我已经达到了想要发现 PHP 的确切限制的地步,包括像这样的小技巧。希望我能在深夜喝点啤酒明白道理。由于丑陋的黑客行为,我实际上预计会被否决。

显然,你不能这样做$this = $that。您也无法在构造对象时更改当前尝试将其放入对象的全局变量,并且尝试这样做将被忽略。正如查尔斯之前所说,这是不合理的做法。不使用clone,不使用serialize(),也不使用__construct()

因此,如果您希望 $a 首先成为 A 类的对象,然后在创建过程中转换为 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 换片器一样的静态类,这就是 通过引用返回 - 在任何范围内使用对对象的变量引用 - 和 变量对象(参考:midir 在该页面上的评论) - 动态设置或使用对象 - 派上用场。

Ok, I've taken an interest in this question because I've reached the point where I'd like to discover the exact limits of PHP, including little hacks like this. Hopefully, I'll make sense this late at night and a few beers in me. Because of the ugly hackishness, I'm actually expecting to be downvoted.

Obviously, you can't do $this = $that. You also can't change the global variable you're currently trying to make into an object while it's being constructed, and attempting to do so will be ignored. As Charles said earlier, this can't be reasonably done. Not with clone, not serialize(), nothing within __construct().

So, unreasonably if you want $a to first become an object of class A, then convert mid-creation to class B, try this pseudo method: You'll have to call __construct of class A twice in a row. First time to handle construction of class A. Second time to complete the object converting it to class B. Class A handles the first half of construction, and class B the second half:

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

Maybe instead make another method of class A named more importantly sounding, which does the same thing to convert the global $a into object of class B, just so it doesn't look so stupid as my example. In other words, you're probably already doing it as best as PHP allows.

Edit: Really though, the above is nothing more than $a = new A(); $a = new B($a);. For better code readability and maintainability, you may want not to use my example and instead opt to implement a factory or handler class that creates and juggles these objects for you. I found a brief and insightful www.ibm.com article explaining the concept of factories how they are applied in PHP. Maybe conceptually, you want a static class that acts like a cd changer, and this is where Return by Reference - to work with a variable reference to the object in any scope - and Variable Objects (ref: midir's comments on that page) - to dynamically set or work with the object - comes in handy.

逆夏时光 2024-09-15 21:52:21

目前这在 PHP 中是不可能的......

不做愚蠢的事情。

如果对象的每个实例都是引用,并且这些引用可以在$GLOBALS中找到,并且该对象知道这些实例中的每一个被调用,那么您 >可以用新对象替换旧对象的每个引用。外界不会知道其中的区别。

然而,这是一个极其糟糕的想法。使用 __call 魔法可能是实现目标的最不疯狂的方法。

编辑:总是有 runkit,它可以让你做诸如添加之类的事情并从类中删除方法。然而,它是一个 PECL 扩展,甚至可能无法正常工作......

This is not currently possible in PHP...

Without doing stupid things.

If every instance of the object is a reference, and those references can be found in $GLOBALS, and the object knows what every one of those instances is called, you could replace each and every reference of the old object with your new object. The outside world won't know the difference.

This is, however, a spectacularly awful idea. Using __call magic is probably the least insane way of accomplishing your goal.

Edit: There's always runkit, which will let you do things like add and remove methods from classes. However, it's a PECL extension and might not even work correctly...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文