Le package PHP Macro offre une injection de dépendance de setter basée sur la fermeture (fonction anonyme) en fournissant un trait qui peut être inclus dans n'importe quelle classe.
composer req aimeos/macro
Ce package est destiné aux développeurs d'applications, de frameworks et de bibliothèques qui souhaitent permettre à leurs utilisateurs de personnaliser le comportement de leur code.
Dans les applications, frameworks ou bibliothèques conçus pour la personnalisation, il est nécessaire d'autoriser l'écrasement des fonctionnalités existantes afin de pouvoir personnaliser leur comportement. C'est là que les macros sont très pratiques car elles peuvent ajouter du code personnalisé à l'aide de fermetures.
Avec le package PHP Macro, vous pouvez également autoriser les utilisateurs à écraser les méthodes dans les classes de base sans obliger vos utilisateurs à étendre ces classes. Le package PHP Macro n'utilise AUCUNE réflexion ou autre hack, juste des méthodes PHP pures .
Il y a quelques avantages et inconvénients par rapport à l’injection de dépendances basée sur les classes :
Pro:
Escroquer:
Ainsi, il ne s'agit pas d'un remplacement pour l'injection de dépendances basée sur les classes, mais d'un ajout léger pour les petits points d'extension où l'injection de dépendances complète à l'aide de classes implémentant des interfaces représente trop de travail.
Le résultat des méthodes existantes peut être modifié si la méthode d'origine recherche une macro existante et l'utilise à la place de sa propre implémentation :
// original code
class Order
{
use Aimeos Macro Macroable;
private $ id = ' 123 ' ;
public function getOrderNumber ()
{
$ fcn = static :: macro ( ' orderNumber ' );
return $ fcn ? $ fcn ( $ this -> id ) : $ this -> id ;
}
};
Maintenant, vous pouvez ajouter votre macro orderNumber
personnalisée qui sera utilisée à la place :
// user code
Order:: macro ( ' orderNumber ' , function ( string $ id ) {
return date ( ' Y ' ) . ' - ' . $ id ;
} );
( new Order )-> getOrderNumber (); // now returns '2020-123'
Ainsi, vous pouvez générer votre propre sortie ou transmettre un résultat différent aux méthodes suivantes au sein de l'application.
Lorsque les macros sont appelées dans un contexte d'objet, elles peuvent également accéder aux propriétés de classe :
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
Ici, la propriété privée $name
est disponible dans la macro :
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return $ this -> name . ' : ' . implode ( ' - ' , $ values );
} );
( new A )-> concat ( [ ' 1 ' , ' 2 ' , ' 3 ' ] ); // returns 'A:1-2-3'
La macro peut utiliser la propriété comme entrée pour créer la valeur renvoyée.
Le package de macros PHP permet également d'hériter des macros des classes parentes. Ensuite, ils peuvent accéder aux propriétés de la classe enfant, tout comme les méthodes de classe classiques :
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
class B extends A
{
private $ name = ' B ' ;
};
Les macros ajoutées à la classe parent seront également disponibles dans les classes enfants :
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return $ this -> name . ' : ' . implode ( ' - ' , $ values );
} );
( new B )-> concat ( [ ' 1 ' , ' 2 ' , ' 3 ' ] ); // returns 'B:1-2-3'
La classe B
s'étend de la classe A
mais fournit une propriété $name
différente. La macro héritée de la classe A
utilisera désormais la propriété de la classe B
.
Il est également possible d'écraser les macros héritées des classes parentes, comme cela est possible avec les méthodes de classe classiques :
// original code
class A
{
use Aimeos Macro Macroable;
public function do () {
return static :: macro ( ' concat ' )( [ 1 , 2 , 3 ] );
}
};
class B extends A {};
class C extends A {};
Vous pouvez maintenant ajouter des macros à la classe parent et à l'une des classes enfants :
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return implode ( ' , ' , $ values );
} );
C:: macro ( ' concat ' , function ( array $ values ) {
return implode ( ' - ' , $ values );
} );
( new B )-> do (); // returns '1,2,3'
( new C )-> do (); // returns '1-2-3'
Cela vous permet d'ajouter une gestion spéciale pour des classes uniques même si toutes les autres classes utilisent toujours la macro ajoutée à la classe A
.
Les classes de base proposent souvent un ensemble de méthodes utilisées par les classes enfants. En PHP, remplacer les méthodes d'une classe de base est impossible et vous devez donc écraser chaque classe enfant par votre propre implémentation.
Pour éviter cela, la méthode d'origine peut utiliser la méthode call()
au lieu d'appeler directement la méthode de la classe parent :
// original code
class A
{
use Aimeos Macro Macroable;
protected function getName ( $ prefix )
{
return $ prefix . ' A ' ;
}
};
class B extends A
{
public function do ()
{
return $ this -> call ( ' getName ' , ' B- ' );
}
};
Cela vérifiera si une macro getName
est disponible et l'appellera à la place de la méthode getName()
:
// user code
( new B )-> do (); // returns 'B-A'
A:: macro ( ' getName ' , function ( $ prefix ) {
return $ this -> getName ( $ prefix ) . ' -123 ' ;
} );
( new B )-> do (); // returns 'B-A-123'
La méthode getName()
originale peut toujours être utilisée dans la macro.
Parfois, il peut être nécessaire de supprimer les macros des objets, notamment lors de l’exécution de tests automatisés. Vous pouvez supprimer une macro en utilisant :
class A
{
use Aimeos Macro Macroable;
};
// add macro
A:: macro ( ' test ' , function () {
return ' test ' ;
} );
// remove macro
A:: unmacro ( ' test ' );