Explore Aspect Oriented Programming with CodeIgniter, Part 1
Have you ever heard of Aspect Oriented Programming (AOP) before? It’s a widely used concept in developing enterprise level systems, although it hasn’t seen much use in PHP. I’m going to use this article as an opportunity to introduce PHP developers to AOP.
This tutorial will be delivered to you as a 3-part series. In this part I’ll explain the concepts of AOP. In part 2 I’ll show you the practical uses of AOP and creating a AOP rules structure. Finally, I’ll show you how to integrate AOP functionality using CodeIgniter in part 3.
What is AOP?
In application development we often find required functionality that needs to be used in multiple points in our code but which is not actually related to business logic. Checking authentication to make sure a user is logged in before executing a specific task is a good example. Such tasks are called cross-cutting concerns. Let’s take a look at the definition of cross-cutting concerns as given by Wikipedia:
In computer science, cross-cutting concerns are aspects of a program which affect other concerns. These concerns often cannot be cleanly decomposed from the rest of the system in both the design and implementation, and can result in either scattering (code duplication), tangling (significant dependencies between systems), or both.
Now that you have a basic idea of what cross-cutting concerns are, let’s see what they look like in code.
Consider the situation where you are the editor of a blog like SitePoint. You need to login in order to create posts, approve posts, edit post, etc. If you are not logged in, you should be directed to the login screen. In order to ensure this behavior, the code must validate authentication before each of the tasks mentioned above.
<?php
class BlogPost extends CI_Controller
{
public function createPost() {
if (!Authentication::checkAuthentication()) {
// redirect to login
}
else {
// proceed
Messages::notifyAdmin();
}
}
public function approvePost() {
if (!Authentication::checkAuthentication()) {
// redirect to login
}
else {
// proceed
}
}
public function editPost() {
if (!Authentication::checkAuthentication()) {
// redirect to login
}
else {
// proceed
}
}
public function viewPost() {
// ...
}
}
Look at the above code and you can see that checkAuthentication()
is called inside every method which needs the user to be logged in, and notifyAdmin()
is called to notify administrators when new posts are created. Not only is this duplicated code, but the BlogPost
class should be only responsible for managing posts. Authentication and notifications should be done separately. We have violated the Single Responsibility Principle:
The single responsibility principle states that every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.
So now we’ve come to a place where we can understand the meaning of AOP. Cross-cutting concerns can be grouped into objects called “aspects,” and the process of separating cross-cutting concerns from our core code is called Aspect Oriented Programming.
AOP Terminology
There are few specific terms used in AOP to explain its features. Understanding these terms will likely be the key to successfully integrating AOP into your PHP projects.
- Aspect
- Advice
- Joinpoint
- Pointcut
We just learned what an aspect is, so now let’s see what the other three terms mean.
Advice
The functionality of an aspect is called an advice. As the name suggests, advices define what to do in certain situations and when to do it. In our previous example, checking authentication (the what) is the advice, and it should be applied before executing code (the when) inside specific methods.
Joinpoint
Joinpoints are places in the application where we can create advices. Looking back at the sample code, you can find several places where I have called functionality that is not directly related to the business logic. In createPost()
, for example, cross-cutting concerns occurs before the executing any logic with the authentication check, and afterwards with sending a message to administrators. These are both possible joinpoints.
Joinpints can be defined anywhere in your application’s code, but applying advices will only be available to certain points according to your AOP framework features and will be discussed later in this tutorial.
Pointcut
Pointcut defines a way of matching advices to certain joinpoints. Though we have a couple joinpoints in our example, you could have thousands of joinpoints in your application and you might not need to apply advice to all of them. In such situations, we can match a subset of joinpoints, which is known as poincuts, and apply advices to the selected elements only.
Assume that we want to advice createPost()
, approvePost()
, and editPost()
, but not viewPost()
. We have to somehow match those 3 methods and apply the advices. Later we will be creating an XML file with aspect details which will contain regular expressions to match joinpoints.
So to summarize, when a cross-cutting concern occurs in the application, we create an aspect that advices the application functionality in certain joinpoints selected using a pointcut.
AOP Advice Types
There are few ways we can advice our code. As I mentioned earlier, the availability of these advice types depends on the type of AOP framework you use, but some types you should be familiar with are:
- Before advice
- After returning advice
- After throwing advice
- Around advice
Before Advice
Before advice will be applied before a specific point in your code, normally a method call.
I have used advices inside methods so far to simplify the concept and help you understand it quickly. But in the real-world, advices usually don’t come inside methods. There should be a separate global controller where each method should go in, and inside the method we can wrap the AOP functionality. This global controller is run inside the system and is not be visible to us.
<?php
class PathController
{
function controlPaths($className, $funcName) {
Authentication::checkAuthentication();
$classObj = new $className();
$classObj->$funcName();
}
}
Here I’ve created a dummy class to show you how it actually happens. Assume the controlPaths()
method acts as the global entry point for the application, and each method call will be passed through this method. In the above code we have applied the advice checkAuthentication()
before desired method call is actually performed. This is called before advice.
After Returning
This advice will be applied once specific functionality is completely executed and returned to the calling point. Consider the following code:
<?php
class PathController
{
function controlPaths($className, $funcName) {
$classObj = new $className();
$classObj->$funcName();
Database::closeConnection();
}
}
See here that once the method is completed we clean up the database resources. This is called after returning advice.
After Throwing
If the function throws an exception in the execution process, After throwing advice can be be applied. Here, the after throwing advice is the error reporting.
<?php
class PathController
{
function controlPaths($className, $funcName) {
try {
$classObj = new $className();
$classObj->$funcName();
}
catch (Exception $e) {
Error::reportError();
}
}
}
Around Advice
A fourth type of advice is around advice, which is a combination of both before advice and after returning advice.
<?php
class PathController
{
function controlPaths($className, $funcName) {
Logger::startLog();
$classObj = new $className();
$classObj->$funcName();
Logger::endLog();
}
}
Summary
In this article I introduced you to AOP. You should have a basic understanding of what AOP tries to accomplish, and be familiar with some of the basic AOP terms. In the next part of this series I’ll show you where AOP is needed in real world projects and how we can use CodeIgniter hooks to create AOP functionality. Stay tuned!
Image via Fotolia