Position actuelle: Accueil> Derniers articles> Évitez les pièges à récursion infinie lors de l'utilisation de sérialiser

Évitez les pièges à récursion infinie lors de l'utilisation de sérialiser

gitbox 2025-05-19

Dans la programmation PHP, la fonction sérialisée est utilisée pour convertir des objets ou des tableaux en chaînes, ce qui leur permet d'être stocké ou transféré. Cependant, lorsque nous sérialisons des objets, s'il y a des attributs dans l'objet qui se réfèrent à d'autres objets et qu'il existe une relation de référence mutuelle entre ces objets (par exemple, A fait référence à B, et B fait référence à a), il peut provoquer une récursion infinie, qui à son tour provoque un débordement de pile et finalement conduire à un crash de script.

Cet article explorera comment éviter le piège de la récursivité infinie lors de l'utilisation de la fonction de sérialisation de PHP.

1. Utilisation de base des fonctions de sérialisation

La fonction sérialisée dans PHP convertit les valeurs PHP en un format qui peut être stocké ou transféré. Généralement utilisé pour le stockage persistant des objets ou des tableaux. Par exemple:

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

2. La génération de récursivité infinie

Le piège de la récursivité infinie se produit généralement lorsqu'il y a une référence circulaire entre les objets. Par exemple:

 <?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); // Cela entraînera une récursivité infinie
?>

Dans le code ci-dessus, $ node1 et $ node2 se référent les uns aux autres. Lorsque Serialize ($ node1) est appelé, PHP commencera à sérialiser l'objet $ node1 , qui sérialisera la propriété enfant de Node1 , et la propriété enfant pointe vers $ node2 . Ensuite, PHP continuera de sérialiser $ node2 , puis reviendra à Serializer $ node1 , ce qui entraînera une récursivité infinie, ce qui entraîne un débordement de mémoire.

3. Comment éviter une récursivité infinie

Pour éviter de tomber dans le piège de la récursivité infinie lors de l'utilisation de sérialisation , nous pouvons prendre les méthodes suivantes:

3.1 Utilisation de la méthode de la magie __

PHP fournit une méthode magique __Sleep , ce qui nous permet de spécifier quelles propriétés doivent être sérialisées. Si un attribut d'objet provoque une récursivité, utilisez la méthode __Sleep pour filtrer ces attributs.

 <?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']; // Sérialisation uniquement $name propriété,Évitez les références circulaires
    }
}

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

$serialized = serialize($node1); // Aucune récursivité ne se produit ici
echo $serialized;
?>

En renvoyant une liste d'attributs dans __Sleep , nous pouvons contrôler les attributs qui seront sérialisés, évitant ainsi la récursivité.

3.2 Utilisez SPPLOBRIGDSTORAGE pour stocker des objets

SplObjectStorage est une classe spécifiquement utilisée pour stocker des objets, ce qui peut éviter les problèmes de récursivité causés par des objets en double lors du stockage. Nous pouvons l'utiliser pour éviter les problèmes de récursivité.

 <?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); // Aucune récursivité ne se produit ici
echo $serialized;
?>

SplobjectStorage suit en interne les références aux objets, nous pouvons donc éviter une récursivité infinie causée par des références circulaires.

3.3 Méthode magique personnalisée __wakeup personnalisée

Dans certains cas, nous pouvons vouloir faire des vérifications supplémentaires lors de la restauration de l'objet sérialisé. PHP fournit la méthode Magic __wakeup , nous permettant d'effectuer certaines opérations lors de la désérialisation des objets.

 <?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; // Empêcher les références circulaires pendant la désérialisation
        }
    }
}

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

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

$unserialized = unserialize($serialized); // La référence circulaire sera automatiquement effacée ici
?>

Dans la méthode __wakeup , nous détectons et effacons la référence de boucle pour éviter à nouveau la récursivité lors de la désérialisation.


Grâce à ces méthodes, nous pouvons éviter efficacement les problèmes de récursion infinie qui peuvent être causés par la sérialisation PHP, garantissant que le programme ne s'écrase pas en raison de références circulaires lors du traitement des objets. J'espère que cet article vous aidera à mieux comprendre comment éviter les pièges récursifs lors de l'utilisation de fonctions sérialiser dans PHP. Si vous avez des questions, veuillez continuer à discuter!