Das PHP-Makropaket bietet eine auf Schließung (anonyme Funktion) basierende Setter-Abhängigkeitsinjektion, indem es ein Merkmal bereitstellt, das in jede Klasse aufgenommen werden kann.
composer req aimeos/macro
Dieses Paket richtet sich an Anwendungs-, Framework- und Bibliotheksentwickler, die ihren Benutzern die Anpassung des Verhaltens ihres Codes ermöglichen möchten.
In Anwendungen, Frameworks oder Bibliotheken, die zur Anpassung erstellt werden, ist es notwendig, das Überschreiben vorhandener Funktionen zu ermöglichen, um ihr Verhalten anpassen zu können. Hier sind Makros sehr praktisch, da sie mithilfe von Abschlüssen benutzerdefinierten Code hinzufügen können.
Mit dem PHP-Makropaket können Sie Benutzern auch erlauben, Methoden in Basisklassen zu überschreiben, ohne Ihre Benutzer zu zwingen, diese Klassen zu erweitern. Das PHP-Makropaket verwendet KEINE Reflektion oder andere Hacks, sondern nur reine PHP-Methoden .
Im Vergleich zur klassenbasierten Abhängigkeitsinjektion gibt es einige Vor- und Nachteile:
Pro:
Nachteil:
Daher ist es kein Ersatz für die klassenbasierte Abhängigkeitsinjektion, sondern eine leichte Ergänzung für kleine Erweiterungspunkte, an denen eine vollständige Abhängigkeitsinjektion mithilfe von Klassen, die Schnittstellen implementieren, zu aufwändig ist.
Das Ergebnis vorhandener Methoden kann geändert werden, wenn die ursprüngliche Methode nach einem vorhandenen Makro sucht und dieses anstelle ihrer eigenen Implementierung verwendet:
// 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 ;
}
};
Jetzt können Sie Ihr benutzerdefiniertes orderNumber
Makro hinzufügen, das stattdessen verwendet wird:
// user code
Order:: macro ( ' orderNumber ' , function ( string $ id ) {
return date ( ' Y ' ) . ' - ' . $ id ;
} );
( new Order )-> getOrderNumber (); // now returns '2020-123'
So können Sie eigene Ausgaben generieren oder ein anderes Ergebnis an nachfolgende Methoden innerhalb der Anwendung übergeben.
Wenn Makros in einem Objektkontext aufgerufen werden, können sie auch auf Klasseneigenschaften zugreifen:
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
Hier ist die private Eigenschaft $name
im Makro verfügbar:
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return $ this -> name . ' : ' . implode ( ' - ' , $ values );
} );
( new A )-> concat ( [ ' 1 ' , ' 2 ' , ' 3 ' ] ); // returns 'A:1-2-3'
Das Makro kann die Eigenschaft als Eingabe zum Erstellen des zurückgegebenen Werts verwenden.
Das PHP-Makropaket ermöglicht auch das Erben von Makros von übergeordneten Klassen. Dann können sie wie normale Klassenmethoden auf Klasseneigenschaften der untergeordneten Klasse zugreifen:
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
class B extends A
{
private $ name = ' B ' ;
};
Der übergeordneten Klasse hinzugefügte Makros sind auch in untergeordneten Klassen verfügbar:
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return $ this -> name . ' : ' . implode ( ' - ' , $ values );
} );
( new B )-> concat ( [ ' 1 ' , ' 2 ' , ' 3 ' ] ); // returns 'B:1-2-3'
Klasse B
erweitert Klasse A
stellt jedoch eine andere $name
Eigenschaft bereit. Das von Klasse A
geerbte Makro verwendet nun die Eigenschaft von Klasse B
Es ist auch möglich, von übergeordneten Klassen geerbte Makros zu überschreiben, wie dies mit regulären Klassenmethoden möglich ist:
// 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 {};
Jetzt können Sie der übergeordneten Klasse und einer der untergeordneten Klassen Makros hinzufügen:
// 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'
Dadurch können Sie eine spezielle Behandlung für einzelne Klassen hinzufügen, auch wenn alle anderen Klassen weiterhin das zur Klasse A
hinzugefügte Makro verwenden.
Basisklassen bieten häufig eine Reihe von Methoden an, die von den untergeordneten Klassen verwendet werden. In PHP ist das Ersetzen der Methoden einer Basisklasse nicht möglich und Sie müssen daher jede untergeordnete Klasse mit Ihrer eigenen Implementierung überschreiben.
Um dies zu vermeiden, kann die ursprüngliche Methode die Methode call()
verwenden, anstatt die Methode der übergeordneten Klasse direkt aufzurufen:
// 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- ' );
}
};
Dadurch wird überprüft, ob ein Makro getName
verfügbar ist, und dieses wird anstelle der getName()
Methode aufgerufen:
// 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'
Die ursprüngliche getName()
Methode kann weiterhin im Makro verwendet werden.
Manchmal kann es notwendig sein, Makros von Objekten zu entfernen, insbesondere wenn automatisierte Tests ausgeführt werden. Sie können ein Makro deaktivieren, indem Sie Folgendes verwenden:
class A
{
use Aimeos Macro Macroable;
};
// add macro
A:: macro ( ' test ' , function () {
return ' test ' ;
} );
// remove macro
A:: unmacro ( ' test ' );