Skip to content

feat: allows get to resolve services as singletons - #2256

Open
aidan-casey wants to merge 1 commit into
3.xfrom
add-singleton-by-default
Open

feat: allows get to resolve services as singletons#2256
aidan-casey wants to merge 1 commit into
3.xfrom
add-singleton-by-default

Conversation

@aidan-casey

Copy link
Copy Markdown
Member

Based on the conversations with @Crell in the Tempest discord, this PR allows services to be shared by default and adds a secondary make method that always retrieves a new instance of the class.

Note the definition of the make method that PHP-DI has:

The make() method works like get() except it will resolve the entry every time it is called. Depending on the type of the entry this means:

  • if the entry is an object, an new instance will be created every time
  • if the entry is a factory, the factory will be called every time
  • if the entry is an alias, the alias will be resolved every time

Please note that only the entry you ask for will be resolved every time: all the dependencies of the entry will not! That means that if the entry is an alias, the entry the alias points to will be resolved only once.

https://php-di.org/doc/container.html#make

@aidan-casey
aidan-casey requested a review from xHeaven August 19, 2026 00:52
@aidan-casey
aidan-casey requested a review from brendt as a code owner August 19, 2026 00:52
@github-actions

Copy link
Copy Markdown

Benchmark Results

Comparison of add-singleton-by-default against 3.x (7e5cff65349956e14578e826a95d1f3ce6953761).

Open to see the benchmark results
Benchmark Set Mem. Peak Time Variability
ViewRenderBench(benchPlainHtml) - 22.028mb +0.01% 492.388μs -7.75% ±1.34% -56.95%

Generated by phpbench against commit a6a9cfe

@innocenzi innocenzi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but I am not a fan of this:

  • get gets a hidden behavior
  • make does what get used to do
  • get and make aren't clear names, they have minor differences in their behavior, so consumers have to read docs or code dive

I feel like we're unlocking a niche use case while making the container more confusing. I don't have an alternative to suggest, however.

@xHeaven

xHeaven commented Aug 19, 2026

Copy link
Copy Markdown
Member

I've reviewed this PR internally on Discord, but here is the review for clarity:

A couple things:

  1. PR says make() always returns a new instance. This is true... unless you called get() earlier.
$container = new GenericContainer(
    getClassAsSingletonByDefault: true,
);

$get = $container->get(Mailer::class);
make = $container->make(Mailer::class);

var_dump($get === $make); // true
  1. PR says make() always returns a new instance. This could be true... but now you just get a (false) CircularDependencyEncountered exception if you call make() more than once on the same class because the first call leaves the class constructor in the chain, and that's what the second call sees, so it's not a true circular dependency.
  2. Though I'm not sure if this was in the scope, but with the current method, constructor dependencies are still not shared. So $mailer->platform === $platform is a false, even if they are the "same-ish" objects

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.

3 participants