<?php
class Invoker
{
public static function invoke(callable $callable, &$p1 = null, &$p2 = null)
{
// Strings are usually free function names, but they can also
// specify a static method with ClassName::methodName --
// if that's the case, convert to array form
$callable = explode('::', $callable); }
// Get a ReflectionFunctionAbstract instance that will give us
// information about the invocation target's parameters
// Now we know it refers to a free function
$reflector = new ReflectionFunction($callable);
}
list ($class, $method) = $callable; $reflector = new ReflectionMethod($class, $method);
}
else {
// must be an object -- either a closure or a functor
$reflector = new ReflectionObject($callable);
$reflector = $reflector->getMethod('__invoke');
}
$forwardedArguments = [];
$paramIndex = 0;
foreach($reflector->getParameters() as $param) {
if ($paramIndex >= $incomingArgumentCount) {
if (!$param->isOptional()) {
// invocation target requires parameter that was not passed,
// perhaps we want to handle the error right now?
}
break; // call target will less parameters than it can accept
}
$forwardedArguments[] = &${'p'.(++$paramIndex)};
}
}
}
// free function
function test(&$x, $y) { $x = 'foo'; $y = 'bar'; }
// method
class dummy {
public static function test(&$x, $y) { $x = 'foo'; $y = 'bar'; }
}
// functor
class test {
public function __invoke(&$x, $y) { $x = 'foo'; $y = 'bar'; }
}
// closure
$closure = function(&$x, $y) { $x = 'foo'; $y = 'bar'; };
$x = 'x'; $y = 'y';
Invoker::invoke('test', $x, $y);
echo "After invoking: \$x = $x, \$y = $y\n";
$x = 'x'; $y = 'y';
Invoker::invoke(['dummy', 'test'], $x, $y);
echo "After invoking: \$x = $x, \$y = $y\n";
$x = 'x'; $y = 'y';
Invoker::invoke(new test(), $x, $y);
echo "After invoking: \$x = $x, \$y = $y\n";
$x = 'x'; $y = 'y';
Invoker::invoke($closure, $x, $y);
echo "After invoking: \$x = $x, \$y = $y\n";
PD9waHAKCmNsYXNzIEludm9rZXIKewogICAgcHVibGljIHN0YXRpYyBmdW5jdGlvbiBpbnZva2UoY2FsbGFibGUgJGNhbGxhYmxlLCAmJHAxID0gbnVsbCwgJiRwMiA9IG51bGwpCiAgICB7CiAgICAgICAgaWYgKGlzX3N0cmluZygkY2FsbGFibGUpICYmIHN0cnBvcygkY2FsbGFibGUsICc6OicpKSB7CiAgICAgICAgICAgIC8vIFN0cmluZ3MgYXJlIHVzdWFsbHkgZnJlZSBmdW5jdGlvbiBuYW1lcywgYnV0IHRoZXkgY2FuIGFsc28KICAgICAgICAgICAgLy8gc3BlY2lmeSBhIHN0YXRpYyBtZXRob2Qgd2l0aCBDbGFzc05hbWU6Om1ldGhvZE5hbWUgLS0KICAgICAgICAgICAgLy8gaWYgdGhhdCdzIHRoZSBjYXNlLCBjb252ZXJ0IHRvIGFycmF5IGZvcm0KICAgICAgICAgICAgJGNhbGxhYmxlID0gZXhwbG9kZSgnOjonLCAkY2FsbGFibGUpOwogICAgICAgIH0KIAogICAgICAgIC8vIEdldCBhIFJlZmxlY3Rpb25GdW5jdGlvbkFic3RyYWN0IGluc3RhbmNlIHRoYXQgd2lsbCBnaXZlIHVzCiAgICAgICAgLy8gaW5mb3JtYXRpb24gYWJvdXQgdGhlIGludm9jYXRpb24gdGFyZ2V0J3MgcGFyYW1ldGVycwogICAgICAgIGlmIChpc19zdHJpbmcoJGNhbGxhYmxlKSkgewogICAgICAgICAgICAvLyBOb3cgd2Uga25vdyBpdCByZWZlcnMgdG8gYSBmcmVlIGZ1bmN0aW9uCiAgICAgICAgICAgICRyZWZsZWN0b3IgPSBuZXcgUmVmbGVjdGlvbkZ1bmN0aW9uKCRjYWxsYWJsZSk7CiAgICAgICAgfQogICAgICAgIGVsc2UgaWYgKGlzX2FycmF5KCRjYWxsYWJsZSkpIHsKICAgICAgICAgICAgbGlzdCAoJGNsYXNzLCAkbWV0aG9kKSA9ICRjYWxsYWJsZTsKICAgICAgICAgICAgJHJlZmxlY3RvciA9IG5ldyBSZWZsZWN0aW9uTWV0aG9kKCRjbGFzcywgJG1ldGhvZCk7CiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgICAvLyBtdXN0IGJlIGFuIG9iamVjdCAtLSBlaXRoZXIgYSBjbG9zdXJlIG9yIGEgZnVuY3RvcgogICAgICAgICAgICAkcmVmbGVjdG9yID0gbmV3IFJlZmxlY3Rpb25PYmplY3QoJGNhbGxhYmxlKTsKICAgICAgICAgICAgJHJlZmxlY3RvciA9ICRyZWZsZWN0b3ItPmdldE1ldGhvZCgnX19pbnZva2UnKTsKICAgICAgICB9CgogICAgICAgICRmb3J3YXJkZWRBcmd1bWVudHMgPSBbXTsKICAgICAgICAkaW5jb21pbmdBcmd1bWVudENvdW50ID0gZnVuY19udW1fYXJncygpIC0gMTsKICAgICAgICAkcGFyYW1JbmRleCA9IDA7CiAKICAgICAgICBmb3JlYWNoKCRyZWZsZWN0b3ItPmdldFBhcmFtZXRlcnMoKSBhcyAkcGFyYW0pIHsKICAgICAgICAgICAgaWYgKCRwYXJhbUluZGV4ID49ICRpbmNvbWluZ0FyZ3VtZW50Q291bnQpIHsKICAgICAgICAgICAgICAgIGlmICghJHBhcmFtLT5pc09wdGlvbmFsKCkpIHsKICAgICAgICAgICAgICAgICAgICAvLyBpbnZvY2F0aW9uIHRhcmdldCByZXF1aXJlcyBwYXJhbWV0ZXIgdGhhdCB3YXMgbm90IHBhc3NlZCwKICAgICAgICAgICAgICAgICAgICAvLyBwZXJoYXBzIHdlIHdhbnQgdG8gaGFuZGxlIHRoZSBlcnJvciByaWdodCBub3c/CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGJyZWFrOyAvLyBjYWxsIHRhcmdldCB3aWxsIGxlc3MgcGFyYW1ldGVycyB0aGFuIGl0IGNhbiBhY2NlcHQKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgJGZvcndhcmRlZEFyZ3VtZW50c1tdID0gJiR7J3AnLigrKyRwYXJhbUluZGV4KX07CiAgICAgICAgfQogICAgICAgIAogICAgICAgIHJldHVybiBjYWxsX3VzZXJfZnVuY19hcnJheSgkY2FsbGFibGUsICRmb3J3YXJkZWRBcmd1bWVudHMpOwogICAgfQp9CgovLyBmcmVlIGZ1bmN0aW9uCmZ1bmN0aW9uIHRlc3QoJiR4LCAkeSkgeyAkeCA9ICdmb28nOyAkeSA9ICdiYXInOyB9CgovLyBtZXRob2QKY2xhc3MgZHVtbXkgewogICAgcHVibGljIHN0YXRpYyBmdW5jdGlvbiB0ZXN0KCYkeCwgJHkpIHsgJHggPSAnZm9vJzsgJHkgPSAnYmFyJzsgfQp9CgovLyBmdW5jdG9yCmNsYXNzIHRlc3QgewogICAgcHVibGljIGZ1bmN0aW9uIF9faW52b2tlKCYkeCwgJHkpIHsgJHggPSAnZm9vJzsgJHkgPSAnYmFyJzsgfQp9CgovLyBjbG9zdXJlCiRjbG9zdXJlID0gZnVuY3Rpb24oJiR4LCAkeSkgeyAkeCA9ICdmb28nOyAkeSA9ICdiYXInOyB9OwoKJHggPSAneCc7ICR5ID0gJ3knOwpJbnZva2VyOjppbnZva2UoJ3Rlc3QnLCAkeCwgJHkpOwplY2hvICJBZnRlciBpbnZva2luZzogXCR4ID0gJHgsIFwkeSA9ICR5XG4iOwoKJHggPSAneCc7ICR5ID0gJ3knOwpJbnZva2VyOjppbnZva2UoWydkdW1teScsICd0ZXN0J10sICR4LCAkeSk7CmVjaG8gIkFmdGVyIGludm9raW5nOiBcJHggPSAkeCwgXCR5ID0gJHlcbiI7CgokeCA9ICd4JzsgJHkgPSAneSc7Ckludm9rZXI6Omludm9rZShuZXcgdGVzdCgpLCAkeCwgJHkpOwplY2hvICJBZnRlciBpbnZva2luZzogXCR4ID0gJHgsIFwkeSA9ICR5XG4iOwoKJHggPSAneCc7ICR5ID0gJ3knOwpJbnZva2VyOjppbnZva2UoJGNsb3N1cmUsICR4LCAkeSk7CmVjaG8gIkFmdGVyIGludm9raW5nOiBcJHggPSAkeCwgXCR5ID0gJHlcbiI7Cg==