List Info

Thread: 0 for PHP::PHP_Callback




0 for PHP::PHP_Callback
user name
2007-06-05 11:05:06
Greg Beaver (http://pear.php.net/u
ser/cellog) has voted 0 on the proposal for
PHP::PHP_Callback.

Proposal information:
http://pear.php.net/pepr/pepr-proposal-show.php?id=482

Vote information:
http://pear.php.net/pepr/pepr-vote-show.php?
id=482&handle=cellog

Comment:

I have been thinking about this proposal quite a bit and
have finally come
to my own conclusions about it.

Obviously, it will not be accepted as a new package in its
current state,
so the question is only how to reformulate the idea so that
it will be a
useful package.

>From my end, the extensive wrapping around calling the
callback must go. 
There is no good reason to do this:

<?php
require_once 'PHP/Callback.php';
$a = new PHP_Callback(array('hello', 'there'));
$a->addParameter(1);
$a->addParameter(2);
$a->addParameter(3);
$a->execute();
?>

instead of this:

<?php
call_user_func(array('hello', 'there'), 1, 2, 3);
?>

As I said in my offlist email to you, the primary issue I
have experienced
when coding with callbacks is improper validation.  This
means two things:

1) forgetting to do an is_callable() check
2) forgetting to ensure that the callback actually accepts
the arguments I
want it to accept

The primary mechanisms in place for ensuring #2 in PHP 5 are
reflection,
interfaces, and abstract classes.

At a certain point, validating this aspect of a callback can
become quite
complex, i.e.:

<?php
if (!is_callable($callback)) return;
if (is_array($callback)) {
    if (is_string($callback[0])) {
        // callback is array('class', 'method')
        $a = new ReflectionClass($callback[0]);
        if ($a->implementsInterface('someInterface')) {
            // check to see if this callback implements a
            // specific method's signature
            if ($callback[1] != 'someMethod') return;
        } else {
            // more loosely, make sure this callback
            // accepts 3 parameters
            $m = $a->getMethod($callback[1]);
            if ($m->getNumberOfParameters() < 3 ||
$m->getNumberOfRequiredParameters() > 3) return;
        }
    } else {
        // callback is array($object, 'method')
        if ($callback[0] instanceof someInterface) {
            // check to see if this callback implements a
            // specific method's signature
            if ($callback[1] != 'someMethod') return;
        } else {
            // more loosely, make sure this callback
            // accepts 3 parameters
            $a = new ReflectionClass($callback[0]);
            $m = $a->getMethod($callback[1]);
            if ($m->getNumberOfParameters() < 3 ||
$m->getNumberOfRequiredParameters() > 3) return;
        }
    }
    // if we reach here we are certain that this is the
interface we
expect
} else {
    // callback is 'function'
    // make sure this callback function
    // accepts 3 parameters
    $a = new ReflectionFunction($callback);
    if ($a->getNumberOfParameters() < 3 ||
$a->getNumberOfRequiredParameters() > 3) return;
}
?>

*this* is the kind of thing that may be useful to abstract -
a callback
validator that can accept as its arguments:

 - an interface that must be validated (require an array()
callback)
 - the number of parameters that must be accepted

With this kind of functionality, one can then use it inside
a method

<?php
require_once 'PHP/CallbackValidator.php';
...
function whatever($a)
{
    if (!PHP_CallbackValidator::validate($a,
PHP_CallbackValidator::INTERFACE, 'interfaceName',
'method')) {
        throw new Whatever_Exception('what evER');
    }
}
?>

or inside a wrapper PHP_Callback-style object for type
hinting:

<?php
require_once 'PHP/CallbackValidator.php';
class MY_CustomCallback
{
    private $_callback;
    function __construct($callback)
    {
        if (!PHP_CallbackValidator::validate($callback,
PHP_CallbackValidator::ARGS, 3)) {
            throw new MY_Exception('callback must accept 3
arguments');
        }
        $this->_callback = $callback;
    }

    function execute($a, $b, $c)
    {
        call_user_func($this->_callback, $a, $b, $c);
    }
}
?>

This PHP_CallbackValidator package need only be a 1-static
method class,
but it would still be useful and impose a minimal
performance penalty for
the functionality it would provide.  The flexibility of
being able to use
it as a one-off validation inside a method or function or to
create a
customized PHP_Callback that can be used for type-hinting is
far better in
my opinion.  I hope that with these ideas, you can find a
way to glean the
most useful part of your proposal into a package that all
PEAR and all PHP
developers will want to use.

-- 
Sent by PEPr, the automatic proposal system at http://pear.php.net

-- 
PEAR Development Mailing List (http://pear.php.net/)
To unsubscribe, visit: http://www.php.net/unsub
.php


[1]

about | contact  Other archives ( Real Estate discussion Medical topics )