Created
May 7, 2011 00:02
-
-
Save borzilleri/960035 to your computer and use it in GitHub Desktop.
PHP function to cast an object from one class to another.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Cast an object into a different class. | |
* | |
* Currently this only supports casting DOWN the inheritance chain, | |
* that is, an object may only be cast into a class if that class | |
* is a descendant of the object's current class. | |
* | |
* This is mostly to avoid potentially losing data by casting across | |
* incompatable classes. | |
* | |
* @param object $object The object to cast. | |
* @param string $class The class to cast the object into. | |
* @return object | |
*/ | |
function cast($object, $class) { | |
if( !is_object($object) ) | |
throw new InvalidArgumentException('$object must be an object.'); | |
if( !is_string($class) ) | |
throw new InvalidArgumentException('$class must be a string.'); | |
if( !class_exists($class) ) | |
throw new InvalidArgumentException(sprintf('Unknown class: %s.', $class)); | |
if( !is_subclass_of($class, get_class($object)) ) | |
throw new InvalidArgumentException(sprintf( | |
'%s is not a descendant of $object class: %s.', | |
$class, get_class($object) | |
)); | |
/** | |
* This is a beautifully ugly hack. | |
* | |
* First, we serialize our object, which turns it into a string, allowing | |
* us to muck about with it using standard string manipulation methods. | |
* | |
* Then, we use preg_replace to change it's defined type to the class | |
* we're casting it to, and then serialize the string back into an | |
* object. | |
*/ | |
return unserialize( | |
preg_replace( | |
'/^O:\d+:"[^"]++"/', | |
'O:'.strlen($class).':"'.$class.'"', | |
serialize($object) | |
) | |
); | |
} | |
?> |
To initialize properties on the new object that didn't exist in the old one (if the new extends the old), its class definition needs to have a __wakeup() method as unserialize doesn't call __construct().
Line 23 could be rewritten to allow either class
or $object
class to be a descendant of either:
if (!is_subclass_of($class, get_class($object)) && !is_subclass_of(get_class($object), $class)) {
throw new InvalidArgumentException(sprintf(
'%s is not a descendant of $object class: %s.',
$class,
get_class($object)
));
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you stick this inside a namespaced class as a method, then don't forget that the fully qualified class name won't be resolved by the alias, so you might want to do some sort of additional check for that before throwing an exception.