begin process at 2010 02 10 09:34:58
  Trouver un code source :
 
dans
 
Accueil > 

Tutoriels

 > 

Class et Objet ( POO )

 > des assert pour vos classes php5

des assert pour vos classes php5


 Information sur le tutoriel



 Description

Voici une explication sur l’utilisation des assert dans des classes en php5.
Ici, j'explique un peu l'utilite des assert, comment ca a ete implemente/remplace dans d'autres langages, et comment on peut en faire des sympas en php5 OO.

Tutorial

Pourquoi et comment utiliser unassert en php5 OO

1 Généralités sur les asserts

Le assert est quelquechose qui sert énormément dans un programme,en général en C. On s'en sert souvent pour vérifier lors d'undebug, si nos variables sont bien cohérentes. L'utilisation d'unassert :

assert(chose_qui_doit_etre_vraie);

On peut trouver de nombreux exemples sur les assert sur cette page :http://www.google.com/codesearch?as_q=assert\((.*)\)voici un exemple marquant :

assert( min <= max );

en C, ce n'est pas une fonction mais une macro, elle peut-etredéfinie comme ceci :

#ifdef DEBUG
#define assert(expr) {if (!(expr)) \
  FatalError("Assertion failed file %s, line %d: expr\n", \
  __FILE__, __LINE__); }
#else
#define assert(expr)
#endif

http://www.google.com/codesearch?hl=en&q=+assert\((.*)\)+show:fInDJnJnt8I:bDg3EMzJKx4:KLZFRWkNVQk&sa=N&cd=10&ct=rc&cs_p=http://releases.mozilla.org/pub/mozilla.org/firefox/releases/2.0.0.2/source/firefox-2.0.0.2-source.tar.bz2&cs_f=mozilla/gfx/cairo/libpixman/src/pixregion.c Source de mozilla.

Le fait que ça soit une macro ne ralentit en rien l'exécution enproduction (en debug, on s'en moque). C'est un aventage compareaux assert de d'autres langages (php par exemple.)

Quand on débute, on peut s'imaginer que ça ne sert à rien devérifier si un min est infèrieur à un max, mais parfois, il arriveque des bugs nous ammènnent à cette situation, on doit donc pouvoirêtre prévenu en cas de bug, trouver le bug, et le corriger.L'assert ne nous permet pas de le corriger, mais il nous permet desavoir qu'il existe, et en gros de situer ou se trouve le bug.

En gros, vérifiez les évidences et vous debugerez moins longtemps.

2 Pourquoi utiliser un assert en php5 ?

En php, trop peu de gens se servent d'un error_reporting strict, ontrouve trop de gens qui codent sans afficher les warnings et notices.Si ce n'est deja fait : la page :http://fr2.php.net/manual/fr/function.error-reporting.phpvous offre un apperçu intéressant pour reconfigurer votre php.ini.Voici la fonction assert prédéfinie dans php :http://fr2.php.net/manual/fr/function.assert.phptrop peu s'en servent. Tout les programmeurs C ont deja vu desassert, j'en ai rarement vu en php. en php :http://www.google.com/codesearch?as_q=assert\((.*)\)&btnG=Search+Code&as_lang=php8000 codes trouvés seulement (contre 1 570 000 pour tout langagesconfondus)

En php, on peut passer des éléments du mauvais type, voir, laisserpasser des choses par le client (en GET ou POST), qu'il ne devraitpas passer.

Parfois, vérifier tout ça, avec des assert, serait utile, ouvérifier qu'une date de naissance à une valeur infèrieure à ladate du jours, des choses du genre. Ca peut toujours être utile devérifier ça, pour interdire les objets "mauvais", cesobjets entrainnent un code "fou", il est important debloquer le flux d'execution quand on arrive là.

Quand on utilise le modèle objet, il est simple de vérifier danschaque "seter" de propriétée privée ou protegée, si lavariable à une valeur "corrompue" ou non.

En php, on a pas de properties, on fait soit des seters, soit uneméthode magique :

public function __set($clef, $valeur){
    $this->$clef = $valeur ;
}

3 Comment utiliser un assert en php5

On peut commencer par definir une Exception d'assertion.

class AssertException extends Exception {}

Pour la suite, on vérifiera si un humain a un âge négatif ou non.

En général, quand on fait de l'objet en java ou php5, on fait untruc du genre :

class Humain extends assertable{
  public function __construct($age){
    parent::__construct();
    echo 'Un humain nait<br/>';
    $this->setAge($age);
  }
  protected function setAge($age){
    if ($age < 0){
      throw new AssertException('age invalide');
    }
    $this->age=$age;
  }
}

