-
Notifications
You must be signed in to change notification settings - Fork 11.5k
Closed
Closed
Copy link
Description
Laravel Version
11.31.0
PHP Version
8.3.10
Database Driver & Version
n/a
Description
Its possible to use Container::extend()
to extend the behavior of a container service, this makes it easy to compose behavior based on specific needs. However when using this feature together with contextual bindings it may fail depending on a few factors (detailed below).
Steps To Reproduce
- Register a contextual binding in the container, this binding must resolve something that the container can't build on its own (e.g. an interface)
- Trigger the contextual binding
- Register an extension for the
$abstract
(e.g. the interface) that we bound contextually in the prior step
If you followed steps 1, 2, and 3 an exception will be thrown, as whatever interface you picked cannot be resolved. If you skip step 2, everything works as expected.
Below is some example code that contains both scenarios:
<?php
namespace LaravelContainerBugExample;
use Illuminate\Container\Container;
require_once __DIR__ . '/vendor/autoload.php';
interface Foo
{
}
class Bar implements Foo
{
}
class Baz
{
public function __construct(
public Foo $foo,
) {
}
}
class Qux implements Foo
{
public function __construct(
private Foo $foo,
) {
}
}
$container = new Container();
$container->when(Baz::class)->needs(Foo::class)->give(fn () => new Bar());
// This works...
$app = clone $container;
$app->extend(Foo::class, fn (Foo $foo) => new Qux($foo));
$baz = $app->make(Baz::class);
echo $baz->foo instanceof Qux ? 'Foo implementation was extended' : 'Foo implementation was not extended';
echo PHP_EOL;
// This breaks...
$app = clone $container;
$app->make(Baz::class);
$app->extend(Foo::class, fn (Foo $foo) => new Qux($foo));
Metadata
Metadata
Assignees
Labels
No labels