Un collègue a ajouté la commande assert plusieurs fois dans nos bibliothèques à des endroits où j'aurais utilisé une instruction if et levé une exception. (Je n'avais jamais entendu parler d'assertion avant cela.) Voici un exemple de la façon dont il l'a utilisé:
assert('isset($this->records); /* Records must be set before this is called. */');
Je l'aurais fait:
if (!isset($this->records)) {
throw new Exception('Records must be set before this is called');
}
En lisant les documents PHP sur assert , il semble qu'il est recommandé de vous assurer que assert est actif et d'ajouter un gestionnaire avant d'utiliser assert. Je ne trouve pas de endroit où il a fait ça.
Donc, ma question est, est-ce que l'utilisation de l'affirmation est une bonne idée étant donné ce qui précède et devrais-je l'utiliser plus souvent au lieu de si et d'exceptions?
Autre remarque, nous prévoyons d'utiliser ces bibliothèques sur une variété de projets et de serveurs, y compris des projets dont nous ne faisons peut-être même pas partie (les bibliothèques sont open source). Cela fait-il une différence dans l'utilisation de l'assertion?
La règle générale qui s'applique à la plupart des langues (tout ce que je sais vaguement) est qu'une assert
est utilisée pour affirmer qu'une condition est toujours vraie alors qu'une if
est approprié s'il est concevable qu'il échoue parfois.
Dans ce cas, je dirais que assert
est approprié (en fonction de ma faible compréhension de la situation) car records
devrait toujours être défini avant d'appeler la méthode donnée . Donc, un échec de définition de l'enregistrement serait un bogue dans le programme plutôt qu'une condition d'exécution. Ici, le assert
aide à garantir (avec des tests adéquats) qu'il n'y a pas de chemin possible d'exécution du programme qui pourrait provoquer l'appel du code gardé avec le assert
sans records
ayant été défini.
L'avantage d'utiliser assert
par opposition à if
est que assert
peut généralement être désactivé dans le code de production, réduisant ainsi les frais généraux. Le type de situations qui sont mieux gérées avec if
pourrait se produire pendant l'exécution dans le système de production et donc rien n'est perdu en ne pouvant pas les désactiver.
Considérez les assertions comme des "commentaires puissants". Plutôt qu'un commentaire comme:
// Note to developers: the parameter "a" should always be a number!!!
utilisation:
assert('is_numeric(a) /* The parameter "a" should always be a number. */');
Les significations sont exactement les mêmes et sont destinées au même public, mais le premier commentaire est facilement oublié ou ignoré (quel que soit le nombre de points d'exclamation), tandis que le "commentaire sur la puissance" n'est pas seulement disponible pour être lu et compris par les humains, il est également constamment testé en machine pendant le développement et ne sera pas ignoré si vous configurez une bonne gestion des assertions dans le code et dans les habitudes de travail.
De cette façon, les assertions sont un concept complètement différent de if (erreur) ... et des exceptions, et elles peuvent coexister.
Oui, vous devriez commenter votre code, et oui, vous devriez utiliser des "commentaires de puissance" (assert) dans la mesure du possible.
Cela dépend entièrement de votre stratégie de développement. La plupart des développeurs ne connaissent pas assert()
et utilisent les tests unitaires en aval. Mais des programmes de tests proactifs et intégrés peuvent parfois être avantageux.
assert est utile, car il peut être activé et désactivé. Il ne réduit pas les performances si aucun gestionnaire d'assertion n'est défini. Votre collègue n'en a pas et vous devez concevoir un code qui l'activera temporairement dans l'environnement de développement (si E_NOTICE/E_WARNINGs sont activés, le gestionnaire d'assertion devrait donc l'être). Je l'utilise occasionnellement lorsque mon code ne peut pas contenir de types de variables mixtes - je ne m'engage pas normalement à taper strictement dans un PHP faiblement typé, mais il existe des cas d'utilisation aléatoires:
function xyz($a, $b) {
assert(is_string($a));
assert(is_array($b));
Ce qui par exemple compenserait le manque de spécificateurs de type string $a, array $b
. PHP5.4 les supportera, mais ne vérifiera pas.
Assert ne remplace pas le contrôle de flux normal comme if
ou les exceptions, car il est uniquement destiné à être utilisé pour le débogage pendant le développement.
Une note importante concernant l'assertion dans PHP plus tôt que 7. Contrairement à d'autres langages avec une construction assert, PHP ne jette pas les instructions assert entièrement - il les traite en tant que fonction (faites un debug_backtrace () dans une fonction appelée par une assertion). La désactivation des assertions semble simplement câbler la fonction pour ne rien faire dans le moteur. Notez que PHP 7 peut être fait pour émuler ce comportement en définissant zend.assertions à 0 au lieu des valeurs plus normales de 1 (activé) ou -1 (désactivé).
Le problème se pose en ce que l'assertion prendra n'importe quel argument - mais si l'argument n'est pas une chaîne, alors assert obtient les résultats de l'expression, que l'assertion soit activée ou désactivée. Vous pouvez le vérifier avec le bloc de code suivant.
<?php
function foo($a) {
echo $a . "\n";
return TRUE;
}
assert_options(ASSERT_ACTIVE, FALSE);
assert( foo('You will see me.'));
assert('foo(\'You will not see me.\')');
assert_options(ASSERT_ACTIVE, TRUE);
assert( foo('Now you will see'));
assert('foo(\'both of us.\')');
Étant donné l'intention d'assert, c'est un bogue, et de longue date car il est dans le langage depuis que assert a été réintroduit en PHP 4.
Les chaînes passées à assert sont évaluées, avec toutes les implications de performance et les dangers qui en découlent, mais c'est le seul moyen de faire fonctionner les instructions assert comme elles le devraient dans PHP (This comportement obsolète dans PHP 7.2).
EDIT: modifié ci-dessus pour noter les changements dans PHP 7 et 7.2
Assert ne doit être utilisé que dans le développement car il est utile pour le débogage. Donc, si vous le souhaitez, vous pouvez les utiliser pour développer votre site Web, mais vous devez utiliser des exceptions pour un site Web en direct.
Non, votre collègue ne devrait pas l'utiliser comme gestionnaire d'erreurs à usage général. Selon le manuel:
Les assertions doivent être utilisées uniquement comme fonctionnalité de débogage. Vous pouvez les utiliser pour des vérifications d'intégrité qui testent des conditions qui devraient toujours être VRAIES et qui indiquent des erreurs de programmation sinon ou pour vérifier la présence de certaines fonctionnalités comme les fonctions d'extension ou certaines limites et fonctionnalités du système.
Les assertions ne doivent pas être utilisées pour les opérations d'exécution normales comme les vérifications des paramètres d'entrée. En règle générale, votre code devrait toujours pouvoir fonctionner correctement si la vérification des assertions n'est pas activée.
Si vous connaissez les suites de tests automatisés, le verbe "assert" est généralement utilisé pour vérifier la sortie d'une méthode ou d'une fonction. Par exemple:
function add($a, $b) {
return $a + $b;
}
assert(add(2,2) == 5, 'Two and two is four, dummy!');
assert(is_numeric(add(2,2)), 'Output of this function to only return numeric values.');
Votre collègue ne doit pas l'utiliser comme gestionnaire d'erreurs à usage général et dans ce cas comme vérification d'entrée. Il semble qu'il soit possible que le champ des enregistrements ne soit pas défini par un utilisateur de votre bibliothèque.
Votre collègue essaie vraiment d'appliquer conception par contrat (DbC) à partir du langage Eiffel et basé sur le livre: Object Oriented Software Construction, 2nd Edition.
L'affirmation, telle qu'il l'a utilisée, serait la partie {P} de la logique Hoare ou Hoare Triple: {P} C {Q}, où le {P} est l'assertion (ion) s de précondition et {Q} sont l'affirmation de post-condition (ion) s.
Je prendrais une note critique des conseils donnés sur la fonction assert dans PHP ayant des bogues. Vous ne voulez pas utiliser de code bogué. Ce que vous voulez vraiment, ce sont les créateurs de PHP pour corriger le bogue dans l'assertion. Jusqu'à ce qu'ils le fassent, vous pouvez utiliser l'assertion, mais en gardant à l'esprit son état de bogue actuel.
De plus, si la fonction d'assertion est boguée, je vous suggère de ne pas l'utiliser dans le code de production. Néanmoins, je vous recommande de l'utiliser dans le code de développement et de test, le cas échéant.
Enfin - si vous étudiez la conception par contrat, vous constaterez qu'il y a des conséquences à utiliser des assertions booléennes à la lumière de l'héritage classique orienté objet - c'est-à-dire que vous ne devez jamais affaiblir une condition préalable, ni affaiblir une post-condition. Cela pourrait être dangereux pour vos objets descendants polymorphes interagissant les uns avec les autres. Jusqu'à ce que vous compreniez ce que cela signifie - je le laisserais tranquille!
De plus, je recommande vivement aux créateurs de PHP de faire une étude complète de la conception par contrat et d'essayer de l'intégrer dans PHP ASAP! Alors nous pouvons tous bénéficier d'un compilateur/interprète compatible DbC, qui traiterait les problèmes mentionnés dans les réponses (ci-dessus):
REMARQUE: même votre utilisation d'une instruction if
- en remplacement de l'assertion (précondition) subira des conséquences désastreuses si elle est utilisée pour renforcer une précondition ou affaiblir une post-condition. Pour comprendre ce que cela signifie, vous devrez étudier la conception par contrat pour le savoir! :-)
Bonne étude et apprentissage.