All previous attempts are mostly flawed due to http://ocramius.imtqy.com/presentations/proxy-pattern-in-php/#/71
Here is a simple example taken from my slides:
class BankAccount { }
And here is our "poor" interceptor logic:
class PoorProxy { public function __construct($wrapped) { $this->wrapped = $wrapped; } public function __call($method, $args) { return call_user_func_array( $this->wrapped, $args ); } }
Now, if we call the following method:
function pay(BankAccount $account) { }
Then this will not work:
$account = new PoorProxy(new BankAccount()); pay($account);
This applies to all solutions offering to implement a "proxy".
Solutions that explicitly use other methods that then call your internal API are erroneous because they force you to change your public API to change internal behavior and reduce type safety.
The solution provided by Kristoffer does not take public methods into account, which is also a problem, since you cannot rewrite your API to make it all private or protected .
Here is a solution that partially solves this problem:
class BankAccountProxy extends BankAccount { public function __construct($wrapped) { $this->wrapped = $wrapped; } public function doThings() {
Here's how you use it:
$account = new BankAccountProxy(new BankAccount()); pay($account);
This is a type-safe, clean solution, but it involves a lot of coding, so please take it as an example only.
Writing this boilerplate code is NOT fun, so you can use different approaches.
To give you an idea of how complex this category of problems is, I can just tell you that I wrote the entire library to solve them, and some smarter, older people even went and invented a completely different paradigm called Aspect Oriented Programming (AOP) .
Therefore, I suggest you study these 3 solutions, which I think can solve your problem in a much cleaner way:
Use the ProxyManager " access interceptor ", which is basically a proxy type that allows you to trigger closure when other methods are called ( example ). The following is an example of how to proxy ALL calls to the $object public API:
use ProxyManager\Factory\AccessInterceptorValueHolderFactory; function build_wrapper($object, callable $callOnMethod) { return (new AccessInterceptorValueHolderFactory) ->createProxy( $object, array_map( function () use ($callOnMethod) { return $callOnMethod; }, (new ReflectionClass($object)) ->getMethods(ReflectionMethod::IS_PUBLIC) ) ); }
then just use build_wrapper as you like.
Use GO-AOP-PHP , which is a real AOP library written entirely in PHP, but will apply this logic to ALL instances of the classes for which you define dot reductions. This may or may not be what you want, and if your $callOnMethod should be applied only to specific instances, then AOP is not what you are looking for.
Use the PHP AOP extension, which I believe is not a good solution, mainly because GO-AOP-PHP solves this problem in a more elegant / debugable way and because extensions in PHP are essentially a mess (which should be related with internal PHP components, not extension developers). In addition, using the extension, you make your application as portable as possible (try convincing sysadmin to install a compiled version of PHP if you dare), and you cannot use your application for new new engines, such as HHVM.