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
|