La version qui ne posait aucun problème était la suivante :
<?php
error_reporting(E_STRICT);
class a { public function test($foo) {} }
class b extends a { public function test($foo, $bar) {} }
$b = new b();
?>
La version, qui était strictement identique fonctionnellement parlant, mais qui posait problème était quand à elle composée de trois fichiers.
Le premier fichier, nommons le a.php
, contenait le code suivant :
<?php
class a { public function test($foo) {} }
?>
Le second fichier, nommons le b.php
, contenait le code suivant :
<?php
class b extends a { public function test($foo, $bar) {} }
?>
Et le troisième et dernier fichier, all.php
, contenait le code suivant :
<?php
error_reporting(E_STRICT);
require('a.php');
require('b.php');
$b = new b();
?>
A l'éxécution de all.php
, PHP générait l'erreur suivante :
PHP Strict standards: Declaration of b::test() should be compatible with that of a::test() in /path/to/b.php on line 3
En résumé, inclure deux classes à l'aide de require()
ne revenait pas au même que de déclarer les deux classes dans le même fichier...
Afin d'être sur de mon fait, j'ai demandé à mes collégues et aux personnes présentes sur #jelix
sur irc
de confirmer qu'ils avait bien le même comportement, et à ma grande surprise, ce fût le cas.
Vous ne me croyez pas ? cela vous semble trop gros pour être vrai ? essayez...
Il y a 85% de chances, et voir même 100% de chances si vous n'avez jamais touché à la directive error_reporting
de votre php.ini
, que vous obteniez le même comportement.
En effet, error_reporting
a pour valeur par défaut E_ALL
.
Cela signifie que lorsque PHP interpréte le code de la première version, la directive error_reporting
n'a pas la valeur E_STRICT
, mais bien E_ALL
, puisque l'appel à error_reporting(E_STRICT)
n'a pas encore été éxécuté.
En effet, c'est lors de l'éxécution du script proprement dit, et donc après son interprétation, que l'appel à error_reporting(E_STRICT)
est effectué et que error_reporting
prend réellement la valeur E_STRICT
.
Or, avec la seconde version qui fait appel à require()
, les fichiers a.php
et b.php
sont inclus après l'interprétation du code et lors de son éxécution. Au moment des appels à require()
, error_reporting
a donc la valeur E_STRICT
.
Voici donc la raison pour laquelle deux codes fonctionnellement identiques n'ont pas le même comportement : l'environnement d'éxécution n'est tout simplement pas configuré de la même manière dans les deux cas.
La solution du problème est donc très simple : Il suffit de donner la valeur E_ALL|E_STRICT à la directive error_reporting
dans votre php.ini
.
Vicieux, non ?
8 réactions
1 De Jérémy - 19/02/2010, 12:46
Vicieux, oui et non, tu l'a très bien expliqué : l'erreur en question est généré lors de la compilation et la directive E_STRICT est interprété après la phase de compilation. C'est donc logique.
2 De Jean-Marc Fontaine - 19/02/2010, 12:49
Carrément même !
3 De doubleface - 19/02/2010, 13:01
J'avais eu le même problème, mais je n'avais pas assez creusé pour en connaitre la raison. Merci !
4 De desfrenes - 19/02/2010, 16:12
"PHP est vicieux"
attention, on pourrait y voir une légère inflexion de ton discours habituel
5 De tight - 25/02/2010, 12:26
A noter qu'à partir de php 5.3, l'error_reporting est sur E_ALL | E_STRICT par défaut dans le php.ini-development
6 De mageekguy - 25/02/2010, 16:12
@tight:
Cela dépend de ta distribution et/ou de l'OS sur lequel tu travailles...
Il n'y a pas que Linux/Debian/Ubuntu dans la vie ;).
7 De metagoto - 26/02/2010, 06:11
@fch
N'empêche que @tight a raison, le tarball des sources et le SVN contiennent bien E_ALL | E_STRICT à partir de 5.3. Si les distribs modifient cette valeur, alors c'est un autre problème.
8 De mageekguy - 26/02/2010, 08:57
@metagoto:
Effectivement, je confirme, E_ALL|E_STRICT est également présent par défault sous FreeBSD dans /usr/local/etc/php.ini-development.
Mais comme j'ai l'habitude d'utiliser celui de production, je suis passé à côtè.