Skip to content

Instantly share code, notes, and snippets.

@hannesvdvreken
Last active August 29, 2015 14:13
Show Gist options
  • Save hannesvdvreken/328d3e85cc920a3d3759 to your computer and use it in GitHub Desktop.
Save hannesvdvreken/328d3e85cc920a3d3759 to your computer and use it in GitHub Desktop.
set_exception_handler($app->wrap(function (\Exception $exception, \Whoops\Run $run) {
$run->handleException($exception);
}));
@hannesvdvreken
Copy link
Author

I was using the Illuminate Container in a non-laravel project and figured it would be useful to wrap callables like this.

Right now the anonymous function returned by App::wrap doesn't accept arguments and when it is called it calls the original function and returns the result.

What I'm trying to archieve here is quite hard to solve because of several reasons:

$app->wrap(function (\Vendor\Class $obj, $arg1, $arg2) {...}, ['argument 1', 'argument 2']);

Will correctly inject argument 1 and 2 from the given array.

It would also be possible to intelligently figure out what to do with this:

$callable = $app->wrap(function (\Vendor\Class $obj, $arg1, $arg2) {...});

$callable('argument 1', 'argument 2');

But this is a more challenging situation.

$callable = $app->wrap(function (\Vendor\Class $obj, $arg1, $arg2) {...}, ['argument x']);

$callable('argument y');

What will be the value of $arg1 and what will be the value of $arg2?

Also it would require people NOT to type hint arguments, because otherwise the $app->call method will try to resolve it from the container.

$callable = $app->wrap(function (\Vendor\Class $obj, \Exception $arg1) {
    // $arg1 will not equal the new \Exception() which is used to call the anonymous function.
});

$callable(new \Exception());

Or the given arguments (func_get_args) must be matched with the type hinted arguments of the wrapped anonymous function first before resolving the rest...

Here's a proposed solution:

public function wrap(Closure $callback, array $parameters = [])
{
    return function() use ($callback, $parameters)
    {
        $parameters = array_merge(func_get_args(), $parameters);
        return $this->call($callback, $parameters);
    };
}

This would give priority to the parameters passed to the new anonymous function returned by the wrap method.

Another solution (with respect to type hints):

public function wrap(Closure $callback, array $parameters = [])
{
    return function() use ($callback, $parameters)
    {
        $arguments = func_get_args();

        $parameters = $this->mergeArguments($callback, $arguments, $parameters);

        return $this->call($callback, $parameters);
    };
}

public function mergeArguments($callback, array $arguments, array $parameters)
{
    foreach ($arguments as $arg)
    {
        $reflector = new \ReflectionClass($arg);
        // Do some reflection on the method. 
    }
}

Maybe enforce a specific order: func_get_args arguments first, then arguments resolvable from the container, then the $parameters array arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment