sanmai sanmai - 1 month ago 11
PHP Question

Type hinting when calling arbitrary functions (closures) in PHP


Possible Duplicate:

PHP Reflection - Get Method Parameter Type As String




Silex PHP microframework does a callback injection based on the automatic type hinting. For example, in Silex one can supply a Closure argument with arbitrary arguments like so:

$app->get('/blog/show/{postId}/{commentId}', function ($commentId, $postId) {
//...
});
$app->get('/blog/show/{id}', function (Application $app, Request $request, $id) {
//...
});
// following works just as well - order of arguments is not important
$app->get('/blog/show/{id}', function (Request $request, Application $app, $id) {
//...
});


How do I do this? I'm not interested in getting parameter types as strings. I am looking for a "no strings" fully automatic solution. In other words,


  1. For a number of possible arguments:

    $possible_arguments = [
    new Class_A(),
    new Class_B(),
    new Class_C(),
    new Another_Class,
    $some_class
    ];

  2. For a closure with any number of arbitrary arguments, that can only include those defined above only once:

    $closure = function (Class_B $b, Another_Class, $a) {
    // Do something with $a and $b
    };

  3. I need to get only matching arguments in order to call the closure with them:

    // $arguments is now [$possible_arguments[1], $possible_arguments[3]]
    call_user_func_array($closure, $arguments);


Answer

Indeed they're using Reflection, specifically in the ControllerResolver class.

If you let me to simplify to include only one case of Closure and only object-type arguments:

$availableArguments = array($a, new B(), $c);
$arguments = array();
$reflection = new \ReflectionFunction($callback);  // $callback is a Closure
foreach ($reflection->getParameters() as $param) {
    if ($paramClass = $param->getClass()) {
        foreach ($availableArguments as $proposedArgument) {
            if ($paramClass->isInstance($proposedArgument)) {
                $arguments[] = $proposedArgument;
                break;
            }
        }
    }
}
call_user_func_array($callback, $arguments);
Comments