Functors for your single-parameter callback blues

When using PHP functions such as array_map, usort or preg_replace_callback, you are forced to pass in a single-parameter callback function, making it impossible to send additional context information to the callback. But it ain't necessarily so.

Function objects, aka Functors, are here to help. The idea is to create a small object that holds the additional context for you, and that will call your callback on your behalf, provided you can convince the PHP function to call a method on this object.

Here's how to do it:

<?php

/**
* A function object class to allow callbacks with arbitrary parameters.
*/
class Functor {
  function
__construct($callback, $args) {
   
$this->callback = $callback;
   
$this->args = $args;
  }
  function
callback() {
   
$args = array_merge(func_get_args(), $this->args);
    return
call_user_func_array($this->callback, $args);
  }
  static function
create_functor($callback) {
   
$args = func_get_args();
   
array_shift($args);
    return array(new
Functor($callback, $args), 'callback');
  }
  var
$callback;
  var
$args;
};

?>

Here's an example of using the functor, in the realm of Drupal filters:

<?php

/**
* Implementation of hook_filter().
*/
function myfilter_filter($op, $delta = 0, $format = -1, $text = '') {
  switch (
$op) {
  case
'process':
     return
preg_replace_callback(MYFILTER_REGEX, Functor::create_functor('myfilter_process', $format), $text);
  }
}

function
myfilter_process($matches, $format) {
 
$text = $matches[0];
  ....
  return
$text;
}

?>

That's it! Happy coding.

Comments

Just read your article on Drupal planet. This is exactly what I was looking for recently. Thank you so much! :)