Un collègue a ajouté la commande assert à quelques reprises dans nos bibliothèques à des endroits où j'aurais utilisé une instruction if et levé une exception. (Je n'avais même jamais entendu parler d'affirmation 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');
}
À la lecture de la documentation PHP sur assert , il semble qu'il soit recommandé de s'assurer que l'assert est actif et d'ajouter un gestionnaire avant d'utiliser assert. Je ne trouve pas d'endroit où il a fait ça.
Donc, ma question est la suivante: utiliser assert est-il une bonne idée étant donné ce qui précède et devrais-je l'utiliser plus souvent au lieu des if et des exceptions?
Une autre note, 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 d'assert?
'isset
(la ligne de code avecassert
)? Pas seulementisset
(sans le guillemet simple'
)?Réponses:
La règle de base qui s'applique dans la plupart des langues (tout ce que je sais vaguement) est que an
assert
est utilisé pour affirmer qu'une condition est toujours vraie alors que anif
est approprié s'il est concevable qu'elle échoue parfois.Dans ce cas, je dirais que
assert
c'est approprié (basé sur ma faible compréhension de la situation) carrecords
devrait toujours être défini avant que la méthode donnée ne soit appelé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, leassert
aide à garantir (avec des tests adéquats) qu'il n'y a pas de chemin d'exécution de programme possible qui pourrait provoquer l'assert
appel du code protégé par le sansrecords
avoir été défini.L'avantage d'utiliser
assert
par opposition àif
est qu'ilassert
peut généralement être désactivé dans le code de production, réduisant ainsi les frais généraux. Le genre de situations avec lesquelles il est le mieux géréif
pourrait se produire pendant l'exécution dans le système de production et ainsi rien n'est perdu en ne pouvant pas les désactiver.la source
assert_options(ASSERT_BAIL)
. C'est de toute façon plus rapide que les solutions de contournement manuelles if / throw.Considérez les affirmations 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 exactement 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 de puissance" n'est pas seulement disponible pour les humains à lire et à comprendre, 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.
Vu de cette façon, les assertions sont un concept complètement différent de si (erreur) ... et des exceptions, et elles peuvent coexister.
Oui, vous devriez commenter votre code, et oui, vous devriez utiliser des «commentaires puissants» (assertions) chaque fois que possible.
la source
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 les schémas de test proactifs et intégrés peuvent parfois être avantageux.assert est utile, car il peut être activé et désactivé. Cela n'épuise pas les performances si aucun gestionnaire d'assertions n'est défini. Votre collègue n'en a pas, et vous devriez concevoir du code qui l'activera temporairement dans l'environnement de développement (si E_NOTICE / E_WARNINGs sont activés, le gestionnaire d'assertions devrait l'être également). Je l'utilise occasionnellement lorsque mon code ne supporte pas les types de variables mixtes - je ne m'engage normalement pas dans une saisie stricte 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.la source
Assert ne remplace pas le contrôle de flux normal
if
ou les exceptions, car il est uniquement destiné à être utilisé pour le débogage pendant le développement.la source
Une note importante concernant l'assert en PHP antérieur à 7. Contrairement à d'autres langages avec une construction assert, PHP ne lance pas entièrement les instructions assert - il la traite comme une fonction (faites un debug_backtrace () dans une fonction appelée par une assertion). La désactivation des assertions semble simplement inciter la fonction à ne rien faire dans le moteur. Notez que PHP 7 peut être amené à émuler ce comportement en définissant zend.assertions sur 0 au lieu des valeurs plus normales de 1 (activé) ou -1 (désactivé).
Le problème se pose en ce que l'assert accepte n'importe quel argument - mais si l'argument n'est pas une chaîne, assert obtient les résultats de l'expression, que l'assert soit activé ou non. 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'affirmer, il s'agit d'un bogue, et il existe depuis longtemps car il est dans le langage depuis que assert a été introduit dans PHP 4.
Les chaînes passées à assert sont évaluées, avec toutes les implications de performances et les dangers qui en découlent, mais c'est le seul moyen de faire fonctionner les instructions assert comme elles le devraient en PHP (ce comportement est déconseillé en PHP 7.2).
EDIT: Modifié ci-dessus pour noter les changements dans PHP 7 et 7.2
la source
zend.assertions
paramètre ini pour désactiver complètementassert()
.Assert ne doit être utilisé qu'en 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.
la source
Non, votre collègue ne devrait pas l'utiliser comme gestionnaire d'erreurs à usage général. Selon le manuel:
Si vous êtes familier avec 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 devrait pas l'utiliser comme un gestionnaire d'erreurs à usage général et dans ce cas comme un contrôle d'entrée. Il semble qu'il est possible que le champ des enregistrements ne soit pas défini par un utilisateur de votre bibliothèque.
la source
Votre collègue tente vraiment d'appliquer la conception par contrat (DbC) à partir du langage Eiffel et basé sur le livre: Object Oriented Software Construction, 2nd Edition.
L'assertion, telle qu'il l'utilisait, serait la {P} -partie du Hoare Logic ou Hoare Triple: {P} C {Q}, où le {P} est les assertions de précondition (ion) s et {Q} sont l'affirmation (ion) post-condition s.
Je prendrais note critique des conseils donnés sur la fonctionnalité d'assert en PHP ayant des bogues. Vous ne voulez pas utiliser de code bogué. Ce que vous voulez vraiment, ce sont les fabricants de PHP pour corriger le bogue dans l'assert. Jusqu'à ce qu'ils le fassent, vous pouvez utiliser l'assert, mais en gardant à l'esprit son état de buggy actuel.
De plus, si la fonction d'assert 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 développement et le test du code 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 précondition, ni affaiblir une post-condition. Cela pourrait être dangereux pour vos objets descendants polymorphes qui interagissent les uns avec les autres. Jusqu'à ce que vous compreniez ce que cela signifie - je le laisserais tranquille!
De plus, je recommande vivement aux fabricants de PHP de faire une étude approfondie de la conception par contrat et d'essayer de la mettre en PHP dès que possible! Ensuite, nous pouvons tous bénéficier d'un compilateur / interpréteur compatible DbC, qui traiterait les problèmes notés dans les réponses (ci-dessus):
REMARQUE: Même votre utilisation d'une
if
déclaration comme substitut à l'affirmation (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, il vous faudra étudier la conception par contrat pour le savoir! :-)Bonne étude et apprentissage.
la source