Created
December 14, 2011 10:41
-
-
Save commuterjoy/1476082 to your computer and use it in GitHub Desktop.
PHP 5.4 traits to emulate AOP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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(); | |
?> | |
This appears to be a superficial opinion at best. Perhaps there's more coming on traits. Buf what shows for 5.4.0 ranks in the [proper term] category. "Nasty" certainly isn't the proper term. I've been looking at this for more than 5 years. The implementations vary from overkill to not even really anything. and like the current lithium, this traits feature appears to belong with the latter.
Down with php!
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
use
ing class) - How to enforce that this initialization is performed when
use
ing 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 theparent::construct()
and then theinitialize()
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
use
ing class; that is of course unrealistic and inflexible
- overriding the constructor means that the traits always know beforehand the signature of the __construct of the
-
- should a trait define it's own protected/private properties, to support the methods? Or the data should be held (and defined) on the
use
ing class?
- should a trait define it's own protected/private properties, to support the methods? Or the data should be held (and defined) on the
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output should be :-