Question

Quels types de conséquences sur les performances faut-il prendre en compte lors de l'utilisation d'instructions try-catch dans PHP 5?

J'ai déjà lu sur le Web des informations anciennes et apparemment contradictoires sur ce sujet. Une grande partie du framework sur lequel je travaille actuellement a été créée sur php 4 et manque de nombreuses subtilités de php 5. Donc, je n'ai pas beaucoup d'expérience dans l'utilisation de try-catchs avec php.

Était-ce utile?

La solution

Une chose à considérer est que le coût d'un bloc try où aucune exception n'est levée est une question différente du coût de lancer et de capturer une exception.

Si des exceptions ne sont levées que dans les cas d'échec, les performances ne vous intéressent presque certainement pas, car vous n'échouerez pas très souvent lors de l'exécution de votre programme. Si vous échouez dans une boucle serrée (a.k.a: vous cogner la tête contre un mur de briques), votre application rencontrera probablement des problèmes plus graves que la lenteur. Alors, ne vous inquiétez pas du coût lié à la génération d'une exception, à moins que vous ne soyez obligé de l'utiliser pour un flux de contrôle régulier.

Quelqu'un a posté une réponse sur le code de profilage qui lève une exception. Je ne l'ai jamais testé moi-même, mais je prédis avec confiance que cela affichera un impact beaucoup plus grand sur les performances que de simplement entrer et sortir d'un bloc d'essai sans rien jeter.

Une autre chose à prendre en compte est que, lorsque vous nidifiez des appels en profondeur, il peut être encore plus rapide d’essayer en une seule tentative ... au premier plan plutôt qu’à vérifier les valeurs renvoyées et à propager des erreurs à chaque appel. .

À l'inverse de cette situation, vous constaterez que vous encapsulez chaque appel à sa propre tentative ... catch block, votre code sera plus lent. Et plus laid.

Autres conseils

Je me suis ennuyé et ai profilé ce qui suit (j'ai oublié le code temporel):

function no_except($a, $b) { 
    $a += $b;
    return $a;
}
function except($a, $b) { 
    try {
        $a += $b;
    } catch (Exception $e) {}
    return $a;
}

utilisant deux boucles différentes:

echo 'no except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    no_except(5, 7);
}
echo 'no except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    try {
        no_except(5, 7);
    } catch (Exception $e) {}
}
echo 'except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    except(5, 7);
}
echo 'except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    try {
        except(5, 7);
    } catch (Exception $e) {}
}

Avec 1000000 exécutions sur ma boîte WinXP, exécutez apache et PHP 5.2.6:

no except with no surrounding try = 3.3296
no except with surrounding try = 3.4246
except with no surrounding try = 3.2548
except with surrounding try = 3.2913

Ces résultats étaient cohérents et restaient dans une proportion similaire quel que soit l'ordre dans lequel les tests ont été effectués.

Conclusion: l’ajout de code permettant de gérer les rares exceptions n’est pas plus lent que le code qui ignore les exceptions.

Les blocs try-catch ne constituent pas un problème de performances: le goulot d'étranglement des performances provient de la création d'objets d'exception.

Code de test:

function shuffle_assoc($array) { 
    $keys = array_keys($array);
    shuffle($keys);
    return array_merge(array_flip($keys), $array);
}

$c_e = new Exception('n');

function no_try($a, $b) { 
    $a = new stdclass;
    return $a;
}
function no_except($a, $b) { 
    try {
        $a = new Exception('k');
    } catch (Exception $e) {
        return $a + $b;
    }
    return $a;
}
function except($a, $b) { 
    try {
        throw new Exception('k');
    } catch (Exception $e) {
        return $a + $b;
    }
    return $a;
}
function constant_except($a, $b) {
    global $c_e;
    try {
        throw $c_e;
    } catch (Exception $e) {
        return $a + $b;
    }
    return $a;
}

