Skip to content

Container::extend() breaks when $abstract was previously contextually bound #53501

@axlon

Description

@axlon

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

  1. 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)
  2. Trigger the contextual binding
  3. 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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions