Current Location: Home> Latest Articles> Avoid infinite recursion traps when using serialize

Avoid infinite recursion traps when using serialize

gitbox 2025-05-19

In PHP programming, the serialize function is used to convert objects or arrays into strings, allowing them to be stored or transferred. However, when we serialize objects, if there are attributes in the object that refer to other objects and there is a mutual reference relationship between these objects (for example, A refers to B, and B refers to A), it may cause infinite recursion, which in turn causes stack overflow and eventually lead to script crash.

This article will explore how to avoid the trap of infinite recursion when using PHP's serialize function.

1. Basic use of serialization functions

The serialize function in PHP converts PHP values ​​into a format that can be stored or transferred. Usually used for persistent storage of objects or arrays. For example:

 <?php
$array = array("name" => "GitBox", "url" => "https://gitbox.net");
$serialized = serialize($array);
echo $serialized;
?>

2. The generation of infinite recursion

The trap of infinite recursion usually occurs when there is a circular reference between objects. For example:

 <?php
class Node {
    public $name;
    public $child;
    
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function setChild($child) {
        $this->child = $child;
    }
}

$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);

$serialized = serialize($node1); // This will result in infinite recursion
?>

In the above code, $node1 and $node2 refer to each other. When serialize($node1) is called, PHP will start serializing the $node1 object, which will serialize the child property of node1 , and the child property points to $node2 . Then PHP will continue to serialize $node2 and then return to serialize $node1 , which will result in infinite recursion, resulting in memory overflow.

3. How to avoid infinite recursion

To avoid falling into the trap of infinite recursion when using serialize , we can take the following methods:

3.1 Using __sleep magic method

PHP provides a magic method __sleep , which allows us to specify which properties should be serialized. If an object attribute causes recursion, use the __sleep method to filter out these attributes.

 <?php
class Node {
    public $name;
    public $child;
    
    public function __construct($name) {
        $this->name = $name;
    }

    public function setChild($child) {
        $this->child = $child;
    }

    public function __sleep() {
        return ['name']; // Serialization only $name property,Avoid circular references
    }
}

$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);

$serialized = serialize($node1); // No recursion happens here
echo $serialized;
?>

By returning a list of attributes in __sleep , we can control which attributes will be serialized, thus avoiding recursion.

3.2 Use SpplObjectStorage to store objects

SplObjectStorage is a class specifically used to store objects, which can avoid recursion problems caused by duplicate objects when storing. We can use it to avoid recursion problems.

 <?php
class Node {
    public $name;
    public $child;
    
    public function __construct($name) {
        $this->name = $name;
    }

    public function setChild($child) {
        $this->child = $child;
    }
}

$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);

$storage = new SplObjectStorage();
$storage->attach($node1);
$storage->attach($node2);

$serialized = serialize($storage); // No recursion happens here
echo $serialized;
?>

SplObjectStorage internally tracks references to objects, so we can avoid infinite recursion caused by circular references.

3.3 Custom __wakeup magic method

In some cases, we may want to do some additional checks when restoring the serialized object. PHP provides the __wakeup magic method, allowing us to perform some operations when deserializing objects.

 <?php
class Node {
    public $name;
    public $child;
    
    public function __construct($name) {
        $this->name = $name;
    }

    public function setChild($child) {
        $this->child = $child;
    }

    public function __wakeup() {
        if ($this->child === $this) {
            $this->child = null; // Prevent circular references during deserialization
        }
    }
}

$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);

$serialized = serialize($node1); 
echo $serialized;

$unserialized = unserialize($serialized); // The circular reference will be automatically cleared here
?>

In the __wakeup method, we detect and clear the loop reference to avoid recursion again when deserialized.


Through these methods, we can effectively avoid the infinite recursion problems that may be caused by PHP serialization, ensuring that the program does not crash due to circular references when processing objects. Hope this article helps you better understand how to avoid recursive traps when using serialize functions in PHP. If you have any questions, please continue to discuss!