Skip to content

Instantly share code, notes, and snippets.

@commuterjoy
Created December 14, 2011 10:41
Show Gist options
  • Save commuterjoy/1476082 to your computer and use it in GitHub Desktop.
Save commuterjoy/1476082 to your computer and use it in GitHub Desktop.
PHP 5.4 traits to emulate AOP
<?php
// There's a few nasty AOP implementations in PHP that either
// rely on code generation or reflection. PHP 5.4 should allow us
// to define the horizontal concerns using _traits_
// - ref. http://php.net/manual/en/language.oop5.traits.php
/**
* A class that does something. Nice, clean. Just business logic.
**/
abstract class Base {
public function sayHello($arg) {
echo "Base class says _hello_ with argument: '$arg' \n";
return true;
}
public function sayByeBye() {
echo "Base class says _bye_bye_ \n";
return true;
}
}
/**
* Some logging advice
**/
trait LoggerAdvice {
// match the signature of the base method and add logging around the sayHello method
public function sayHello($arg)
{
echo 'logging before ' . get_class($this) . "\n";
$r = parent::sayHello($arg);
// eg, could add logging conditionally on the return value
echo 'logging after - return value of ' . $r . "\n";
echo $this->log();
}
public function sayByeBye() {
parent::sayByeBye();
echo $this->log();
}
// provide common logging across methods
protected function log()
{
echo "****log\n";
}
}
/**
* Apply the advice to an concrete instance of the class
**/
class MyHelloWorld extends Base {
use LoggerAdvice;
}
// call the method with it's advice
$o = new MyHelloWorld();
$o->sayHello('foo');
$o->sayByeBye();
?>
@Pictor13
Copy link

That's interesting, but I still have several technical doubts on best practices for performing AOP with Traits:

  • What about having to do initialization code for the trait, like injecting services (that I think is a smelly practice) or initialising the values of some trait's properties? (maybe according to the value as defined in the useing class)
  • How to enforce that this initialization is performed when useing the trait? How to communicate minimal requirements to the developer that wants to use the trait?
  • Isn't it smelly to solve the problem overriding the __construct magic method, calling the parent::construct() and then the initialize() method?
    • the trait shouldn't be aware of construction; traits are not classes but just collections of behaviours (so I am not even sure if should define data/properties).
    • overriding the constructor means that the traits always know beforehand the signature of the __construct of the useing class; that is of course unrealistic and inflexible
    • should a trait define it's own protected/private properties, to support the methods? Or the data should be held (and defined) on the useing class?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment