-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DI] Inline trivial private servives #23674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -446,6 +446,50 @@ private function isSimpleInstance($id, Definition $definition) | |
return true; | ||
} | ||
|
||
/** | ||
* Checks if the definition is a trivial instance. | ||
* | ||
* @param Definition $definition | ||
* | ||
* @return bool | ||
*/ | ||
private function isTrivialInstance(Definition $definition) | ||
{ | ||
if ($definition->isPublic() || $definition->getMethodCalls() || $definition->getProperties() || $definition->getConfigurator()) { | ||
return false; | ||
} | ||
if ($definition->isDeprecated() || $definition->isLazy() || $definition->getFactory() || 3 < count($definition->getArguments())) { | ||
return false; | ||
} | ||
|
||
foreach ($definition->getArguments() as $arg) { | ||
if (!$arg || ($arg instanceof Reference && 'service_container' !== (string) $arg)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why the special case about referencing the container ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because this considers |
||
continue; | ||
} | ||
if (is_array($arg) && 3 >= count($arg)) { | ||
foreach ($arg as $k => $v) { | ||
if ($this->dumpValue($k) !== $this->dumpValue($k, false)) { | ||
return false; | ||
} | ||
if (!$v || ($v instanceof Reference && 'service_container' !== (string) $v)) { | ||
continue; | ||
} | ||
if (!is_scalar($v) || $this->dumpValue($v) !== $this->dumpValue($v, false)) { | ||
return false; | ||
} | ||
} | ||
} elseif (!is_scalar($arg) || $this->dumpValue($arg) !== $this->dumpValue($arg, false)) { | ||
return false; | ||
} | ||
} | ||
|
||
if (false !== strpos($this->dumpLiteralClass($this->dumpValue($definition->getClass())), '$')) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Adds method calls to a service definition. | ||
* | ||
|
@@ -675,7 +719,7 @@ private function addServices() | |
foreach ($definitions as $id => $definition) { | ||
if ($definition->isPublic()) { | ||
$publicServices .= $this->addService($id, $definition); | ||
} else { | ||
} elseif (!$this->isTrivialInstance($definition)) { | ||
$privateServices .= $this->addService($id, $definition); | ||
} | ||
} | ||
|
@@ -1504,10 +1548,18 @@ private function getServiceCall($id, Reference $reference = null) | |
} | ||
|
||
if ($this->container->hasDefinition($id)) { | ||
$code = sprintf('$this->%s()', $this->generateMethodName($id)); | ||
$definition = $this->container->getDefinition($id); | ||
|
||
if ($this->container->getDefinition($id)->isShared()) { | ||
$code = sprintf('($this->%s[\'%s\'] ?? %s)', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $id, $code); | ||
if ($definition->isPublic() || !$this->isTrivialInstance($definition)) { | ||
$code = sprintf('$this->%s()', $this->generateMethodName($id)); | ||
} else { | ||
$code = substr($this->addNewInstance($definition, '', '', $id), 8, -2); | ||
if ($definition->isShared()) { | ||
$code = sprintf('($this->privates[\'%s\'] = %s)', $id, $code); | ||
} | ||
} | ||
if ($definition->isShared()) { | ||
$code = sprintf('($this->%s[\'%s\'] ?? %s)', $definition->isPublic() ? 'services' : 'privates', $id, $code); | ||
} | ||
} elseif (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) { | ||
$code = sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,6 +125,7 @@ | |
$container | ||
->register('factory_simple', 'SimpleFactoryClass') | ||
->addArgument('foo') | ||
->setDeprecated(true) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added this to have at least one private service that cannot be inlined. |
||
->setPublic(false) | ||
; | ||
$container | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this method name (
isTrivialInstance()
) which feels like an internal detail, maybe we could use a more generic and future-proof name, such ascanBeInlined()
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, as a private method, this is an internal detail :)
more importantly, the "trivial" is important here. It's not only that the instantiation can be inlined, it's also that the instantiation is trivial, this meaning that it mostly a simple
new Foo()
.More complex instantiation would also be inlineable (eg
Factory::create(new Foo($this->get('bar')))
), but we don't want to inline those (we need a limit, being trivial is the one, for what it means (it only means whatever logic is in the method, see patch :) .)In this respect,
canBeInlined()
would be confusing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. My reasoning was that in the future, if you add new optimizations, the code will complicate a lot (
if ($this->isTrivialInstance() || $this->isServiceLengthSmall() || $this->isDevEnvironment())
vsif ($this->canBeInlined())
and then adding more optimizations to that method).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, if in the future we decide that more cases would benefit from this, we could still change the defining of what a trivial service is. And we can decide to rename the method if actually necessary.
canBeInlined
has another reason to be confusing: we have another concept calledinlining
in the component (although a bit related)