When functions are invoked in this class, we have a business requirement to log that fact. In order to do that, we add a call to the logger at the beginning of the function.
class RequiresLogging { public function secretAction() { Logger::log( "notice", "Secret action performed by user " . $_SESSION['user'] ); // perform secret action... } }
This doesn't seem like much work, but of course there will not be just one ation performed by this class. Also, the calls to the logger are littered everywhere. Because we all like abstraction so much, enabling via attributes will provide a simplistic and very maintainable solution.
In order to make this work, the extension has one main function add_function_hook()
.
The function works a lot like an Aspect Oriented technique, whereby a function call is intercepted
and redirected to a function specified by the developer. The difference is that the function is only intercepted if
it has a particular attribute in its comments. Essentially, every time a function is called,
the extension:
So to implement the above code in an attribute oriented manner, we will need to:
class RequiresLogging { /** * @log notice "Secret action performed by user [user] */ public function secretAction() { // perform secret action... } } function performLog( $message ) { $parts = split( " ", $message, 2 ); $level = $parts[0]; $message = $parts[1]; Logger::log( $level, $message ); } add_function_hook( "log", "performLog" ); $object = new RequiresLogging(); $object->secretAction();
The amount of boiler plate code is no different from, say, a custom error handler
in PHP, yet once done, logging becomes extermely simple. I have also played around
with other parameters to add_function_hook
, especially one which prevents
the original destination function (secretAction in our example) from being executed
if the registered hook function returns false after analysing the attributes. This
would allow for low level permissioning of functions, at the Zend engine level.