Current Location: Home> Latest Articles> How to deal with complex object serialization with recursive references?

How to deal with complex object serialization with recursive references?

gitbox 2025-05-19

In PHP, the serialize() function is used to convert an object or array into a string for storage or transmission. However, the serialize() function may encounter problems when the object contains recursive references (i.e. the object references itself or references to each other). This article will discuss how to use the serialize() function to deal with complex object serialization problems with recursive references and provide related solutions.

What is a recursive reference?

Recursive reference refers to an object's properties that contain references to itself, or there is a relationship between multiple objects that reference each other. This situation is more common in complex data structures, especially in data models such as tree structures and graph structures. For example, suppose there is a parent object containing a child object, and the child object contains a reference to the parent object, this structure may cause the problem of recursive references.

Problems with serialize() and recursive reference

In PHP, the serialize() function is a standard way to convert PHP variables into strings. However, when there are recursive references inside the object, serialize() will fall into a dead loop because it will constantly try to serialize the same object, resulting in stack overflow or infinite recursion. Here is a simple example showing a case with recursive references:

 class Node {
    public $value;
    public $next;

    public function __construct($value) {
        $this->value = $value;
    }
}

$node1 = new Node(1);
$node2 = new Node(2);
$node3 = new Node(3);

$node1->next = $node2;
$node2->next = $node3;
$node3->next = $node1;  // Recursive reference

echo serialize($node1);

In the above code, $node1 , $node2 , and $node3 refer to each other, forming a loop. When serialize() is called, PHP will enter an infinite recursion state, resulting in an error.

How to solve the problem of recursive references?

To solve the problem of recursive references, we can adopt several methods. The two most common methods are to use serialize() 's custom processor, or use PHP's __sleep() and __wakeup() magic methods to control the serialization process of objects.

Method 1: Use the magic method of __sleep() and __wakeup()

The __sleep() method can process the object's properties before the object is serialized, while the __wakeup() method restores the object's state when the object is deserialized. We can use these methods to prevent problems caused by recursive references.

 class Node {
    public $value;
    public $next;

    public function __construct($value) {
        $this->value = $value;
    }

    public function __sleep() {
        // Here you can choose to serialize only the required attributes,避免Recursive reference
        return ['value']; 
    }

    public function __wakeup() {
        // Operations during deserialization,Relationships between objects can be re-established
    }
}

$node1 = new Node(1);
$node2 = new Node(2);
$node3 = new Node(3);

$node1->next = $node2;
$node2->next = $node3;
$node3->next = $node1;  // Recursive reference

echo serialize($node1);

In this example, the __sleep() method only returns the value attribute, so that only the attribute will be saved during the serialization process, avoiding the problem of recursive references.

Method 2: Handle recursive references

Another approach is to manually handle recursive references, which can be recorded by using a global array to record already serialized objects. This allows you to skip those already processed objects during serialization, thus avoiding the problem of infinite recursion. This method can be used well in complex object structures.

 class Node {
    public $value;
    public $next;

    public function __construct($value) {
        $this->value = $value;
    }
}

$visited = [];

function safe_serialize($obj) {
    global $visited;

    if (in_array(spl_object_hash($obj), $visited)) {
        return '';  // Avoid duplicate serialization
    }

    $visited[] = spl_object_hash($obj);

    return serialize($obj);
}

$node1 = new Node(1);
$node2 = new Node(2);
$node3 = new Node(3);

$node1->next = $node2;
$node2->next = $node3;
$node3->next = $node1;  // Recursive reference

echo safe_serialize($node1);

In this example, we use global $visited to save the identifier of the already serialized object (obtained via spl_object_hash() ). If an object has been serialized, then skip the object to avoid the problem of recursive references.

summary

To deal with complex object serialization problems with recursive references, you can customize serialization through PHP's built-in __sleep() and __wakeup() magic methods, or manually implement the serialization process to avoid repeated serialization. For different requirements and object structures, we can choose different methods to avoid dead loops or stack overflow errors caused by recursive references.