O pacote PHP Macro oferece injeção de dependência de setter baseada em fechamento (função anônima), fornecendo uma característica que pode ser incluída em qualquer classe.
composer req aimeos/macro
Este pacote é para desenvolvedores de aplicações, frameworks e bibliotecas que desejam permitir a customização do comportamento de seu código por seus usuários.
Em aplicações, frameworks ou bibliotecas construídas para customização é necessário permitir a substituição de funcionalidades existentes para poder customizar seu comportamento. É aqui que as macros são muito úteis porque podem adicionar código personalizado usando encerramentos.
Com o pacote PHP Macro, você também pode permitir que os usuários sobrescrevam métodos em classes base sem forçá-los a estender essas classes. O pacote PHP Macro NÃO usa reflexão ou outros hacks, apenas métodos PHP puros .
Existem alguns prós e contras quando comparados à injeção de dependência baseada em classe:
Pró:
Contra:
Portanto, não é um substituto para a injeção de dependência baseada em classe, mas uma adição leve para pequenos pontos de extensão onde a injeção de dependência completa usando interfaces de implementação de classes dá muito trabalho.
O resultado dos métodos existentes pode ser modificado se o método original verificar uma macro existente e usá-la em vez de sua própria implementação:
// 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 ;
}
};
Agora, você pode adicionar sua macro orderNumber
personalizada que será usada:
// user code
Order:: macro ( ' orderNumber ' , function ( string $ id ) {
return date ( ' Y ' ) . ' - ' . $ id ;
} );
( new Order )-> getOrderNumber (); // now returns '2020-123'
Assim, você pode gerar sua própria saída ou passar um resultado diferente para métodos subsequentes dentro do aplicativo.
Quando as macros são chamadas em um contexto de objeto, elas também podem acessar propriedades de classe:
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
Aqui, a propriedade privada $name
está disponível na 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'
A macro pode usar a propriedade como entrada para criar o valor retornado.
O pacote de macros PHP também permite herdar macros de classes pai. Então, eles podem acessar as propriedades da classe filha como métodos de classe regulares:
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
class B extends A
{
private $ name = ' B ' ;
};
As macros adicionadas à classe pai também estarão disponíveis nas classes filhas:
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return $ this -> name . ' : ' . implode ( ' - ' , $ values );
} );
( new B )-> concat ( [ ' 1 ' , ' 2 ' , ' 3 ' ] ); // returns 'B:1-2-3'
A classe B
se estende da classe A
mas fornece uma propriedade $name
diferente. A macro herdada da classe A
agora usará a propriedade da classe B
Também é possível sobrescrever macros herdadas de classes pai, assim como é possível com métodos de classe regulares:
// 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 {};
Agora você pode adicionar macros à classe pai e a uma das classes filhas:
// 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'
Isso permite adicionar manipulação especial para classes únicas, mesmo que todas as outras classes ainda usem a macro adicionada à classe A
.
As classes base geralmente oferecem um conjunto de métodos que são usados pelas classes filhas. No PHP, substituir os métodos de uma classe base é impossível e, portanto, você deve sobrescrever cada classe filha com sua própria implementação.
Para evitar isso, o método original pode usar o método call()
em vez de chamar diretamente o método da classe pai:
// 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- ' );
}
};
Isso verificará se há uma macro getName
disponível e a chamará em vez do método 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'
O método getName()
original ainda pode ser usado na macro.
Às vezes, pode ser necessário remover macros de objetos, especialmente ao executar testes automatizados. Você pode desativar uma macro usando:
class A
{
use Aimeos Macro Macroable;
};
// add macro
A:: macro ( ' test ' , function () {
return ' test ' ;
} );
// remove macro
A:: unmacro ( ' test ' );