Die Flagge des Marasek

Dekostreifen

Deutsch

Current Texts Comic Imprint Calendar Search PHP-Classes Container-Wizard main.s21

Categories

Class Library
Computers
Gaming
Global Politics
Programming
Society
Weblog
World Outlook
{{login}}

paran: Callback

Permalink
Previous: paran: AutoloaderNext: Finanzkrise, Gesellschaftskrise
Assigned keywords: Programmieren

I use the callback pattern often. It is a good solution to keep software modular and extensible; I have certain examples within my library where the main classes have little functionality beyond their main purpose. One example is a class displaying a table from a query. A typical need is to format values coming from the database, such as to turn ISO 8601 dates into their nationalized counterparts. I could of course implement a conversion method within the main class, but it is obvious that there are many other possible conversions as well as the fact that I probably need the conversion of dates more often. It is therefore a good idea to write this functionality into a separate class and give it to the display class as callback.

Now callbacks are a little bit awkward to handle. First of all, you have to check (or you should!) whether the callback is available or not. And then you possibly want to give the function some parameters as well. Consider the following example:

<?php
function formatDate($timestamp$target) {
    switch(
$target) {
        case 
"de":
            return 
date("d.m.Y");
        break;
        case 
"us":
            return 
date("m/d/Y");
        break;
        case 
"iso":
            return 
date("m/d/Y");
        break;
    throw new 
Exception("no valid date format selected");
    }
}
?>

Now you give it to a method demanding a callback:

<?php
$list
->addCallback("column_name""formatDate""de");
?>

Within that method, you have to check that formatDate is_callable as well to handle and keep everything than the second parameter as possible parameters for the callback. You have to drag it with you along to the place where the function is called, and there you have to splice the value(es) on which the callback is to be bestowed into the kept values, to finally call the callback with call_user_func_array. Pretty much to consider and therefore pretty much to go wrong. Not to mention that you have to handle a lot of code which has nothing to do with the class as such.

Enters class Callback, as I think the whole callback thing screams for an object oriented wrapper class. Basically, it works as follows:

<?php
//construct with formatDate as callback and parameter "de".
$callback = new Callback("formatDate""de");
$date $callback->call($timestamp)

class 
Whatever {
    private 
$callback;
    
// make use of type hinting here
    
function setCallback(Callback $callback) {
        
$this->callback $callback;
    }

    function 
doWhatever() {
        
/* ... */
        
$convert $this->callback($value);
        
/* ... */
    
}
}
?>

The single instance of callback is easy to handle as it keeps all necessary values neatly encapsulated within itself. And once you call the callback, you can rely upon that it can be called, because Callback::__construct() fails if you give it a bogus function / method.
The first parameter of __construct(); can be any variation of the callback pseudotype, while further parameters will be stored and given to the callback when it is called (after the parameters which are given to Callback::call).

Now paran would not be paran if there is not a paranoid way to do things. There are situations where you want be sure that you get what you expect from a callback. You would not be so happy if you call a converter and get an (resource) instead of a (string). callExpect serves that purpose:

<?php
$callback 
= new Callback("formatDate""de");
$date $callback->callExpect("string", array($timestamp));

$callback = new Callback(array("Date""fromIsodate"));
$dateObject $callback->callExpectObject("Date", array($timestamp));
?>

Both calls will throw an Exception if the callback does not return what they expect. Given the fact that you may expect that the callbacks will be written by other, maybe less experienced programmers, it is a good idea to actually use callExpect.

By the way: the module which provides for the nifty PHP code samples within this text is a callback given to the text parser.

Dieser Text ist Teil der Serie Paran in Action

paran: Autoloader
paran: Callback
paran: Basic
paran: EPDO

Comments

Please note: comments posted won't be visible immediately, as they will be checked for harmful content.

* Title  
* Nickname  
* Comment