$tests = array(
    'no try with no surrounding try'=>function() {
        no_try(5, 7);
    },
    'no try with surrounding try'=>function() {
        try {
            no_try(5, 7);
        } catch (Exception $e) {}
    },
    'no except with no surrounding try'=>function() {
        no_except(5, 7);
    },
    'no except with surrounding try'=>function() {
        try {
            no_except(5, 7);
        } catch (Exception $e) {}
    },
    'except with no surrounding try'=>function() {
        except(5, 7);
    },
    'except with surrounding try'=>function() {
        try {
            except(5, 7);
        } catch (Exception $e) {}
    },
    'constant except with no surrounding try'=>function() {
        constant_except(5, 7);
    },
    'constant except with surrounding try'=>function() {
        try {
            constant_except(5, 7);
        } catch (Exception $e) {}
    },
);
$tests = shuffle_assoc($tests);

foreach($tests as $k=>$f) {
    echo $k;
    $start = microtime(true);
    for ($i = 0; $i < 1000000; ++$i) {
        $f();
    }
    echo ' = '.number_format((microtime(true) - $start), 4)."<br>\n";
}

Résultats:

no try with no surrounding try = 0.5130
no try with surrounding try = 0.5665
no except with no surrounding try = 3.6469
no except with surrounding try = 3.6979
except with no surrounding try = 3.8729
except with surrounding try = 3.8978
constant except with no surrounding try = 0.5741
constant except with surrounding try = 0.6234

En règle générale, utilisez une exception pour vous protéger contre les échecs inattendus et utilisez la vérification des erreurs dans votre code pour identifier les échecs faisant partie de l'état normal du programme. Pour illustrer:

  1. Enregistrement introuvable dans la base de données - état valide, vous devez vérifier les résultats de la requête et envoyer un message à l'utilisateur de manière appropriée.

  2. Erreur SQL lors de la tentative de récupération d'un enregistrement - échec inattendu, l'enregistrement peut être ou ne pas être là, mais vous avez une erreur de programme - c'est un bon emplacement pour une exception - journal d'erreur dans le journal des erreurs, envoyez un courrier électronique à l'administrateur trace de la pile et affiche un message d'erreur poli à l'utilisateur pour l'informer que quelque chose ne va pas et que vous travaillez dessus.

Les exceptions coûtent cher, mais à moins que vous ne les utilisiez dans votre flux de programme complet, aucune différence de performances ne devrait être perceptible par l'homme.

Je n'ai rien trouvé sur les performances Try / Catch sur Google, mais un simple test avec une erreur de lancement de boucle au lieu d'une instruction IF produit 329 ms contre 6 ms dans une boucle de 5 000.

Désolé de poster un très vieux message, mais j'ai lu les commentaires et je ne suis pas du tout d'accord, la différence peut être minime avec un simple morceau de code ou peut être négligeable lorsque les codes Try / Catch sont utilisés pour des parties spécifiques du code. qui ne sont pas toujours prévisibles, mais je crois aussi (non testé) qu'un simple:

if(isset($var) && is_array($var)){
    foreach($var as $k=>$v){
         $var[$k] = $v+1;
    }
}

est plus rapide que

try{
    foreach($var as $k=>$v){
        $var[$k] = $v+1;
    }
}catch(Exception($e)){
}

Je crois aussi (non testé) que a:

<?php
//beginning code
try{
    //some more code
    foreach($var as $k=>$v){
        $var[$k] = $v+1;
    }
    //more code
}catch(Exception($e)){
}
//output everything
?>

est plus cher que des FI supplémentaires dans le code

C’est une très bonne question!

Je l'ai testé plusieurs fois et je n'ai jamais rencontré de problème de performances ;-) C'était vrai il y a 10 ans en C ++, mais je pense qu'aujourd'hui, ils l'ont beaucoup amélioré depuis que c'est tellement utile et plus propre.

Mais j'ai toujours peur d'entourer mon premier point d'entrée:

try {Controller::run();}catch(...)

Je n’ai pas testé avec de nombreuses fonctions d’appel et d’inclusion importante.

En règle générale, ils sont chers et ne valent pas la peine en PHP.

S'agissant d'un langage à expressions contrôlées, vous DEVEZ intercepter tout ce qui déclenche une exception.

S'agissant du code hérité qui ne jette pas et du nouveau code qui le fait, cela ne fait que semer la confusion.

Bonne chance!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top