Chers amis développeurs bonsoir. Je vous écris car je souhaite soumettre à votre sagacité un problème étrange. À défaut de pouvoir me venir en aide (seule ma dignité m’empêche encore de verser des larmes de frustration), peut-être au moins cela vous fera-t-il marrer. Je suis victime d’une version particulièrement vicieuse du bug de 17h30 (avec un combo « bug du vendredi de fin d’itération » compte triple).
Projet symfony. Je code, tout se déroule bien, fin de semaine, je balance mon code sur le serveur de recette, et je jette un coup d’œil sur l’environnement de prod. Horreur ! Page blanche ! Je vérifie la même page sous l’environnement de dev. Elle s’affiche correctement.
Je jette un coup d’œil dans la log apache :
child pid 16813 exit signal Segmentation fault (11)
Un sentiment d’immense lassitude m’envahit aussitôt.
Après une longue et pénible session profilage / debugage avec xdebug, je finit par circonvenir plus ou moins l’endroit du problème, et parviens même à le reproduire à l’envie. Vous allez voir, c’est surprenant :
$category = Article->getCategory(); // objet de classe 'Category' echo $category; // Affiche le titre de la catégorie printf('%s', $category); // Page blanche, segfault, sacrifice de chatons, etc.
Amusant, non ? Après quelques recherches, il semblerait que dans le contexte d’une fonction *printf, php n’utilise pas la fonction magique __toString().
Je teste donc :
<?php class Toto { private $tata; public function __construct($tata) { $this->tata = $tata; } public function __toString() { return (string) $this->tata . "\n"; } } $toto = new Toto('tutu'); echo $toto; printf('%s', $toto); // tutu // tutu
WTF ? Mais ça marche trés bien ! C’est donc un problème spécifique à mon code ? Je poursuis mon débuggage, et j’arrive ici :
$category = $article->getCategory(); // $category est de la classe sfOutputEscaperIteratorDecorator // qui hérite de sfOutputEscaperObjectDecorator // qui définit une fonction __toString() printf('%s', $category); // Appelle sfOutputEscaperObjectDecorator::__toString
Bon, allons voir sur place ce qui ne va pas.
class sfOutputEscaperObjectDecorator { … public function __toString() { // Jusqu'ici, tout va bien, mais dés l'instruction return, ça plante return $this->escape($this->escapingMethod, $this->value->__toString()); } // Je modifie donc la fonction pour obtenir ceci : public function __toString() { $value = $this->escape($this->escapingMethod, $this->value->__toString()); var_dump(gettype($value)); var_dump($value); die(); return $value; } // J'obtiens pour affichage : // 'String' // 'Titre de ma catégorie' // En revanche : public function __toString() { $value = $this->escape($this->escapingMethod, $this->value->__toString()); var_dump(gettype($value)); var_dump($value); // die(); return $value; } // Page blanche. Continuons dans l'étrange, avec quelques modifications de la même méthode : public function __toString() { $value = $this->escape($this->escapingMethod, $this->value->__toString()); die('ici'); // Affiche 'ici' return 'toto'; } public function __toString() { return 'toto'; // Affiche 'toto' } public function __toString() { $value = $this->escape($this->escapingMethod, $this->value->__toString()); return 'toto'; // Page blanche } }
Tout ça, bien sûr, c’est sur l’environnement de prod. En dev, tout se passe toujours normalement.
J’en suis là. Si quelqu’un a une bonne explication. En attendant, je crois que je vais aller me coucher de bonne heure. Bon week-end à tous.
7 Commentaires
Bug bien connu de php 5.2 sur les toString(). Monte en version, ou appele directement la propriété
Dsl sur iphone je suis un peu laconique.
Et si dans la fonction __toString() tu remplaces l’appel à $this->value->__toString() par « toto », ça plante toujours ?
J’ai comme l’impression que toString() est pas trop réentrante et que la rappeler depuis _toString() est la raison pour laquelle PHP part en vrille.
Salut,
Je crois que le truc le plus sûr pour éviter ce genre de désagrément, c’est de faire les développements & les tests sur le système de production.
Plus de souci d’installation, de différence de niveau qui génère des effets dont les causes sont difficiles à trouver, &c.
En plus, ça permet d’utiliser les systèmes de développement ou de test pour faire de la perruque… que du bonheur, je te dis…
Vale
Pierre
@Pierre Je crois qu’il y a méprise. Je parlais bien des environnements sous symfony, l’outil qui permet d’adapter ta conf simplement en changeant de controlleur frontal.
Les systèmes de dev et de production sont, à quelques poils près, les mêmes.
thibault> gaffe à l’impact du « poil près » quand même, des fois une version mineure de PHP différente (voire de distrib utilisée) et c’est le drâme.
Les stratégie du Decorator sont les même en dev et prod ?
Tiens c’est marrant, il m’est arrivé la même chose vendredi : gros bug de la page blanche sur l’environnement de prod (et pas en dev).
C’était également un bug de php et le code exécuté était le même en prod et en dev. Le bug était un « method_exists » qui provoquait également un « segmentation fault » de Apache ; ce bug est répertorié sur bug.php.net.
Je pense qu’en dev, il doit chargé plus de classe et donc ça empêche le problème de survenir. Il me semble avoir déjà eu ce bug il y’a 6 mois.
Si vous avez un problème de page blanche en prod, regardez du coté des method_exists.