Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Allow method typed variadics dependencies #40255

Merged
merged 2 commits into from
Jan 5, 2022
Merged

[8.x] Allow method typed variadics dependencies #40255

merged 2 commits into from
Jan 5, 2022

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.

None yet

2 participants