2011-07-13

Papaya Callbacks

papaya CMS got a new class PapayaObjectCallbacks recently. The class can be used to define and handle callbacks for other classes and relies heavily on the magic methods. It addresses several problems.
  1. Code duplication if you have several callbacks in one class
  2. Validation before you can use the callback
  3. Easy to use, self speaking API for callbacks

PapayaObjectCallbacks is defined as a sub object with lazy initialization. An array is used to define the callbacks functions and the default return value. If you have a complex/large list of callback functions, I suggest to define a new class that extends PapayaObjectCallbacks. With a special class you can define the dynamic properties/methods using PHPDoc comments.

public function callbacks(PapayaObjectCallbacks $callbacks = NULL) {
  if (isset($callbacks)) {
    $this->_callbacks = $callbacks;
  } elseif (is_null($this->_callbacks)) {
    $this->_callbacks = new PapayaObjectCallbacks(
      array(
        'onEventOne' => TRUE,
        'onEventTwo' => 'default'
      )
    );
  }
  return $this->_callbacks;
}


To call the function is really simple. Just do it!

$result = $this->callbacks()->onEventOne($argument);

If no function was assigned to the callback the defined default will be returned. Otherwise the assigned function is called and its return value will be used. So no validation of the assignment is needed.

The user (of your class with the callbacks) can assign the callback function, now.

$someObject->callbacks()->onEventOne = array($this, 'someCallbackHandler');

In PHP equal or greater 5.3 an anonymous function is possible:

$someObject->callbacks()->onEventOne = function($context, $argumentOne) { ... };

The first argument of the callback is always a context object. The reason for this is, that we still have to be PHP 5.2 compatible, so we can not use the PHP syntax for it. In addition you can edit the context without a local variable. By default this is an instance of stdClass but you can assign any object.

$someObject->callbacks()->onEventOne->context->someProperty = 'some value';

If you like to see the implementation, you can find it in the papaya SVN.