I have a class where it may be necessary to change the object to a descendent class further down the line. Is this possible? I know that one option is to return a copy of it but using the child class instead, but it'd be nice to actually modify the current object... so:
class myClass {
protected $var;
function myMethod()
{
// function which changes the class of this object
recast(myChildClass);
}
}
class myChildClass extends myClass {
}
$obj = new myClass();
$obj->myMethod();
get_class_name($obj); // => myChildClass
Casting to change the object's type is not possible in PHP (without using a nasty extension). Once you instantiate a object, you can't change the class (or other implementation details) anymore...
You can simulate it with a method like so:
Usage:
But beware that it doesn't actually change the original class. It just creates a new one. And beware that this requires that the properties are public or have getter and setter magic methods...
And if you wanted some more checks (I'd suggest so), I'd add this line as the first line of
castAs
to prevent issues:Alright, since Gordon posted a very black-magic solution, I will do the same (using the RunKit PECL extension (warning: here be dragons):
So, instead of doing
new Foo
, you'd do something like this:And from within the class (as long as it was created with
getInstance
):Disclaimer: Don't do this. Really, don't. It's possible, but it's such a horrible idea...
This is not possible because while an instance of a child class is also an instance of a parent class, the reverse is not true.
What you could do is create a new instance of the child class and copy the values from the old object onto it. You can then return the new object which will be of type
myChildClass
.You can, as described in other answers, do it with nasty black magic PECL extensions.
Though, you seriously don't want it. Any problem you want to solve in OOP there's an OOP-compliant way to do it.
Runtime type hierarchy modifications are not OOP-compliant (in fact, this is consciously avoided). There are design patterns that should fit what you want.
Please, tell us why do you want that, I'm sure there must be better ways to do it ;)
For simple classes this may work (I am using this successfully in some rare cases):
Usage in my case:
More abstract:
Of course
TargetClass
has to inherit from the class ofsourceObject
and you have to make all protected and private properties public inTargetClass
to get this work.I use this to change
FormMapper
(https://github.com/sonata-project/SonataAdminBundle/blob/3.x/src/Form/FormMapper.php) on the fly toIndentedFormMapper
by adding a new method calledchain
:Redefining Classes
You can do this with the runkit PECL extension aka the "Toolkit from Hell":
runkit_class_adopt
— Convert a base class to an inherited class, add ancestral methods when appropriaterunkit_class_emancipate
— Convert an inherited class to a base class, removes any method whose scope is ancestralRedefining Instances
The runkit functions do not work on object instances. If you want to do that on object instances, you could theoretically do that by messing with the serialized object strings.
This is the realms of black magic though.
The code below allows you to change an instance to whatever other class:
Example:
Result:
As you can see, the resulting object is a
Bar
object now with all properties retaining their visibility butprop2
isNULL
. The ctor doesnt allow this, so technically, while you have aBar
child ofFoo
, it is not in a valid state. You could add a magic__wakeup
method to handle this somehow, but seriously, you dont want that and it shows why casting is ugly business.DISCLAIMER: I absolutely do not encourage anyone to use any of these solutions in production.