Maintaining Object Relationships with PHP Serialization

I ran into a rather difficult problem to solve objects that implement the interface Serializable. Take an example:

class A {
    public $b;
}

class B {
    public $a;
}

$a = new A;
$b = new B;

$a->b = $b;
$b->a = $a;

echo serialize($a); // O:1:"A":1:{s:1:"b";O:1:"B":1:{s:1:"a";r:1;}}
echo serialize($b); // O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"b";r:1;}}

$a = unserialize(serialize($a));
var_export($a === $a->b->a); // true

In this example, we see that when using the built-in PHP serialization function (regardless of whether we use the function __sleep()), cross-references between Aand Bare preserved ( r:1;).

However, if we want to ensure that the Serializable interface is used, a problem arises:

class A implements Serializable  {
    public $b;

    public function serialize() { return serialize($this->b); }
    public function unserialize($s) { $this->b = unserialize($s); }
}

class B implements Serializable {
    public $a;

    public function serialize() { return serialize($this->a); }
    public function unserialize($s) { $this->a = unserialize($s); }
}

$a = new A;
$b = new B;

$a->b = $b;
$b->a = $a;

echo serialize($a); // infinite loop crashes PHP

Since each serialization of objects is controlled independently, there is no global way to see if an object has already been serialized; there is no link to it. Then the functions serialize()are called in an infinite loop.

? , serialize()?

+5
3

Doctrine :

Serializable ( , , , ).

, , .

+3

:

function inStack( $cls, $func ) {
    $backTrace = debug_backtrace();
    for( $i = 2; $i < count( $backTrace ); ++$i  ) {
        if( isset( $backTrace[$i][ 'class' ] ) && $backTrace[$i][ 'class' ] == $cls &&
            isset( $backTrace[$i][ 'function' ] ) && $backTrace[$i][ 'function' ] == $func )
            return true;
    }
    return false;
}

class A implements Serializable  {
    public $b;

    public function serialize() {
        if( inStack( 'A', 'serialize' ) ) return '';
        return serialize( $this->b );
    }
    public function unserialize($s) {
        if( $s == '' ) return null;
        $b = unserialize( $s );
        if( $b !== null ) {
            $this->b = $b;
            $this->b->a = $this;
        }
    }
}

class B implements Serializable {
    public $a;

    public function serialize() {
        if( inStack( 'B', 'serialize' ) ) return '';
        return serialize( $this->a );
    }
    public function unserialize($s) {
        if( $s == '' ) return null;
        $a = unserialize( $s );
        if( $a !== null ) {
            $this->a = $a;
            $this->a->b = $this;
        }
    }
}

$a = new A;
$b = new B;

$a->b = $b;
$b->a = $a;

$a = unserialize( serialize( $a ) );
var_dump( $a === $a->b->a ); //true
+3

PHP , : ref.

Serializable, ​​ , . , , , .

, - , - . , , Serializable .

. - .

Taken in a word, the doctrine draft really has it already. Its form of serializing objects is the database itself. Just to open a little presentation, make sure that this is not what you are looking for.

+3
source

All Articles