michiruf
michiruf

Reputation: 423

How to unset scoped instances from the DI Container in laravel

EDIT1: I am trying to bind a singleton instance to the container, that has specified args and sometimes other dependencies (from the container) and I want to be able to get this instance via class name and also unset all instances that where constructed this way when I need to (which is typicall when I want to lose their state and initialize them with new arguments).

I've currently been struggling on unsetting a scoped instance from laravels DI container. To reproduce and unserstand, please see the following test:

it('should be able to remove scoped instances', function () {
    class TestClass
    {
        public function __construct(
            public int $count,
        ) {
        }
    }

    function testResolveClass($class, array $args = []): object
    {
        if (! app()->bound($class)) {
            $instance = app($class, $args);
            app()->scoped($class, fn (Application $app) => $instance);
        }

        return app($class);
    }

    // Create first instance
    $instance = testResolveClass(TestClass::class, ['count' => 123]);
    $id = spl_object_id($instance);

    // Unset instances
    unset($instance);
    app()->forgetScopedInstances(); // TODO Why doesnt this unset the instance?

    // unset(app()[TestClass::class]); // would work because it also unsets the variables 'binding' and 'resolved', but cannot be done in my case

    // Create another instance (at least we try to...)
    $instance = testResolveClass(TestClass::class, ['count' => 456]);
    $id2 = spl_object_id($instance);

    // Expect the object id is not the same and the count changed
    expect()
        ->and($id2)->not->toBe($id) // fails because id is the same
        ->and($instance->count)->toBe(456); // would fail because count is 123
});

Is my approach wrong, am I missing something or would you expect this behaviour aswell?

If I could check if the instance was forgotten, I could at least rebind the instance manually, but I cannot seem to find any check if a scoped instance is really bound or was unbound after calling app()->forgetScopedInstances();.

Many thanks, michiruf

Upvotes: 0

Views: 50

Answers (1)

Flame
Flame

Reputation: 7618

Your test code is invalid. In your test you use:

$instance = app($class, $args);
app()->scoped($class, fn (Application $app) => $instance);

It seems wrong to me to retrieve the instance from the container in the first line and then return it as part of a scoped instance in the second one.

When you change your code to the following, it will likely work as expected:

// No $instance variable here used.
app()->scoped($class, fn (\Illuminate\Foundation\Application $app) => new $class(...$args));

Upvotes: 0

Related Questions