Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.Sign up
Aspect oriented programming proxies
In computing, aspect-oriented programming (AOP) is a programming paradigm which isolates secondary or supporting functions from the main program's business logic. It aims to increase modularity by allowing the separation of cross-cutting concerns, forming a basis for aspect-oriented software development.
In the context of this dependency injector, AOP is achieved thanks to PHP's __call magic method combined with the Proxy design pattern. In short
- Assume an existing service declaration exists called MyService
- An AopProxyService class instance is created, and assigned this service being proxied which it stores in a member variable.
- Objects are added to the AopProxyService instance's "beforeCall" and "afterCall" lists; each of these implements either the beforeCall or afterCall method
- When client code declares a dependency on MyService, it is actually passed in the AopProxyService instance
- Client code calls a method myMethod it knows exists on MyService - this doesn't exist on AopProxyService, so __call is triggered.
- All classes bound to the beforeCall list are executed; if any explicitly returns 'false', myMethod is not executed.
- myMethod is executed
- All classes bound to the afterCall list are executed
The following is an example of the configuration required for this; in this case, we're going to replace the definition of "DataService" with a proxied version of it; note that we're NOT using the existing definition - we're declaring a completely new instance of DataService which will then be proxied - remember though, because the injector doesn't actually create anything until reference, all that happens here is having multiple specifications, not actual objects - only one every actually gets created.
singleton('Injector')->load(array( array( 'class' => 'DataService', 'id' => 'DataServiceForProxy' // we can use whatever name here - the object doesn't actually // exist until bind time, so multiple definitions don't matter ), array( 'class' => 'PermissionCheckAspect', 'constructor' => array( 'WRITE' ) ), array( 'id' => 'DataService', // overwriting the default implementation 'class' => 'AopProxyService', 'properties' => array( 'proxied' => '#$DataServiceForProxy', 'beforeCall' => array( 'write' => '#$PermissionCheckAspect' ) ) ) ));
The PermissionCheckAspect here is very simple - it merely checks to see if the current user has the configured permission (in this case WRITE). Effectively, this ensures that the current user has 'WRITE' permission to the passed in object any time the write() method is called on the DataService object, wherever that is used throughout the system.