Skip to content

Conversation

@LeoColomb
Copy link
Contributor

@LeoColomb LeoColomb commented Jan 4, 2022

This reasonably simple change would enable to use variadic for DI when calling a Callable, in addition to class resolution.

Here is an example reusing the objects from the documentation:

$app->bind(Filter::class, function ($app) {
    return [
        $app->make(NullFilter::class),
        $app->make(ProfanityFilter::class),
        $app->make(TooLongFilter::class),
    ];
});

$app->call(function (Logger $logger, Filter ...$filters) {
    //                               ⏫ this is currently unsupported
});

I think this can be beneficial for the following reasons:

  • you may have a callable or a class method that receives an array of typed objects, the same way documentation explains for constructors;
  • there are cases when resolution for constructors only is not sufficient unless over objectifying things.
    • see my example below.
  • this addition partially mitigates the need of contextual binding for methods ([7.x] Allow Contextual Binding outside of constructors #30542):
    • for variadic, the enforced specific context is no more required, they can be use with classical bindings.
    • improve consistency across DI
  • backward compatible, as it only match variadic when a type is specified (maybe array of arrays type can conflit? not even sure it is natively supported)
  • it is not very easy to implement the suggested behavior via a package
Example of a case where a constructor cannot handle it
  • Not allowed:

    public function __construct(public Logger $logger, Filter ...$filters, Whatever ...$objects)
    { //                                                                   ⏫ this is illegal
        $this->filters = $filters;
        $this->objects = $objects;
        $this->method();
    }  
    
    public function method()
    {
        // attributes consumer
    }
  • Naive remedy:

    public function __construct(public Logger $logger, Filter ...$filters)
    {
        $this->filters = $filters;
        App::call([$this, 'method']);
    }
    
    public function method(Whatever ...$objects)
    {
        //
    }

@taylorotwell taylorotwell merged commit 5321e34 into laravel:8.x Jan 5, 2022
@taylorotwell
Copy link
Member

Had to make one small change for backward compatibility with existing code.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants