Пакет макросов PHP предлагает внедрение зависимостей установщика на основе замыкания (анонимной функции), предоставляя признак, который можно включить в любой класс.
composer req aimeos/macro
Этот пакет предназначен для разработчиков приложений, платформ и библиотек, которые хотят разрешить пользователям настраивать поведение своего кода.
В приложениях, платформах или библиотеках, созданных для настройки, необходимо разрешить перезапись существующих функций, чтобы можно было настроить их поведение. Здесь очень полезны макросы, поскольку они могут добавлять собственный код с помощью замыканий.
С помощью пакета макросов PHP вы также можете разрешить пользователям перезаписывать методы в базовых классах, не заставляя пользователей расширять эти классы. Пакет макросов PHP не использует никаких отражений или других хаков, только чистые методы 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 ' );