Instancier un objet dynamiquement sans eval()

eval() est décidément un gouffre à performance !

Voici le script que j’ai utilisé pour comparer les performances de l’instanciation d’un objet avec eval ou avec new. (j’utilise php 5.2.5).

<?php

$nb_iteration = 400000;

class toto {
 public $raoul;
}

$class_name = 'toto';

$start_time = microtime(true);
for ($i=0; $i <= $nb_iteration; $i++) {
 eval ('$objet = new toto();');
}
$end_time = microtime(true);

echo 'time taken (with eval)      : '.($end_time-$start_time).' s'."n";

$start_time = microtime(true);
for ($i=0; $i <= $nb_iteration; $i++) {
 $objet = new $class_name();
}
$end_time = microtime(true);

echo 'time taken (no eval)        : '.($end_time-$start_time).' s'."n";

et voici les résultats :

$ php test_eval.php
time taken (with eval)      : 18.955335140228 s
time taken (no eval)        : 3.5720331668854 s

Parlant non ?

Publicités

11 réflexions au sujet de « Instancier un objet dynamiquement sans eval() »

  1. Antoine

    Salut,

    il manque une balise de fermeture à ton script. Aussi, il est sans doute utile de préciser que faire new $class_name() ne prends pas plus de temps que de faire new toto().

    La fonction call_user_func est un bon compromis pour ce genre de chose. Par exemple, sur mon serveur :
    time taken (with eval) : 2.98381304741 s
    time taken (no eval) : 0.30176615715 s
    time taken (call_user_func) : 0.819909095764 s

    Antoine

    Répondre
  2. Laurentj

    Oui c’est totalement logique, quand on sait que l’évaluation d’un script PHP se fait en deux phases : transformation du code source en bytecode, puis évaluation du bytecode.

    Avec eval, on a à chaque itération les deux phases. Tandis qu’en faisant un new direct, on a que la deuxième phase, l’instruction dans la boucle ayant déjà été transformé en bytecode avant l’execution globale du bytecode du script.

    Répondre
  3. Chris

    @Antoine : la balise de fermeture n’est pas obligatoire. C’est même mieux d’ailleurs de ne pas l’utiliser pour éviter un retour chariot intempestif en fin de fichier, qui serait envoyé directement sur la sortie standard. Symfony a adopté cette pratique par exemple.

    Répondre
  4. Gérald

    Pour compléter les tests, voici ce que ça donne avec l’api Reflection

    $start_time = microtime(true);
    for ($i=0; $i newInstance ();
    }
    $end_time = microtime(true);

    echo ‘time taken (new Reflection) : ‘.($end_time-$start_time).’ s’. »n »;

    $start_time = microtime(true);
    $reflection = new ReflectionClass ($class_name);
    for ($i=0; $i newInstance ();
    }
    $end_time = microtime(true);

    echo ‘time taken (keeped Reflection) : ‘.($end_time-$start_time).’ s’. »n »;

    time taken (with eval) : 9.55426383018 s
    time taken (no eval) : 0.662239074707 s
    time taken (new Reflection) : 4.30600905418 s
    time taken (keeped Reflection object) : 1.75258493423 s

    Répondre
  5. Gérald

    Tient, le code est mal passé dans les commentaires….. un strip tags qui doit traîner 🙂

    Pour résumer, dans le premier cas j’effectue un new ReflectionClass ($class_name) à chaque passage dans le foreach, en plus de l’appel à la méthode newInstance (). Dans le deuxième cas, je ne fais qu’appeler la méthode newInstance () en ayant au préalable instancié la ReflectionClass.

    Dans tous les cas donc, new $class_name est plus rapide.

    Répondre
  6. Ping : Laurent Deséchalliers : “Tech”Blog » [Veille>Dev] PHP : Bench de la function eval()

  7. Martin

    En même temps, il faut bien garder à l’esprit que l’on est sur une boucle de 400 000 itérations, et donc que toutes les solutions sont envisageable dans un cas bien précis. On ne peut pas toujours utiliser la méthode la plus rapide, et même la moins rapide utilisée avec parcimonie est tout à fait correcte.

    Répondre

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s