PHP and Runtime Subclassing / Object reclassification
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 a开发者_如何学JAVAm 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)
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.
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...
精彩评论