web-dev-qa-db-fra.com

Erreur fatale: niveau d'imbrication trop profond - dépendance récursive?

J'ai une hiérarchie complexe d'objets imbriqués, avec tous les objets enfants (stockés dans un tableau d'objets dans la classe parente) contenant une propriété renvoyant à leur parent: assez simple et direct, sans réel problème. Si je fais un var_dump d'un objet de la hiérarchie, j'obtiendrai une référence récursive dans le dump, exactement comme je le pensais.

FIRSTGEN 
   _children array of objects of type SECONDGEN
      SECONDGEN #1
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #1
               _parent object of type SECONDGEN
            THIRDGEN #2
               _parent object of type SECONDGEN
      SECONDGEN #2
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #3
               _parent object of type SECONDGEN

J'ai récemment ajouté de nouveaux éléments à cette hiérarchie et ils ne suivent pas exactement le même schéma. Ils sont stockés dans un tableau d'objets du parent de niveau supérieur, mais contiennent une propriété les liant en retour, non à leur parent, mais à un frère. Quand je fais un var_dump maintenant, j'obtiens une "Erreur fatale: niveau d'imbrication trop profond - dépendance récursive?".

FIRSTGEN 
   _children_1 array of objects of type SECONDGEN_1
      SECONDGEN_1 #1
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #1
               _parent object of type SECONDGEN_1
            THIRDGEN #2
               _parent object of type SECONDGEN_1
      SECONDGEN_1 #2
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #3
               _parent object of type SECONDGEN_1
   _children_2 array of objects of type SECONDGEN_2
      SECONDGEN_2 #1
         _parent object of type SECONDGEN_1

Tout le reste du code fonctionne correctement, à l'exception de var_dump (). J'ai essayé de créer un exemple plus simple pour illustrer le problème afin de pouvoir donner un exemple en posant cette question. mais je n'ai pas été en mesure de le répliquer lors d'un court test, mais uniquement dans mon code plus complexe.

Je sais que la solution consiste à refactoriser la relation afin que mon tableau _children_2 d'objets SECONDGEN_2 soit conservé dans le parent SECONDGEN_1 approprié, ce qui rend la relation parent "correcte" ... J'ai déjà commencé à le faire. Cependant, cette erreur m'intrigue et me demande si quelqu'un d'autre l'a rencontrée (et comment vous l'avez traitée vous-même).

22
Mark Baker

Ressemble à une limitation de PHP dans le code à référencement automatique et tente de l'afficher avec print_r, var_dump, var_export ou d'effectuer une recherche à l'aide de in_array. En gros, il n’ya aucun moyen pour ces fonctions de savoir où arrêter la récurrence si un objet est référencé de manière circulaire.

Selon ce rapport de bogue le moyen le plus simple de reproduire ceci est:

$outText = var_export( $GLOBALS, true );
print_r($outText) ;

Autres rapports de bugs mention aussi, avec quelques cas de test supplémentaires. Je dirais que si cela n'est déclenché que dans var_dump, vous ne devriez pas trop vous inquiéter à ce sujet. J'appuie sans aucun doute la suggestion de Wrikken concernant xdebug si c'est à des fins de débogage.

10
Fanis

Cela se produit également si vous comparez des objets récursifs en utilisant == au lieu de ===

Si vous avez besoin de comparer des instances d'objet réelles utilisez toujours l'opérateur de comparaison strict === car il ne compare que si les objets font référence à la même instance de la même classe.

Brève explication:

Si vous comparez des objets à l'aide de $object == $objectToCompareWith, PHP compare chaque attribut et valeur du premier objet avec le second. Cette comparaison est récursive par rapport aux objets qui sont des propriétés des objets comparés.

Cela signifie que si les deux objets partagent un attribut avec la valeur d'un objet, PHP effectue la même comparaison == entre ces objets d'attribut. Désormais, dès que l'un de ces objets d'attribut est récursif (par exemple, un objet à référence automatique), la comparaison est également rétablie jusqu'à ce que le niveau maximal d'imbrication soit atteint.

Comme indiqué dans les commentaires de Josh Stuart et de mazatwork, il est possible de forcer une comparaison stricte lors de l’utilisation de fonctions de tableaux telles que in_array() et array_search() en définissant leurs paramètres $strict respectifs sur true.

Richard Lord: "Niveau de nidification trop profond - dépendance récursive?"

PHP Manual: "Comparaison d'objets"

68
flu

Parfois (mais rarement, car il y a peu de commandes valides utilisées pour ce type de contrôles), cela se produit et tant que votre code fonctionne correctement, je ne lui donnerais pas vraiment une pensée qu'un var_dump (un outil de débogage, pas un outil de production) ne peut pas s'en sortir. avec ça. Cependant, si vous avez toujours besoin de var_dump, je vous recommande vivement de lancer xdebug, dans lequel vous pouvez définir la profondeur maximale affichée par le var_dump, la longueur maximale d'un vidage de chaîne et le nombre maximal d'enfants. .

3
Wrikken

J'avais la même erreur que vous mais dans un scénario totalement différent. Je poste la réponse au cas où quelqu'un d'autre arriverait de la même manière que moi.

Si vous essayez un tri personnalisé (usort) avec un tableau d'objets, voici ce que je devais faire:

function cmp($a, $b) {
    if($a->num_estimates == $b->num_estimates) return 0;

    return($a->num_estimates < $b->num_estimates) ? -1 : 1;
}
$c = usort(Company::$companies, "cmp");

Il s'est avéré que $object->num_estimates retournait occasionnellement un objet au lieu d'un nombre. Une fois que je me suis assuré qu'il retournait toujours un numéro, l'erreur a disparu.

1
Jacksonkr

Vous pouvez utiliser la méthode magique __toString pour définir une conversion personnalisée en chaîne. Parcourez votre objet et évitez de trop plonger dans les récursions lors de la mise en œuvre de __toString et tout devrait bien se passer. N'oubliez jamais et appelez accidentellement var_dump, var_export, print_r, etc.

Une fois que la méthode __toString a été définie, les éléments suivants fonctionnent parfaitement:

echo $ yourObjectHere;

C'est ma solution actuelle qui fonctionne bien, mais j'aimerais quand même quelque chose pour me protéger de ne pas oublier d'appeler var_dump, var_export et print_r.

0
Paul

Peut-être que cela aide quelqu'un.

Pour moi, une solution consistait à soulever pcre.recursion_limit dans le fichier php.ini. Il s’agit plutôt d’une solution de contournement temporaire lorsque vous lisez les autres réponses, car le problème réside probablement dans votre propre code.

0
pduersteler