php serialize trickery

30 November 2006 // php. stuff.

A couple of code snippets that show how to do some intriguing stuff in oop php using serialization

 

changing the class of an instance

Convert object to a new class is fairly simple, because serializer stores class name along with object's data. The new mutated object inherits the properties from source object, but not methods.

function to_class($obj, $klass) {
    return unserialize(preg_replace(
        '/^O:\d+:\"(\w+)/',
        'O:' . strlen($klass) . ':"' . $klass,
        serialize($obj)));
}

# example

class A {
    public $a_var = "var in A\n";
    function a_method() {
        echo "method in A\n";
    }
}

class B {
    public $b_var = "var in B\n";
}

$old = new B;
$new = to_class($old, 'A');
$new->a_method();
echo $new->a_var;
echo $new->b_var;

accessing private members

More convoluted (and far dirtier) serialize trick for accessing private members from outside of the class.

function get_private($obj, $member) {
    $c = get_class($obj);
    $s = array("O:".strlen($c).":\"$c\"", "\000$c\000$member");
    $r = array("O:8:\"stdClass\"", "\001$c\001$member");
    $q = unserialize(str_replace($s, $r, serialize($obj)));
    return $q->{$r[1]};
}

function set_private(&$obj, $member, $value) {
    $c = get_class($obj);
    $s = array("O:".strlen($c).":\"$c\"", "\000$c\000$member");
    $r = array("O:8:\"stdClass\"", "\001$c\001$member");
    $q = unserialize(str_replace($s, $r, serialize($obj)));
    $q->{$r[1]} = $value;
    $obj = unserialize(str_replace($r, $s, serialize($q)));
}

# example:

class A {
    private $x = 'foo';
    function echo_priv() {
        echo "private x= ",  $this->x, "\n";
    }
}

$a = new A();

echo get_private($a, 'x'), "\n";

$a->echo_priv();
set_private($a, 'x', 'NEW');
$a->echo_priv();

Important notice: these functions are not for use in production environments. ;)

 
If you think this comment is spam or otherwise completely irrelevant here, feel free to hide it. The comment disappears immediately, though it is not deleted, so I have an option to "unhide" it later.
 

comment on this