Search This Blog

4/27/2011

Callback

Introduction

Callback is a feature used to pass a function/method by parameter of an other function/method. In general, a function with generic operations receives a callback by parameter and use it to do specific operations. This way, it is possible to use the specific function in diferent places.

This feature is often used in array sorting function. The global operation to sort an array is the same (independs of the type of the array element), but the unit operation to compare two elements is specific (depends of the type of the array elements). For example, to sort an array of numbers, the unit operation is to use the "<" or ">" operators to determine which of two elements are bigger than the other. It is internaly implemented in the sort function, for example.

However, the sort function can not sort an array of objects, because the "<" or ">" operators do not work with this kind of element. Fortunately, we can implement a function that shows how to compare two objects and pass to the function usort using callback. This function sorts an array using a specific algorithm received by the parameter as a callback.

Example:

$array = array();

// Creating an array of 100 objects with random attribute value
for ($i = 0; $i < 100; $i++) {
    $obj = new stdClass();
    $obj->value = rand(0, 1000);
    $obj->name = 'test';
    $array[] = $obj;
}

// Creating a function to compare two objects
function compare_objects($obj1, $obj2) {
    if ($obj1->value < $obj2->value) {
        return -1;
    } elseif ($obj1->value > $obj2->value) {
        return +1;
    }
    return 0;
}

// Creating a callback
$callback = 'compare_objects';

// Using usort with the callback
usort($array, $callback);

Callback representation

The callback can be represented by these ways:

  • Function: the callback is a string with the funciton name;
  • Non-static Method: the callback is an array where the first element is an object and the second is a string with the name of the non-static method;
  • Static Method: the callback can be a string with the name of the class, followed by "::" and followed by the static method name. The callback can also be an array as the same way of a non-static method.

Tip: in PHP 5.3, with namespace suport, the callback of function or static methods may be specified with the absolute namespace where the function or class was defined.

User function or Native PHP functions can be used as callback. Although, remember that there are language construction that seems like functions, but they are not. Some examples are: echo, isset, unset, list, eval, include, and others. You must see a construction language and understand that it is like a "if", "while", "foreach" and similar, not a function.


Creating a generic function

All function/method that receives a parameter of callback pseudo-type should specify what the callback must receive by parameter and what it must return. This is important to the user of the generic function to know how to create the callback. The case of the sorting algorithm, the function must receive two parameters of any type and return a integer. If the first parameter is lower than the second, then the function must return a negative integer. If the second parameter is lower than the first, then the function must return a positive integer. Oterwise, the function must return "zero" to indicate that both are equivalent in sort operation.

To create a function that receives a callback, you should use the call_user_func_array or call_user_func to execute the function represented by the callback. An other solution is to use the callback as a "variable function". To check whether a callback is valid, use the is_callable function.

Example:

/**
 * Return the lower element of an array
 * @param array $array Array of any type of elements
 * @param callback $callback A callback function that compares two elements of the array
 * @return mixed The lower element
 */
function lower(array $array, $callback) {

    // Check parameter
    if (!is_callable($callback)) {
        trigger_error('Invalid callback parameter', E_USER_ERROR);
        return false;
    }

    // Get the lower element of array
    list($pos, $lower) = each($array);
    while (list($pos, $element) = each($array)) {

        // Using the callback to compare the current element with the current lower element
        $comparision = call_user_func($callback, $element, $lower);

        // If the element is lower than the current lower element, then it is the new lower
        if ($comparision < 0) {
            $lower = $element;
        }
    }
    return $lower;
}

No comments:

Post a Comment