Aspect-oriented Software Development and PHP
Introduction
Object oriented approach has been popular for a number of years. Its advantages can hardly be visible within short-term projects, yet any major long-term one simply cannot do without it. Object-oriented programming languages provide the tools necessary to present business logic in a demonstrable form. Today UML Class diagram (http://en.wikipedia.org/wiki/Unified_Modeling_Language) does suggest itself even on the stage of developing the system logic.
Demonstrable business logic makes it easier for new participants to join in, helps to save time for those developers that come back into the project at later stages. It also considerably reduces the number of mistakes. But is implementing object-oriented approach enough to develop the demonstrable business logic? Obviously not. To create smart object-oriented programme architecture is not an easy task – unless you were able to successfully implement methods described in the book by Martin Fowler called Refactoring: Improving the Design of Existing Code.
Yet even now one can find not encapsulated functionality (crosscutting concerns) in a number of various classes (logging, caching, synchronizing, tracing, monitoring, debugging, run a security check, start a transaction, open a database connection). AOSD (aspect-oriented software development, http://en.wikipedia.org/wiki/Aspect-oriented_programming) is capable of organizing this kind of program logic.
What is AOSD?
Aspect-oriented software development (AOSD) is a relatively new approach in the area of developing business applications. This approach is based on the notion of Aspect. Aspect is a standpoint for considering some other notion, process or perspective. To be able to quickly discern the underlying idea of the approach, let us try and consider various aspects of a web-site. Information architecture defines a site’s structure. Usability refers to the degree of site’s friendliness towards the user. Graphic design determines the visual perception of a site. The functional model describes its business logic. All of them are various components of the web-site development process, and each component requires specific resources, approaches and solutions. For a project to be successful, all of the aforementioned components are to be efficiently developed and implemented. Lest someone should find this example too complicated, let us consider a simpler and more universal scheme. When an apartment building is being designed, the architect had to first elaborate a framework, then the wirework scheme, then the water supply plan and so on and so forth. Each of the stages in this process is a different aspect, a different perspective of the project. No matter how trite it may sound, a similar approach can be implemented in software development for identifying various aspects of business logic within applications. More than 20 years ago Bjarne Stroustrup (http://en.wikipedia.org/wiki/Bjarne_Stroustrup) arranged the programme code within C into sets of logical entities, whose behaviour and interactions could be defined in a number of ways (inheritance, encapsulation, abstraction, polymorphism). It is a reliable and time-tested paradigm of software development, known as object-oriented programming. Yet this approach has certain limitations as to the decomposition of application business logic aspects. Over the years that have passed since the time this paradigm emerged, a number of approaches aimed at overcoming the said limitations have emerged. Among them are adaptive programming, composition filters, aspect-oriented programming, hyperspaces, role-modelling, subject-oriented programming and so on. Lately, the development of such approaches has moved to the area of AOSD. As we have already pointed out, the cross-cutting concerns code is going to be distributed among the various modules, which will inevitably impair the quality of the software with regard to the transparency of business logic, its adaptability and upgradeability. The aim of AOSD is to isolate the cross-cutting concerns and place it outside applications' business logic.
Let us consider some integrated web-application, for example CMS, and try to imagine at what point and in what way we are likely to encounter the above-mentioned difficulties. Suppose, a certain number of system functions require converting input data from XML to arrays. Due to the fact that in this case XML-parsing aspect involves only a limited number of functions, it doesn’t imply considerable extension. As it is clear, in such case there’s no need for extensive decomposition and therefore no need for AOSD to be implemented. The simplest and most logical solution would be to include this procedure into the root class method (or, otherwise, into the external class, depending on the specific circumstances) and activate it when it’s needed.
Yet no manipulations with objects are going to help if we have to monitor the productivity, and our task is to take on demand the readings of all functions performed, at their entry and exit points. An attentive reader would suggest that we should resort to the previous example and use trigger for activation or deactivation of statistic data capture. Well, we can only warn him or her that, should a need arise for logging system transactions in specified cases, it will become necessary to recall all the details of programme architecture and to reorganize it.
It would be much more practical to task the system with handling specified events in certain objects within a given aspect. Suppose, after some time new security requirements have to be introduced into a large and sophisticated project. We then create a procedure for additional security checks and task the system with carrying out this procedure at the activation of specified methods within the security aspect. This is implied by the paradigm of AOSD. We set up a new abstraction level outside the existing program architecture, and then in it we declare a functionality that in some way is applicable to the whole of the system. As you can see from Figure 3, it is possible to define program procedures that attend the system, say, within the security aspect, and then place them outside the main classes. In the same way we can treat the input data validation aspect procedures. Thus, with each time we make the business logic more evident and demonstrable. As a matter of fact, what we get as a result is a clearly defined business logic in system’s main classes and precisely distributed outside the essential model cross-cutting concerns.
Let us sum up:
- the aspect-oriented approach is based on the principle of identifying common program code within certain aspects and placing the common procedures outside the main business logic;
- the process of aspect orientation and software development may include modelling, design, programming, reverse-engineering and re-engineering;
- the domain of AOSD includes applications, components and databases;
- interaction with and integration into other paradigms is carried out with the help of frameworks, generators, program languages and architecture-description languages (ADL).
Basics of Aspect-Oriented Approach
Aspect-oriented programming allows developers to organize cross-cutting concerns into individual declarations – aspects. It provides possibilities to define functionality for specified program execution points JoinPoints (method activation , class construction, access to a class field etc.). Languages that support aspect-oriented programming (AOP) more commonly employ functions for a set of points – Pointcut. The functionality at those points is determined by the program code which is politely referred to as Advice (AspectJ). Thus, aspects describe crosscutting concerns for a specific set of system components. The components themselves include only business logic that they are supposed to implement. During compilation of the program the components are associated with aspects (Weave).
To better grasp the basics of aspect-oriented programming, let us once again consider the example, which involves defining the productivity monitoring aspect. (see Figure 2). Suppose, we want to take the timer readings at entry and exit points of all the methods within such classes as Model, Document, Record and Dispatcher. So, we have to introduce into the Logging aspect a Pointcut with the listing of all the required functions. To cover all of the methods of a certain class, most AOP-supporting languages employ a special mask. Now it is possible to define the needed Pointcut. We set up Advice at the entry (Before) and exit (After) points to the methods listed in the Pointcut. Usually, Advice in AOP-supporting languages is available for such events as Before, After and Around, though sometimes other events are also present.
Thus, the following basic AOP declarations may be singled out:
-Aspect – a definition of a certain set of cross-cutting concerns performing a specific task; -Pointcut – a code of an Aspect’s applicability: defines when and where the functionality of a given aspect may be applied (see Figure 3) -Advice – a code of an object’s functionality: a direct functionality code for the specified events. In other words, this is what is going to be executed for the objects listed in the Pointcut.
Still too complicated? Well, I think everything will become clear once we introduce some practical examples. Let us begin with the simplest of them: https://github.com/dsheiko/aop4php. I wrote this small library with a view to demonstrate both the advantages and availability of AOSD.
It is possible to define a certain aspect for crosscutting concerns (let’s say, for keeping transaction log), through initiating the \Lib\Aop\Aspect class:
$aspect1 = new \Lib\Aop\Aspect();
Then we set up a Pointcut and specify the methods it affects:
$pc1 = $aspect1->pointcut("call Sample::Sample or call Sample::Sample2");
The only thing remaining is to specify the program code for entry and exit points for the methods of the current pointcut:
$pc1->before(function()
{
print 'Aspect1 preprocessor<br />';
});
$pc1->after(function()
{
print 'Aspect1 postprocessor<br />';
});
In the same way we can define an additional aspect, for example:
$aspect2 = new \Lib\Aop\Aspect();
$pc2 = $aspect2->pointcut("call *::Sample2");
$pc2->before(function()
{
print 'Aspect2 preprocessor<br />';
});
$pc2->after(function()
{
print 'Aspect1 postprocessor<br />';
});
In order to enable one or several aspects just use the Aspect:::apply() function:
$aspect1->apply();
$aspect2->apply();
Further we need to specify the points of our concern using before, after and event static method of \Lib\Aop\Advice:
class Sample
{
public function sample()
{
\Lib\Aop\Advice::before();
print 'Class initilization<br />';
\Lib\Aop\Advice::after();
return $this;
}
public function sample2()
{
\Lib\Aop\Advice::before();
print 'Business logic of Sample2<br />';
\Lib\Aop\Advice::after();
return $this;
}
}
Mark that event triggers \Lib\Aop\Advice::* may have any number of arguments. Specified with pointcut handler then receive all these arguments preceding by mandatory \Lib\Aop\Dto\Trace object.
$pc->before(function($trace, $arg1, $arg2)
{
echo "Entry point of ", $trace->class, "::",
$trace->function, " with passed arguments ", $arg1, ", ", $arg2, PHP_EOL;
});
//...
function sample() {
\Lib\Aop\Advice::before($arg1, $arg2);
}
Now during the run of these marked methods PHP fires corresponding events. It checks if the caller function matches pointcuts of any of enabled aspects and if it' so invokes handlers respectively.
An example of practical use? Suppose, we have wrapped our code with advices (\Lib\Aop\Advice methods) . Then one day a need arises to obtain a detailed report on the distribution of workload among the functions of our project. We set up an aspect and define its Pointcut, which includes all functions within the project:
$Monitoring = new Aspect();
$pc3 = $Monitoring->pointcut("call *::*");
Now we can attach before and after event handlers which will store timestamp on entry point and on exit point of very function affected. When having that log it’s not a big deal to make a report on functions performance.
Moreover, this library allows you to register your own system events and define cross-cutting concerns for them in the future. Your own events could be defined in any place of application code:
Advice::event("OnProcess", $arg1, $argN);
We could add event handler for the necessary events to make an additional decomposition or include a new plug-in in a complete application:
$aspect3 = new \Lib\Aop\Aspect();
$pc3 = $aspect3->pointcut("call *::*");
$pc3->event("OnProcess", function()
{
echo "It's controller";
});
$aspect3->apply();
Let us consider another example. PHP is quite tolerant towards various types of variables. On the one hand, this is a very positive feature for it means that there’s no need to constantly check for compliance with the specified types and waste time for the declaration. On the other, this could lead to errors.
In case a project contains a huge number of functions, it is hardly possible to remember the syntax we have devised for them. Yet misplacing even one single argument can cause unpredictable changes in a function’s behaviour. Can AOSD be of help in such situation? Definitely! Let us recall the diagram in Figure 3. As you see, classes Document and Record contain similar methods add, update, delete, copy, get. A well-organized program architecture presupposes similar syntax for these methods: add($id, $data), update($id, $data), delete($id), copy($id1,$id2), get($id). AOSD can help us to organize the program architecture – as well as our own activities. We can set up input data validation aspect and define the Pointcut for the Document and Record class methods. The add, update, delete, copy and get entry event function can check for the type of the first argument. If the latter is not integer, an error has surely occurred. It is also possible to set up the second Pointcut for the add and update methods. What is going to be checked in this case is the type of the second argument, which obviously has to correspond to the array type.
In this way we can place transactions logging outside the project business logic; now it is possible at any time to define functions, which require additional checks for security etc.
Of particular interest is the fact that with the help of AOSD we can provide for a specific system error warning to be displayed for a specified set of functions. Suppose, a number of our functions participate in setting up WML (WAP), WSDL (SOAP), RSS/ATOM or SVG mark-up code. Obviously, in this case it is unacceptable to display HTML-code with the error message. The “notifier” in PHP error processor will make the system display the message either in XML, or use non-visual means (for example, send a notification via e-mail).
Anyone who at least once participated in the development of commercial software, knows how difficult it is to solve the issue of updating the final product. Certainly, we are all aware of the existence of the version control software – for instance, CVS (Concurrent Versions System, http://en.wikipedia.org/wiki/Concurrent_Versions_System ).Yet the problem is that every new product, based on the previous one, requires certain customization, and more often than not it is not at all easy to find out whether the update is going to affect areas customized for a specific project. Some of you have surely encountered cases when after an update you had to restore the whole project from back-up copies. And now just try to imagine a case when “disappearance” of customized features is noticed only a long time after the update! “Well, where does AOSD come in?” you may ask. The thing is that AOSD can exactly enable us to address this issue: the whole customization code can be placed outside the project’s business logic as crosscutting concerns. You only have to define the Aspect of interest, specify the area of its application (Pointcut) and elaborate the corresponding functionality code. It is worthwhile trying to imagine how exactly this is going to work.
Aspect-Oriented Software Development in PHP
At present there are a number of advanced projects, whose authors have introduced various techniques of AOSD and PHP implementation. The AOPHP project (http://www.aophp.net ) includes a PHP preprocessor written in Java 1.5. We can write a usual PHP-code, but we’ll also have to notify the preprocessor of our intention to use AOSD. To do this, we’ll use structure instead of . The crosscutting concerns can be put into separate scripts.
before(): execr(add($x,$y)) | execr(sub($x,$y)){
echo "<font color=red>Im About To Add/Sub $x %26 $y</font><br>";
}
If necessary, these scripts can be enabled by issuing instruction while declaring AOPHP code:
<?aophp filename="aotest.aophp,aotest2.aophp" debug="off"
// PHP code
?>
Seasar.PHP project (http://www.seasar.org/en/php5/index.html) employs a different approach. Its authors use XML for structuring aspect declarations, while integration is carried out with the help of PHP, which then executes the resulting code through eval() function.
MFAOP project (www.mfaop.com ) is based on an approach slightly resembling the one I mentioned in the above examples. The project’s author suggests that first one should set up a Pointcut and then use it according to what is needed:
$pointCut = new PointCut();
$pointCut->addJoinPoint('Example', 'Foo');
$pointCut->addJoinPoint('Example', 'Bar');
$test1 = new Aspect($pointCut, before, 'echo "Before $MethodName";');
$test2 = new Aspect($pointCut, after, 'echo "After $MethodName";');
Unlike in aop.lib.php library, when using this solution there’s no need to manually insert “notifiers” for each function. Yet we’ll have to install an additional PECL Classkit extension on the server.
From my point of view, the most elegant solution has been found by PHPAspect project (www.phpaspect.org ). This was possible thanks to the effective use of new capabilities provided by PHP5, and in particular – the possibility to set up abstract classes. PHPAspect introduces into the language of PHP a specific structure; which presents the declared aspect in a demonstrable form.
aspect TraceOrder{
pointcut logAddItem:exec(public Order::addItem(2));
pointcut logTotalAmount:call(Order->addItem(2));
after logAddItem{
printf("%d %s added to the cartn", $quantity, $reference);
}
after logTotalAmount{
printf("Total amount of the cart : %.2f %26euro;", $thisJoinPoint->getObject()->getAmount());
}
}
As it’s clear from the example, the interval of the specified aspect is precisely defined. The Pointcut and Advice are set up in a way that is so concise and yet capacious, that one may think this is the “native” PHP syntax. This project provides handling capacities for 7 (!) types of Join point events: call, execution (exec), class construction (new), attribute write-in (set), attribute read operation (get), class destruction (unset) and block catching (catch). There are three possible types of Advice: before, after, around. This project developed unusually flexible masks for defining surveillance intervals in Pointcut. Thus, for instance, it is possible to assign intervals for all classes with the specified prefix in the name:
new(*(*));
exec(* Order::addItem(2));
call(DataObject ->update(0));
To be able to install PHP Aspect, you’ll need PHP 5.0.0. or later versions, and have PEAR Console_Getopt, Console_ProgressBar, PHP_Beautifier libraries installed.
This project was successfully presented last year at the PHP conference (http://afup.org/pages/forumphp/) in France (this is where the project originates from), and as for as I know is making good progress. It is possible that Zend Inc. will include the experience generated by this project into the following versions of PHP.
Conclusion
Obviously, AOSD is not a universal solution. AOP is not going to eliminate all bugs or develop software on its own. I doubt that every developer using aspect-oriented programming will get a Nobel Prize. Moreover, this approach is hardly going to become the dominant one in the future: object-oriented approach has been popular for 20 years, yet many developers still confine themselves to procedural code. On the other hand, the advantages of AOSD before object-oriented programming are as obvious as OOP’s advantages before procedural programming. I think I’ll be on the safe side if I say that those developers who use AOSD are one-step ahead of the others. Their code is clearer, easier to perceive, it contains less errors and can easily be developed. Thus, AOSD engineers are capable of implementing larger-scale, more reliable and versatile projects. Importantly, AOSD does not require complete retraining of developers. AOP doesn’t alter programming logic drastically, as it was the case with transition from procedural to object-oriented programming. AOSD just extends it. Developing a new program architecture, you only extract from the objects everything that you think doesn’t fit there and find a suitable place for it. Imagine that for years you’ve tolerated a piece of sculpture, which totally disagrees with the overall design of your home, but which you treasured as a gift. And then one day you find an inconspicuous niche in the wall where the sculpture seems to fit perfectly. “Well then,” you’d say in that case, “this is where it really belongs!”
Apart from all that has already been said, AOSD is easy to get used to – unlike, for example, TDD (http://en.wikipedia.org/wiki/Test_driven_development). At first, one could try and put into aspects simple crosscutting concerns, like logging, and then gradually extend decomposition of program architecture, accumulating in aspects various domains of the application.
Perhaps, some are confused by the fact that at present PHP does not officially support AOSD. Yet in this very article I have presented several examples of how you can easily integrate basic AOSD approaches on your own. It is the essence of AOSD that is important, not the particular way in which it is implemented. Whatever approach you chose, if you were able to achieve efficient decomposition in program architecture it is inevitably going to improve the quality of your product. Today AOSD is supported mainly by extensions to popular programming languages, yet the leading players on the market are not going to stay out of it, and AOSD is gradually finding its way into the popular programming platforms (http://www.internetnews.com/dev-news/print.php/3106021). AOSD is not going to become a new technological revolution, yet evolution, on the other hand, is inevitable. Whether you follow it or take the lead is a matter of your own choice.
Resources & References
[1] Pan-Wei Ng, Ivar Jacobson. Aspect-Oriented Software Development with Use Cases. Addison Wesley Professional (Dec 30, 2004), ISBN: 0321268881.
[2] Robert E. Filman, Tzilla Elrad, Siobhan Clarke, Mehmet Aksit. Aspect-Oriented Software Development. Addison-Wesley Professional (October 6, 2004), ISBN: 0321219767.
[3] Ramnivas Laddad. Aspect Oriented Refactoring. Addison-Wesley Professional (September 29, 2006), ISBN: 0321304721.
[4] Ivan Kiselev. Aspect-Oriented Programming with AspectJ. Addison-Wesley Professional (July 17, 2002), ISBN: 0672324105.
- http://en.wikipedia.org/wiki/Aspect-oriented_programming
- http://eclipse.org/aspectj/
- http://phpaspect.org/
- http://www.aophp.net/
- http://www.seasar.org/en/php5/index.html
- http://www.phpclasses.org/browse/package/2633.html
- http://www.informit.com/articles/article.asp?p=375541&rl=1
- http://www.devx.com/Java/Article/28422
- http://www.scriptol.org/history.php
- http://www.ercim.org/publication/Ercim_News/enw58/mens.html
- http://www.cs.ucl.ac.uk/staff/C.Courbis/papers/12jan04Board.ppt
- http://www.computerworld.com/developmenttopics/development/story/0,10801,85621,00.html