I'd like to create a generic logging decorator that is type safe.
I have a number of repositories (interfaces), and need a decorator for each that catches the exceptions they might throw, passes those to an instance of LoggerInterface and then rethrows them. It's possible to create a dedicated decorator and test for each, though this is quite cumbersome (especially doing the test nicely), and something I rather avoid.
Using __call
to create a more generic decorator is the first approach that comes to mind. This however results in an object instance that does not implement the repository interface it decorates. That is a no go in my project. Is there some way to tell PHP that it does implement this interface, such as by use of some magic reflection?
I've read "how to implement a decorator in PHP?" and "Best way to implement a decorator pattern for method result caching in PHP" here on stackoverflow, both which outline the dedicated and the generic approach, though neither offer an indication of doing the generic approach in a type safe manner. Some time has passed since those questions where posted, so perhaps things have changed. I'm using PHP 7 and can use PHP 7.1 if needed.
PHPUnit_MockObject allows constructing an object implementing an interface, via the same code that gets invoked by the familiar getMock
method in PHPUnit. That can be the basis of a generic decorator. However that would require using a mocking library in production code. Furthermore, this library internally uses eval to gets its job done. This disqualifies it for my project.
Another approach would be to dynamically create the decorated classes at runtime. Unfortunately PHP doesn't allow this out of the box. If the runkit extension is not an option, you could emulate what Doctrine ORM does: Have a DecoratorFactory
that does the following steps:
See an example at http://www.doctrine-project.org/api/orm/2.4/source-class-Doctrine.ORM.Tools.EntityGenerator.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With