Page 1 sur 1

set_error_handler produit un array *RECURSION* en PHP5

Posté : 06 mai 2007, 10:25
par Ripat
Bonjour à tous,

Petit rappel:
set_error_handler ("monGestionnaireErreur");
function monGestionnaireErreur ($errno, $errstr, $errfile, $errline, $errcontext){
  // ici traitement perso des erreurs
}
Depuis PHP5, le dernier élément passé à la fonction callback, errcontext produit un tableau récursif infini qui génère, au mieux un *RECURSION* lors de l'utilisation de print_r() ou, au pire et c'est mon cas, une consommation explosive de la mémoire si on utilise une fonction personnelle récursive pour afficher le contenu d'un tableau.

Le symbole actif fautif est GLOBALS.

Un peu comme dans le cas où on demande à un array de se mordre la queue:
$monTab = array();
// on rajoute à $monTab une référence à lui même.
$monTab[] = &$monTab;
print_r($monTab);
C'est lors du passage d'un site de PHP4 à PHP5 que je m'en suis aperçu. Prise de tête garantie.

Pour tester chez vous:
// gestionnaire perso
function GestionnaireErreur ($errno, $errstr, $errfile, $errline, $errcontext{
  echo '<pre>'. $errno.' '.$errstr.' '.$errfile.' '.$errline."\n";
  print_r(array_keys($errcontext));
  print_r($errcontext);
  echo '</pre>';
}

// changement de gestionnaire d'erreur
$ancienHandler = set_error_handler ("GestionnaireErreur");

// erreur intentionnelle
date(); 
Solution boîteuse:
unset($errcontext['GLOBALS']);
Ais-je raté un épisode de la série "upgrade PHP4 -> PHP5" ?

Posté : 06 mai 2007, 12:41
par titerm
$GLOBALS est un tableau récursif puisqu'il contient aussi $GLOBALS... etc..

Donc c'est normal d'avoir un pb de récursivité. Je n'ai jamais trouvé simple de moyen de détecter en php la récursivité. La solution que j'avais retenu était d'utiliser les fonctions standard telque var_dump ou print_r qui détectent nativement la récursivité et affiche comme tu l'as constaté *RECURSION*. A partir de la sortie de ces fonctions et avec des regexp, on peut customisé l'affichage. C'est typiquement ce que fait la fonction dump de debuggage du package pear.

Posté : 06 mai 2007, 13:54
par Ripat
$GLOBALS est un tableau récursif puisqu'il contient aussi $GLOBALS... etc..
En PHP5 pas en 4, d'où le problème. Je ne vois pas trop l'intérêt d'avoir changé le contenu de GLOBALS et lui faire faire référence à elle même mais bon.

Ce changement ne semble pas documenté. Et ça m'a fait perdre du temps.

Posté : 07 mai 2007, 15:38
par Genova
C'est assez logique que $GLOBALS pointe sur lui même, puisque $GLOBALS contient toutes les globales du script, et que $GLOBALS est une globale.

J'avais fait une fonction d'affichage récursif une fois pour remplacer print_r pour mes besoins personels, et la seule solution que j'avais trouvé pour gérer la récursivité était a chaque niveau de tableau d'ajouter une variable. Si la variable existait déjà, c'est que j'étais dans un cas récursif.