En pascal ou C#, on peut utiliser les properties, ca revient à peuprès au même, mais c'est transparent.

En php, la méthode magique __set permet de faire une fonctionappellée pour gérer les affectations de variables membres par ducode qui n'est pas contenu dans la classe.

$truc->clef=val;

cependant, ça à plusieurs inconvéniants : exemple : l'utilisationne sera pas transparente, c'est seulement ce qui est hors de laclasse qui appelle __set. Voici un exemple de la porté de __set.

//exemple pour voir les apples de __set
class A{
    public function __construct($a){
        $this->a=$a; // ceci ne l'appelle pas.
    }
    public function __set($k, $v){
        echo 'appel a __set';
        $this->$k=$v;
    }
    private $a;
}
				
$a=new A('ok'); // ceci ne l'appelle pas.
$a->a='B'; // ceci l'appelle

Pour l'avoir de façon transparente, à l'intérieur de laclasse, on doit faire un héritage :

abstract class assertable{
  public function __construct(){ }
  public function __set($key, $val){
    $this->$key = $val;
    $this->__assert();
  }
  abstract protected function __assert();
}

Voici une classe qui en hérite :

				
class Humain extends assertable{
  public function __construct($age){
    parent::__construct();
    echo 'Un humain nait<br/>';
    $this->age=$age;
  }
  protected function __assert(){
    if ($this->age > 130){
      throw new AssertException('age invalide');
    }
  }
}

4 Inconvéniants

L'inconvéniant principal, c'est la porté de la variable.

Humain::age n'existe pas, en réalite, c'est assertable::age, cequi fait que age est défini comme étant public...

Ce qui est intéressant ici, c'est que le coté "est-ce publicou pas" n'intervient pas trop, puisqu'on reste dans la boitenoirre, avec ce seter magique qui vérifie les mauvaises valeurs (enrésum é, on simule des sortes de properties du C# ou freepascal).

Cependent, ça peut-etre embétant pour des choses comme ceci :

[assertable] <--- [Humain] <--- [Enfant]

Sur un UML comme ceci, on aurait des choses bizares : on auraittoutes les variables membres de Enfant stoquées en réalite dansassertable.

Avec une déclaration correcte des variables, si on avait vouludéfinir dans Humain une variable private ($age par exemple), et leredéfinir dans Enfant, sans le hack, ca nous aurait fait deuxinstances différentes (à condition de les déclarer avant). Avec lehack, ca ne fonctionne plus, nos deux Enfant::age, et Humain::agesont les mêmes variables.

5 Conclusion

Utiliser les assert vous fera gagner du temps lors du debug, utiliserles __set vous permet d'appler vos assert quand vos variables sontmodifiées depuis d'autres classes, et utiliser __set couple à del'héritage vous permet de faire un assert puissant, qui vérifiechaque modification interne à la classe, bien que vous y perdiez enrigueur.

Commentaires

Commentaire de malalam le 13/05/2008 19:02:57 administrateur CS

Hello,

intéressant, mais tu ne vas pas assez loin dans les assertions. Déjà, tu ne parles pas de la fonction assert(), qui existe en PHP. Et que cette petite fonction (et globalement, le principe de l'assertion) est très pratique pour faire des tests unitaires.
Je pense que tu devrais pousser!
2 remarques :
- on écrit "inconvénient" :-)
- ta remarque sur __set() est bancale : certes, dans ton cas, on ne passe par par __set(). Mais c'est normal : tu déclares ta propriété dans la classe, donc la classe y a accès directement, quel que soit son accessibilité. Si tu ne la déclares pas du tout (supprimes ton private $a), tu verras que même au sein de la classe, tu passeras pas __set(). Perso je trouve ça logique. Pourquoi un objet passerait-il par sa méthode __set() pour mettre à jour des propriétés dont on lui a dit qu'elles lui appartenaient ?

Bref, intéressant ceci dit, mais mérite d'être un peu étoffé.

Commentaire de coucou747 le 13/05/2008 19:15:02

oui, justement, la classe ne passe pas par __set pour acceder a ses variables membres, donc j'utilise l'heritage pour compenser (du coup, elle appelle __set pour acceder aux variables membres de sa classe mere.)

Commentaire de malalam le 17/05/2008 15:33:56 administrateur CS

Oui mais...:-) Bon c'est une question de philosophie hein... : la plupart de mes classes enfants ont la main sur les classes parentes. J'entends par là que je suis plutôt en protected en général. Ce n'est pas très grave, on est censés savoir ce que l'on fait quand même.
Bref, je n'avais pas noté...voici donc :-) 9 parce que je trouve que ce n'est pas assez étoffé. 9 quand même :-)

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,172 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales