Skip to content

Instantly share code, notes, and snippets.

@borzilleri
Created May 7, 2011 00:02
Show Gist options
  • Save borzilleri/960035 to your computer and use it in GitHub Desktop.
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)
)
);
}
?>
@yuricoco
Copy link

hello!
thx for the code it was realy helpfull. I find the way you use the serialize and unserialise function realy fun hahaha but it's also well done. thx. I use it to directly set instance after the validation of a form. My code give me the stdClass and I'm casting it using your function :-D

@kirugan
Copy link

kirugan commented Jul 25, 2016

Is it works?

@jpuck
Copy link

jpuck commented Nov 16, 2016

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.

if( !class_exists($class) ){
    $class = __NAMESPACE__ . "\\$class";
}
if( !class_exists($class) )
    throw new InvalidArgumentException(sprintf('Unknown class: %s.', $class));

@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