AOP
-
A voir en préambule :
- Définition de l’AOP, ou Programmation Orientée Aspect, sur Wikipédia
- Vocabulaire de l’AOP par l’exemple
- Le chapitre d’introduction à l’AOP Des applications modulaires avec l’AOP
Comment utiliser l’AOP dans it.rocks
Vous pouvez utiliser l’AOP pour intervenir dans le comportement des modules logiciels existant en exécutant du code :- avant l’exécution d’une méthode,
- après l’exécution d’une méthode,
- à la place de l’exécution d’une méthode,
- au moment où la valeur d’une propriété est consultée,
- au moment où la valeur d’une propriété est modifiée,
- également avant, après, à la place de l’exécution d’une fonction.
Le tissage, par le biais de la déclaration des aspects, se réalise dans la méthode register des plugins enregistrables, par le biais du tisseur de liens AOP
$register->aop
fourni par cette méthode.Les greffons déclarés lors de l’enregistrement de votre plugins seront actifs pour toute votre application à partir du moment où votre plugin est déclaré dans votre fichier de configuration : il n’est pas possible de rajouter des aspects ailleurs que dans la méthode register des plugins enregistrables.
Implémentation de vos points de coupe
Comme vu en introduction, aucune déclaration particulière nécessaire pour indiquer les points de coupe potentiels : toutes les propriétés, toutes les méthodes de classes, interfaces ou traits, toutes les fonctions que vous avez développé sous projet it.rocks sont des points de coupe que vous pouvez employer.
Exemple de point de coupe : la méthode Email\Sender::send() du framework :
/** * Send an email using its account connection information * or the default SMTP account configuration. * * @param $email Email * @return boolean|string true if sent, error message if string */ public function send(Email $email) { // .. here is the code return true; }
Implémentation de vos greffons
Toute méthode ou fonction peut être utilisée comme greffon. Toutefois ses arguments doivent respecter un certain nombre de conventions de nommage, votre greffon doit donc être compatible avec le ou les points de coupes auxquels il peut s’appliquer.
Exemple de greffon qui écrit en base de données un email, pris dans la classe Email\Archive du framework :
/** * @param $email Email */ public function save(Email $email) { Dao::write($email); }
On a pris soin ici de nommer l’argument avec le même nom que l’argument de la méthode d’origine pour lequel l’aspect sera tissé. C’est par le nom des arguments que le tisseur d’aspects fait le lien entre les arguments, ce qui est surtout utile lorsque votre point de coupe a plusieurs arguments mais que seulement certains vous intéressent : votre greffon peut en effet proposer une liste restreinte d’arguments, dans un ordre différent.
Certains noms d’arguments sont réservés aux mécanismes de l’AOP, et ne peuvent pas être capturés directement du point de coupe. Si jamais l’un d’entre-eux était employé par le point de coupe, vous pourrez toujours utiliser ces arguments par le biais de le l’argument $joinpoint.$result
: la valeur retournée par le point de coupe.$object
: l’objet contexte dans lequel la méthode point de coupe doit être exécutée$joinpoint
: cet objet de classe Joinpoint contient toutes les informations concernant le point de coupe, le point de jonction, et le greffon.
Exemple de greffon dont la tâche serait de sauvegarder un objet passé en argument nommé
$object
dans le point de coupe. On ne peut pas récupérer directement cet argument, mais on le retrouve par le biais de l’argument réservé$joinpoint
:
/** * @param $joinpoint Method_Joinpoint */ public function save(Method_Joinpoint $joinpoint) { Dao::write($joinpoint->object); }
Exemple de greffon qui modifie la valeur de retour de notre point de coupe
send()
vu en exemple plus haut :
/** * @param $result boolean The cut point result, modified by this advice */ public function save(&$result) { $result = false; }
Si vous n’avez pas besoin de consulter la valeur de retour d’origine en fin de votre point de coupe, vous pouvez également retourner cette valeur de retour modifiée :
/** * return boolean */ public function save() { return false; }
Comment écrire vos aspects
Code minimal d’une classe plugin enregistrable :
<?php namespace Author\Project\My_Plugin; use ITRocks\Framework\Plugin\Register; use ITRocks\Framework\Plugin\Registerable; /** * My really first registerable plugin */ class My_Plugin implements Registerable { /** * Registration code for the plugin * * @param $register Register */ public function register(Register $register) { // Aspect weaving will come here } }
Pour tisser un aspect : dans notre exemple le greffon
save()
a été programmé dans la classe du plugin, mais on pourrait très bien appeler une méthode d’un autre objet, une méthode statique, une fonction :
/** * Registration code for the plugin * * @param $register Register */ public function register(Register $register) { $register->aop->afterMethod([Email\Sender::class, 'send'], [$this, 'save']); }
L’appel à afterMethod déclare donc au tisseur d’aspect :- le point de coupe : après chaque appel à la méthode
Email\Sender::send()
- le greffon appelé : la méthode
My_Plugin::save()
Activez vos plugins pour activez vos aspects
Vos aspects ne seront tissés et actifs que si vos plugins sont activés dans votre fichier de configuration.
Exemple de fichier de configuration minimal avec la ligne de déclaration d’utilisation du plugin Email Archive :
<?php namespace Author\Project; use ITRocks\Framework; use ITRocks\Framework\Configuration; global $loc; require __DIR__ . '/../../loc.php'; require __DIR__ . '/../../itrocks/framework/config.php'; $config['Author/Project'] = [ Configuration::APP => Application::class, Configuration::EXTENDS_APP => 'ITRocks/Framework', Priority::NORMAL => [ Framework\Email\Archive::class ] ];
Documentation de référence : voir aussi
Consultez ces documentations pour avoir les explications et exemples pour chaque cas d’utilisation :