Skip to content

Instantly share code, notes, and snippets.

@borzilleri
Created May 7, 2011 00:02
  • Star 21 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save borzilleri/960035 to your computer and use it in GitHub Desktop.
PHP function to cast an object from one class to another.
<?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)
)
);
}
?>
@Ruzgfpegk
Copy link

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().

@3m1n3nc3
Copy link

3m1n3nc3 commented Jan 2, 2024

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