Question éthique

Eléphant du PHP | 185 Messages

30 déc. 2008, 23:17

Après quelques benchs, il s'avère plus rapide de faire ceci:

$test = new test;
$test->methode();

que

call_user_func(array('test', 'methode'));

Je sais très bien que ma méthode est static, mais PHP le reconnait très bien quand on instancie la classe, ce qui est 1) louche 2) plus rapide 3) plus pratique pour moi.

Alors, mieux vaut éviter ou je peux l'utiliser ?

ViPHP
ViPHP | 4674 Messages

31 déc. 2008, 00:27

Hey :),

Premièrement, on a pour habitude de mettre des parenthèses lors de l'utilisation du mot-clé new après le nom de la classe :
$object = new StdClass(); // bien :)
// au lieu de :
$object = new StdClass; // pas bien :(
Ensuite, quand tu utilises new, c'est la procédure classique/habituelle. On peut facilement interagir dessus via des optimisateurs de code (XCache par exemple). Alors que quand tu utilises un callback (un appel dynamique) avec call_user_func(), c'est forcément plus long car on n'utilise pas les même techniques. Je n'arrive pas à expliquer précisément les différences mais c'est logique que ce soit plus long. Au niveau de l'interprétation du code et du nombre de tests, ça n'a rien à voir.

En plus, écrire deux lignes lisibles, compréhensibles et « standards » ne va pas te tuer, alors qu'écrire une ligne moins lisibles, moins compréhensibles, moins fréquentes baisse les performances. Je ne saurai que trop de conseiller d'utiliser le mot-clé new qui est prévu pour ça, alors que call_user_func() est un moyen dynamique détourné pour arriver à nos fins. À utiliser que dans de rare cas (quand la dynamique est vraiment nécessaire, sinon ça ne se justifie pas).
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

31 déc. 2008, 01:03

Ta comparaison est faussée savageman. Tu compares un appel direct de méthode à un appel via une fonction "call_user_func".

Si tu veux appeler une méthode statique, alors utilise simplement "test::methode()".

Et bizarrement, j'ai l'intuition que ça sera plus rapide que tes deux autres essais...

Eléphant du PHP | 185 Messages

31 déc. 2008, 01:23

En fait, le nom de ma classe est dans une variable, je ne peux pas l'écrire directement, ça dépend de l'utilisateur qui me fournit de quoi connaitre la classe à utiliser...

En temps normal, je fais bien entendu Classe::methodeStatique(), mais je ne peux pas faire $classe::methodeStatique(), j'essaye donc de trouver un compromis rapide...

Les 3 solutions que j'ai trouvées sont :
- l'instanciation et l'appel comme une méthode dynamique avec la flèche ->
- call_user_func()
- ReflectionMethod() + invoke

Aucune d'elle ne me convient vraiment, c'est pourquoi j'ai posté mon message. ;) Quoi que c'est que vous me conseillez ?

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

31 déc. 2008, 01:40

À mon sens, si une partie de l'appel est dynamique (nom ou partie du nom de la fonction/méthode, nombre d'arguments), alors on devrait toujours passer par call_user_func().

L'instanciation fonctionne en effet, mais c'est une erreur de la part de PHP (et de son implémentation très très partielle de l'objet), qui ne devrait pas mener à ce genre de bidouille à mon avis ;)

Il faut peser le pour et le contre entre :
- la logique de ce que tu écris en respect avec l'API (pour : call_user_func)
- le risque pris (pour : call_user_func, car on n'est pas à l'abri qu'une future release de PHP lève une E_STRICT quand on appelle une méthode statique comme une méthode d'instance, puisque justement l'inverse lève actuellement une E_STRICT)
- la rapidité d'exécution (pour : instanciation)
- la lisibilité (subjectif)
C'est à toi de voir quel poids tu accordes à chacun de ses points pour faire ton choix. Mais il n'appartient qu'à toi.

ViPHP
ViPHP | 4674 Messages

31 déc. 2008, 01:42

Ça changera en PHP 5.3, mais pour l'instant, voici comment PHP traite tout ça :
  • quand on écrit class::constante, class est de type T_STRING et constante de type T_STRING ;
  • quand on écrit class::$attribute, class est de type T_STRING et $attribute de type T_VARIABLE ;
  • quand on écrit class::methode(), class est de type T_STRING et methode de type T_STRING ou T_VARIABLE.
C'est à dire que tu peux appeler une méthode façon dynamique :
class A {

    public static function method ( ) {

        return 'methode';
    }
}

$m = 'method';
var_dump(A::method());
var_dump(A::$m());
Par contre, on note que la classe est invariablement de type T_STRING (à ne surtout pas confondre avec T_CONSTANT_ENCAPSED_STRING qui est une chaîne de caractères à proprement parler). Donc impossible de rendre ça dynamique.
En PHP 5.3, ce sera possible (yepee).

Donc il te reste deux solutions : appels dynamiques (callback) ou introspection (reflection). À mon avis, les appels dynamiques sont plus rapides que l'introspection car l'introspection va regarder le « bytecode » et agir en conséquence. Cette opération est plus lourde qu'un appel dynamique.

Après relecture : oops, il te reste bien sûr la possibilité d'appeler ta méthode statique directement sur l'objet (qui en fait va rediriger sur la classe). Lors de l'utilisation du mot-clé new, on doit préciser le nom de la classe qui est soit de type T_STRING soit … T_VARIABLE ! Donc on peut avoir du dynamisme à cet endroit :
// Suite du code précédent.
$a = 'A';
var_dump(new A());
var_dump(new $a());
Donc tu peux faire un truc du genre :
$object = new $class();
$return = $object->$method();
ça reste possible. Par contre, pas sûr que d'instancier une classe soit systématiquement plus rapide que d'utiliser des appels dynamiques … À voir :-k.

Conclusion partielle : comme ta classe est dynamique, les appels dynamiques peuvent être nécessaires, donc utiliser call_user_func() se justifie très bien :).
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Eléphant du PHP | 185 Messages

31 déc. 2008, 13:38

Ok, merci à vous.
Ca m'emmerde carrément d'utiliser un truc plus lent pour le faire, mais bon... Si je n'ai pas d'autres solutions...

ViPHP
ViPHP | 4674 Messages

31 déc. 2008, 17:14

Oui enfin, c'est plus lent à quel point (la flemme de me faire un p'tit benchmark …) ?
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).