Skip to content

(feat) Container: using() for temporary, self-restoring overrides - #348

Open
techmahedy wants to merge 1 commit into
doppar:4.xfrom
techmahedy:container
Open

techmahedy wants to merge 1 commit into
doppar:4.xfrom
techmahedy:container

Conversation

@techmahedy

Copy link
Copy Markdown
Member

Pull Request Checklist

Q A
Branch? 4.x
Bug fix? no
New feature? yes
Deprecations? no
Issues -
License MIT

Description

Container: using() for temporary, self-restoring overrides

Summary

Adds Container::using(array $overrides, callable $callback). It replaces one or more bindings only while the callback runs, then puts every one of them back exactly as it was, even if the callback throws.

$result = $this->app->using([
    Mailer::class => new FakeMailer(),
], function () {
    return app(Mailer::class)->send($message); // gets the FakeMailer
});

// Mailer is the real implementation again here

Why

instance() and bind() replace a binding permanently. Anything that needs a short-lived override has to save the old binding and restore it by hand, and forgetting (or an exception skipping the restore) leaks the override. That matters most in long-running processes such as queue workers, where the leak carries into the next job or request, and in tests, where it carries into the next test.

Behaviour

Each override is applied the way the container already reads a binding:

Value Behaviour
Closure Factory, called once and shared for the whole callback
Class name Built by the container on first resolution
Anything else Used as is (object, string, array, number)
  • The callback receives the container, and its return value is returned from using().
  • Several bindings can be overridden in one call; calls can be nested.
  • On exit (normal or exception) each key is restored to its previous binding and its previously resolved instance, so a singleton resolved before the call is the same object afterwards. A key that did not exist before is removed.
  • To override a key with a Closure itself, return it from a factory: fn() => $closure.

Limitation

Services that were already resolved and hold a dependency keep that dependency. Only things resolved inside the callback see the override. This is documented on the method and in the docs.

Compatibility

Purely additive: one new public method on Phaseolies\DI\Container. No existing method, signature or behaviour changed.

Files

  • src/Phaseolies/DI/Container.php: new using() method.
  • tests/Application/ContainerTest.php: 7 new tests.

Testing

New tests cover: override then restore, a key that did not exist before is removed (bindings and instances), restore when the callback throws, a Closure factory is called once per scope, a class-name override is built, the same singleton instance is returned after the scope, and nested scopes.

Checklist

  • Tests have been added or updated
  • Documentation has been updated
  • Code follows the project coding standards
  • All tests pass locally

@techmahedy
techmahedy requested a review from rrr63 October 2, 2026 17:03
@techmahedy techmahedy added the feat new feature label Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant