Я хотел бы создать общую регистрацию декоратор это тип безопасно.
У меня есть ряд хранилища (интерфейсы), и нужен декоратор для каждого, который ловит исключения, которые они могут выдать, передает их экземпляру LoggerInterface а затем отбрасывает их. Можно создать выделенный декоратор и тестировать для каждого, хотя это довольно громоздко (особенно хорошо делает тест), и я этого избегаю.
С помощью __call
создание более общего декоратора — это первый подход, который приходит на ум. Однако это приводит к тому, что экземпляр объекта не реализует интерфейс хранилища, который он декорирует. Это не пойдет в моем проекте. Есть ли способ сказать PHP, что он реализует этот интерфейс, например, с помощью какой-то магии отражение?
Я прочел «Как реализовать декоратор в PHP?» а также «Лучший способ реализовать шаблон декоратора для кэширования результатов метода в PHP«Здесь, на stackoverflow, оба излагают выделенный и общий подход, хотя ни тот, ни другой не дают указаний на то, чтобы сделать общий подход безопасным для типов способом. Некоторое время прошло с тех пор, как эти вопросы были опубликованы, поэтому, возможно, все изменилось. используя PHP 7 и может использовать PHP 7.1 при необходимости.
PHPUnit_MockObject позволяет создать объект, реализующий интерфейс, через тот же код, который вызывается знакомым getMock
метод в PHPUnit. Это может быть основой универсального декоратора. Однако это потребует использования библиотеки-макета в производственном коде. Кроме того, эта библиотека внутренне использует eval чтобы получить свою работу. Это дисквалифицирует это для моего проекта.
Другой подход заключается в динамическом создании декорированных классов во время выполнения. к несчастью PHP не позволяет этого из коробки. Если runkit расширение не вариант, вы могли бы подражать тому, что Учение ОРМ делает: есть DecoratorFactory
это делает следующие шаги:
Смотрите пример на http://www.doctrine-project.org/api/orm/2.4/source-class-Doctrine.ORM.Tools.EntityGenerator.html
Единственный реальный способ получить то, что вам нужно, — это объявить базовый класс Decorator, который полностью реализует необходимый интерфейс, а затем расширяться на основе этого. Например:
interface FooInterface {
function doFoo();
function doMoreFoo();
}
class Foo implements FooInterface {
public function __construct() {}
public function doFoo() {}
public function moreFoo() {}
}
class FooDecoratorBase implements FooInterface {
protected $foo;
public function __construct(FooInterface $foo) { $this->foo = $foo; }
public function doFoo() { $this->foo->doFoo(); }
public function moreFoo() { $this->foo->moreFoo(); }
}
class ExtraFooDecorator extends FooDecoratorBase {
public function extraFoo() {}
}
Хотя я сам не могу процитировать специфику, мне сказали другие разработчики PHP, которых я уважаю, что использование Reflections в производственном коде — плохая идея, поскольку они были разработаны с учетом тестирования / отладки, а не производительности.
«Общие параметры типа» не доступны в PHP (кроме вариации HHVM в Facebook). Так что это невозможно. ответ @Sammitch это путь, если вы действительно хотите пойти по этому пути.
Однако вы пытаетесь решить другую проблему.
Шаблон декоратора действует как обертка. Вы используете его, если вы хотите добавить дополнительные функции для существующего класса, без изменения самого класса (или его состояния объекта).
Пожалуйста, подумайте, каким будет ваш декоратор:
function DoSomeOperation() {
try {
return $this->decoratedObject->DoSomeOperation(); //Object is injected in Decorators Constructor
catch (\Exception $ex) {
Logger::Log($ex);
throw;
}
}
Почему бы просто не сделать это без декоратора в вашем репозитории:
function DoSomeOperation() {
try {
//Do The Logic
catch (\Exception $ex) {
Logger::Log($ex);
throw;
}
}
Но, может быть, Decorator / Wrapper для объекта PDO — это то, что вы действительно хотите иметь? (ᵔᴥᵔ)