PHP 宏包通过提供可以包含在任何类中的特征,提供基于闭包(匿名函数)的 setter 依赖注入。
composer req aimeos/macro
该软件包适用于希望允许用户自定义代码行为的应用程序、框架和库开发人员。
在为定制而构建的应用程序、框架或库中,有必要允许覆盖现有功能以便能够定制其行为。这就是宏非常方便的地方,因为它们可以使用闭包添加自定义代码。
使用 PHP 宏包,您还可以允许用户覆盖基类中的方法,而无需强制用户扩展这些类。 PHP 宏包不使用反射或其他 hack,仅使用纯 PHP 方法。
与基于类的依赖注入相比,有一些优点和缺点:
专业人士:
缺点:
因此,它并不是基于类的依赖注入的替代品,而是对小型扩展点的轻量级补充,其中使用实现接口的类进行全面的依赖注入工作量太大。
如果原始方法检查现有宏并使用它而不是它自己的实现,则可以修改现有方法的结果:
// 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 ;
}
};
现在,您可以添加将要使用的自定义orderNumber
宏:
// user code
Order:: macro ( ' orderNumber ' , function ( string $ id ) {
return date ( ' Y ' ) . ' - ' . $ id ;
} );
( new Order )-> getOrderNumber (); // now returns '2020-123'
因此,您可以生成自己的输出或将不同的结果传递给应用程序中的后续方法。
当在对象上下文中调用宏时,它们还可以访问类属性:
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
这里,私有属性$name
在宏中可用:
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return $ this -> name . ' : ' . implode ( ' - ' , $ values );
} );
( new A )-> concat ( [ ' 1 ' , ' 2 ' , ' 3 ' ] ); // returns 'A:1-2-3'
宏可以使用该属性作为输入来创建返回值。
PHP宏包还允许从父类继承宏。然后,他们可以像常规类方法一样访问子类的类属性:
// original code
class A
{
use Aimeos Macro Macroable;
private $ name = ' A ' ;
};
class B extends A
{
private $ name = ' B ' ;
};
添加到父类的宏也将在子类中可用:
// user code
A:: macro ( ' concat ' , function ( array $ values ) {
return $ this -> name . ' : ' . implode ( ' - ' , $ values );
} );
( new B )-> concat ( [ ' 1 ' , ' 2 ' , ' 3 ' ] ); // returns 'B:1-2-3'
B
类从A
类扩展,但提供了不同的$name
属性。从类A
继承的宏现在将使用类B
的属性。
也可以覆盖从父类继承的宏,就像使用常规类方法一样:
// 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 {};
现在您可以将宏添加到父类和子类之一:
// 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'
这使您能够为单个类添加特殊处理,即使所有其他类仍然使用添加到类A
宏。
基类通常提供一组供子类使用的方法。在 PHP 中,替换基类的方法是不可能的,因此,您必须用自己的实现覆盖每个子类。
为了避免这种情况,原始方法可以使用call()
方法,而不是直接调用父类的方法:
// 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- ' );
}
};
这将检查是否有可用的宏getName
并调用它而不是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'
原来的getName()
方法仍然可以在宏中使用。
有时,可能需要从对象中删除宏,尤其是在运行自动化测试时。您可以使用以下方法取消设置宏:
class A
{
use Aimeos Macro Macroable;
};
// add macro
A:: macro ( ' test ' , function () {
return ' test ' ;
} );
// remove macro
A:: unmacro ( ' test ' );