📜 ⬆️ ⬇️

PHP and Aspect-oriented programming

The aspect-oriented programming (AOP) paradigm that is quite popular in the Java world for some reason is poorly covered in PHP development. In this article I want to present my approach to writing AOP applications using a small framework and module.

Briefly about aspect-oriented programming


Aspect-oriented programming is a paradigm based on the idea of ​​dividing the functionality to improve program partitioning into modules.
Briefly, the essence of the approach is to create functions that run on a specific event (for example, a method call). Depending on the definition, the functions are launched either before the execution of the event, or after (or before and after), so they can take on quite a variety of operations - from logging to synchronizing information about the object with the database (persistence).
The conditions under which such functions are performed are called “join points”, the groups of conditions are “point cuts” (point cut), and the functions themselves are called “advice” (advice).
Most often, tips are grouped into aspects (exactly as methods into classes), so an aspect is a set of tips that implement some functionality.

PHP implementation


There are two obvious implementation methods:
1) create wrapper functions for all potential connection points from which to call for necessary advice;
2) embed your code in the process of launching methods that will run the necessary tips or not run if there are no corresponding connection points.
The main disadvantage of the first method is redundancy. Even more difficult is the task of deciding to implement AOP into an existing system that does not have wrapper functions.
The second method looks nicer, but needs an additional extension to PHP. About him (method) and will go on.
')

MethodIntercept Module


Oddly enough, but for PHP5 + there is no extension that allows you to intercept object method calls. All that happened was to find this Intercept , the development of which focused on the alpha release in 2005. An extension can perform some function before and / or after another function. With OOP in PHP5, of course, does not work.
On the basis of it, I wrote MethodIntercept, which, in addition to intercepting the method call, is also able to pass an object to the interceptor function, whose method is called and the arguments passed to the method.
Compiling an extension is quite simple (example for Linux):
git clone git@github.com:kooler/PAF.git cd PAF/MethodIntercept phpize ./configure make 

As a result, the intercept.so file will appear in the modules folder, which you need to copy to the folder with PHP extensions (you can find it out by running php -i | grep extension_dir) and adding in php.ini: extension = intercept.so.
If everything described above was successful, it will be possible to use the intercept_add function, which takes 3 parameters: class-> method to intercept, function to be called, interception method - before or after.

PHP Aspect Framework (PAF)


Despite the fact that MethodIntercept allows you to embed your code in the process of launching methods, this is not enough to fully work with AOP for several reasons:
1. The extension does not support the queue - you can specify only one interceptor function.
2. Interceptor can only be a function and cannot be a method; accordingly, grouping tips into aspects is impossible.
3. It is not very convenient to specify an interceptor by calling a function (intercept_add).
It is not advisable to add the implementation of all of the above to MethodIntercept, since its task is to intercept the method call, and not to provide all the necessary AOP buns (it may be worthwhile to write a separate extension for this).
Therefore, I decided to write my own mini-framework, which simplifies the use of AOP, namely:
1. Allows you to define connection points using annotations
2. Takes call queue generation and intercept_add execution
3. Allows you to create aspects
4. Allows the use of regular expressions when defining join points.
The framework is called the PHP Aspect Framework (or PAF for short): github.com/kooler/PAF

Classic AOP example - logging


Consider the application of the framework on the classic example of the use of AOP - logging.
Suppose we have a class:
 class Backet { public function order() { //  } public function createNew() { //  } } 

Suppose that we want to display a message (or write to the log) each time the user draws up or creates a basket. Create an aspect of the Logger, which will include two tips: the first should be called after the cart has been created, and the second after creation:
 class Logger extends Aspect { /* * @After(Backet->order) */ public function backetOrderMessage($params) { echo 'Backed has been ordered'; } /* * @After(Backet->createNew) */ public function backetCreatedMessage($params) { echo 'Backet has been created'; } } 

We register the aspect and perform the implementation function:
 AspectRegistry::getInstance()->addAspect(new Logger); AspectRegistry::getInstance()->interceptAll(); 

The latter should be called only once, after registering all aspects, it is she who is responsible for building the queue and performing the intercept_add function.
Each argument is passed one argument - an array, the first element of which contains the object, whose method was intercepted, and the second argument passed to the intercepted method. Thus, if for example you need to display the user name when placing an order, the advice will look like this:
 class Backet { public $username; … } class Logger extends Aspect { /* * @After(Backet->order) */ public function backetOrderMessage($params) { echo 'Backed has been ordered by user: '.$params[0]->username; } ... } 

The complete code for a similar example: github.com/kooler/PAF/blob/master/Framework/example.php

Conclusion


Now the framework is at a rather early stage - there is room to grow. I plan to add the ability to connect plug-ins, implement synchronization of objects with the base (persistance) and much more. Judging by the popularity in Java, the paradigm is quite interesting and has the right to life in PHP.
I would be grateful for any advice and ideas, and whether AOP is needed in PHP at all.

Source: https://habr.com/ru/post/131994/


All Articles