N°8834 - Add compatibility with PHP 8.4 (#819)

* N°8834 - Add compatibility with PHP 8.4

* Rollback of scssphp/scssphp version upgrade due to compilation error
This commit is contained in:
Lenaick
2026-02-26 10:36:32 +01:00
committed by GitHub
parent d4821b7edc
commit fc967c06ce
961 changed files with 12298 additions and 7130 deletions

View File

@@ -185,7 +185,7 @@ class PhpDumper extends Dumper
$this->class = $options['class'];
if (!str_starts_with($baseClass = $options['base_class'], '\\') && 'Container' !== $baseClass) {
$baseClass = sprintf('%s\%s', $options['namespace'] ? '\\'.$options['namespace'] : '', $baseClass);
$baseClass = \sprintf('%s\%s', $options['namespace'] ? '\\'.$options['namespace'] : '', $baseClass);
$this->baseClass = $baseClass;
} elseif ('Container' === $baseClass) {
$this->baseClass = Container::class;
@@ -217,7 +217,7 @@ class PhpDumper extends Dumper
$this->targetDirMaxMatches = $i - $lastOptionalDir;
while (--$i >= $lastOptionalDir) {
$regex = sprintf('(%s%s)?', preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
$regex = \sprintf('(%s%s)?', preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
}
do {
@@ -287,7 +287,7 @@ EOF;
if (!$this->inlineFactories) {
foreach ($this->generateServiceFiles($services) as $file => [$c, $preload]) {
$files[$file] = sprintf($fileTemplate, substr($file, 0, -4), $c);
$files[$file] = \sprintf($fileTemplate, substr($file, 0, -4), $c);
if ($preload) {
$preloadedFiles[$file] = $file;
@@ -353,11 +353,11 @@ $preloadedFiles
EOF;
foreach ($this->preload as $class) {
if (!$class || str_contains($class, '$') || \in_array($class, ['int', 'float', 'string', 'bool', 'resource', 'object', 'array', 'null', 'callable', 'iterable', 'mixed', 'void'], true)) {
if (!$class || str_contains($class, '$') || \in_array($class, ['int', 'float', 'string', 'bool', 'resource', 'object', 'array', 'null', 'callable', 'iterable', 'mixed', 'void', 'never'], true)) {
continue;
}
if (!(class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false)) || (new \ReflectionClass($class))->isUserDefined()) {
$code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class);
$code[$options['class'].'.preload.php'] .= \sprintf("\$classes[] = '%s';\n", $class);
}
}
@@ -458,7 +458,7 @@ EOF;
foreach ($edges as $edge) {
$node = $edge->getDestNode();
$id = $node->getId();
if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isWeak()) {
if (($sourceId === $id && !$edge->isLazy()) || !$node->getValue() instanceof Definition || $edge->isWeak()) {
continue;
}
@@ -542,7 +542,7 @@ EOF;
return;
}
$file = $r->getFileName();
if (str_ends_with($file, ') : eval()\'d code')) {
if ($file && str_ends_with($file, ') : eval()\'d code')) {
$file = substr($file, 0, strrpos($file, '(', -17));
}
if (!$file || $this->doExport($file) === $exportedFile = $this->export($file)) {
@@ -589,12 +589,13 @@ EOF;
continue;
}
do {
$file = $r->getFileName();
if (str_ends_with($file, ') : eval()\'d code')) {
$file = substr($file, 0, strrpos($file, '(', -17));
}
if (is_file($file)) {
$this->container->addResource(new FileResource($file));
if ($file = $r->getFileName()) {
if (str_ends_with($file, ') : eval()\'d code')) {
$file = substr($file, 0, strrpos($file, '(', -17));
}
if (is_file($file)) {
$this->container->addResource(new FileResource($file));
}
}
$r = $r->getParentClass() ?: null;
} while ($r?->isUserDefined());
@@ -613,7 +614,7 @@ EOF;
if ($this->inlineFactories) {
$this->inlinedRequires[$file] = true;
}
$code .= sprintf("include_once %s;\n", $file);
$code .= \sprintf("include_once %s;\n", $file);
}
$proxyCode = $code.$proxyCode;
@@ -624,7 +625,9 @@ EOF;
$proxyCode = substr(self::stripComments($proxyCode), 5);
}
$proxyClass = explode(' ', $this->inlineRequires ? substr($proxyCode, \strlen($code)) : $proxyCode, 3)[1];
$proxyClass = $this->inlineRequires ? substr($proxyCode, \strlen($code)) : $proxyCode;
$i = strpos($proxyClass, 'class');
$proxyClass = substr($proxyClass, 6 + $i, strpos($proxyClass, ' ', 7 + $i) - $i - 6);
if ($this->asFiles || $this->namespace) {
$proxyCode .= "\nif (!\\class_exists('$proxyClass', false)) {\n \\class_alias(__NAMESPACE__.'\\\\$proxyClass', '$proxyClass', false);\n}\n";
@@ -663,7 +666,7 @@ EOF;
}
foreach (array_diff_key(array_flip($lineage), $this->inlinedRequires) as $file => $class) {
$code .= sprintf(" include_once %s;\n", $file);
$code .= \sprintf(" include_once %s;\n", $file);
}
}
@@ -671,7 +674,7 @@ EOF;
if ($file = $def->getFile()) {
$file = $this->dumpValue($file);
$file = '(' === $file[0] ? substr($file, 1, -1) : $file;
$code .= sprintf(" include_once %s;\n", $file);
$code .= \sprintf(" include_once %s;\n", $file);
}
}
@@ -691,12 +694,11 @@ EOF;
$class = $this->dumpValue($definition->getClass());
if (str_starts_with($class, "'") && !str_contains($class, '$') && !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
throw new InvalidArgumentException(\sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
}
$asGhostObject = false;
$isProxyCandidate = $this->isProxyCandidate($definition, $asGhostObject, $id);
$instantiation = '';
$lastWitherIndex = null;
foreach ($definition->getMethodCalls() as $k => $call) {
@@ -705,20 +707,26 @@ EOF;
}
}
if (!$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id]) && null === $lastWitherIndex) {
$instantiation = sprintf('$container->%s[%s] = %s', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $this->doExport($id), $isSimpleInstance ? '' : '$instance');
} elseif (!$isSimpleInstance) {
$instantiation = '$instance';
$shouldShareInline = !$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id]) && null === $lastWitherIndex;
$serviceAccessor = \sprintf('$container->%s[%s]', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $this->doExport($id));
$return = match (true) {
$shouldShareInline && !isset($this->circularReferences[$id]) && $isSimpleInstance => 'return '.$serviceAccessor.' = ',
$shouldShareInline && !isset($this->circularReferences[$id]) => $serviceAccessor.' = $instance = ',
$shouldShareInline || !$isSimpleInstance => '$instance = ',
default => 'return ',
};
$code = $this->addNewInstance($definition, ' '.$return, $id, $asGhostObject);
if ($shouldShareInline && isset($this->circularReferences[$id])) {
$code .= \sprintf(
"\n if (isset(%s)) {\n return %1\$s;\n }\n\n %s%1\$s = \$instance;\n",
$serviceAccessor,
$isSimpleInstance ? 'return ' : ''
);
}
$return = '';
if ($isSimpleInstance) {
$return = 'return ';
} else {
$instantiation .= ' = ';
}
return $this->addNewInstance($definition, ' '.$return.$instantiation, $id, $asGhostObject);
return $code;
}
private function isTrivialInstance(Definition $definition): bool
@@ -782,12 +790,12 @@ EOF;
if ($call[2] ?? false) {
if (null !== $sharedNonLazyId && $lastWitherIndex === $k && 'instance' === $variableName) {
$witherAssignation = sprintf('$container->%s[\'%s\'] = ', $definition->isPublic() ? 'services' : 'privates', $sharedNonLazyId);
$witherAssignation = \sprintf('$container->%s[\'%s\'] = ', $definition->isPublic() ? 'services' : 'privates', $sharedNonLazyId);
}
$witherAssignation .= sprintf('$%s = ', $variableName);
$witherAssignation .= \sprintf('$%s = ', $variableName);
}
$calls .= $this->wrapServiceConditionals($call[1], sprintf(" %s\$%s->%s(%s);\n", $witherAssignation, $variableName, $call[0], implode(', ', $arguments)));
$calls .= $this->wrapServiceConditionals($call[1], \sprintf(" %s\$%s->%s(%s);\n", $witherAssignation, $variableName, $call[0], implode(', ', $arguments)));
}
return $calls;
@@ -797,7 +805,7 @@ EOF;
{
$code = '';
foreach ($definition->getProperties() as $name => $value) {
$code .= sprintf(" \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
$code .= \sprintf(" \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
}
return $code;
@@ -811,25 +819,25 @@ EOF;
if (\is_array($callable)) {
if ($callable[0] instanceof Reference
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))
|| ($callable[0] instanceof Definition && $this->definitionVariables->offsetExists($callable[0]))
) {
return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
return \sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
$class = $this->dumpValue($callable[0]);
// If the class is a string we can optimize away
if (str_starts_with($class, "'") && !str_contains($class, '$')) {
return sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName);
return \sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName);
}
if (str_starts_with($class, 'new ')) {
return sprintf(" (%s)->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
return \sprintf(" (%s)->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
return sprintf(" [%s, '%s'](\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
return \sprintf(" [%s, '%s'](\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
return sprintf(" %s(\$%s);\n", $callable, $variableName);
return \sprintf(" %s(\$%s);\n", $callable, $variableName);
}
private function addService(string $id, Definition $definition): array
@@ -843,15 +851,14 @@ EOF;
if ($class = $definition->getClass()) {
$class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class);
$return[] = sprintf(str_starts_with($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\'));
} elseif ($definition->getFactory()) {
$factory = $definition->getFactory();
$return[] = \sprintf(str_starts_with($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\'));
} elseif ($factory = $definition->getFactory()) {
if (\is_string($factory) && !str_starts_with($factory, '@=')) {
$return[] = sprintf('@return object An instance returned by %s()', $factory);
$return[] = \sprintf('@return object An instance returned by %s()', $factory);
} elseif (\is_array($factory) && (\is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
$class = $factory[0] instanceof Definition ? $factory[0]->getClass() : (string) $factory[0];
$class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class);
$return[] = sprintf('@return object An instance returned by %s::%s()', $class, $factory[1]);
$return[] = \sprintf('@return object An instance returned by %s::%s()', $class, $factory[1]);
}
}
@@ -861,7 +868,7 @@ EOF;
}
$deprecation = $definition->getDeprecation($id);
$return[] = sprintf('@deprecated %s', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']);
$return[] = \sprintf('@deprecated %s', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']);
}
$return = str_replace("\n * \n", "\n *\n", implode("\n * ", $return));
@@ -902,14 +909,14 @@ EOF;
}
if ($definition->hasErrors() && $e = $definition->getErrors()) {
$code .= sprintf(" throw new RuntimeException(%s);\n", $this->export(reset($e)));
$code .= \sprintf(" throw new RuntimeException(%s);\n", $this->export(reset($e)));
} else {
$this->serviceCalls = [];
$this->inlinedDefinitions = $this->getDefinitionsFromArguments([$definition], null, $this->serviceCalls);
if ($definition->isDeprecated()) {
$deprecation = $definition->getDeprecation($id);
$code .= sprintf(" trigger_deprecation(%s, %s, %s);\n\n", $this->export($deprecation['package']), $this->export($deprecation['version']), $this->export($deprecation['message']));
$code .= \sprintf(" trigger_deprecation(%s, %s, %s);\n\n", $this->export($deprecation['package']), $this->export($deprecation['version']), $this->export($deprecation['message']));
} elseif ($definition->hasTag($this->hotPathTag) || !$definition->hasTag($this->preloadTags[1])) {
foreach ($this->inlinedDefinitions as $def) {
foreach ($this->getClasses($def, $id) as $class) {
@@ -919,7 +926,7 @@ EOF;
}
if (!$definition->isShared()) {
$factory = sprintf('$container->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id));
$factory = \sprintf('$container->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id));
}
$asGhostObject = false;
@@ -927,17 +934,17 @@ EOF;
$definition = $isProxyCandidate;
if (!$definition->isShared()) {
$code .= sprintf(' %s ??= ', $factory);
$code .= \sprintf(' %s ??= ', $factory);
if ($definition->isPublic()) {
$code .= sprintf("fn () => self::%s(\$container);\n\n", $asFile ? 'do' : $methodName);
$code .= \sprintf("fn () => self::%s(\$container);\n\n", $asFile ? 'do' : $methodName);
} else {
$code .= sprintf("self::%s(...);\n\n", $asFile ? 'do' : $methodName);
$code .= \sprintf("self::%s(...);\n\n", $asFile ? 'do' : $methodName);
}
}
$lazyLoad = $asGhostObject ? '$proxy' : 'false';
$factoryCode = $asFile ? sprintf('self::do($container, %s)', $lazyLoad) : sprintf('self::%s($container, %s)', $methodName, $lazyLoad);
$factoryCode = $asFile ? \sprintf('self::do($container, %s)', $lazyLoad) : \sprintf('self::%s($container, %s)', $methodName, $lazyLoad);
$code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, $factoryCode);
}
@@ -960,7 +967,7 @@ EOF;
$c = implode("\n", array_map(fn ($line) => $line ? ' '.$line : $line, explode("\n", $c)));
$lazyloadInitialization = $definition->isLazy() ? ', $lazyLoad = true' : '';
$c = sprintf(" %s = function (\$container%s) {\n%s };\n\n return %1\$s(\$container);\n", $factory, $lazyloadInitialization, $c);
$c = \sprintf(" %s = function (\$container%s) {\n%s };\n\n return %1\$s(\$container);\n", $factory, $lazyloadInitialization, $c);
}
$code .= $c;
@@ -1027,13 +1034,13 @@ EOF;
$this->referenceVariables[$targetId] = new Variable($name);
$reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $behavior ? new Reference($targetId, $behavior) : null;
$code .= sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference));
$code .= \sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference));
if (!$hasSelfRef || !$forConstructor) {
return $code;
}
$code .= sprintf(<<<'EOTXT'
$code .= \sprintf(<<<'EOTXT'
if (isset($container->%s[%s])) {
return $container->%1$s[%2$s];
@@ -1048,12 +1055,12 @@ EOTXT
return $code;
}
private function addInlineService(string $id, Definition $definition, Definition $inlineDef = null, bool $forConstructor = true): string
private function addInlineService(string $id, Definition $definition, ?Definition $inlineDef = null, bool $forConstructor = true): string
{
$code = '';
if ($isSimpleInstance = $isRootInstance = null === $inlineDef) {
foreach ($this->serviceCalls as $targetId => [$callCount, $behavior, $byConstructor]) {
foreach ($this->serviceCalls as $targetId => [, , $byConstructor]) {
if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId] && !($this->hasProxyDumper && $definition->isLazy())) {
$code .= $this->addInlineReference($id, $definition, $targetId, $forConstructor);
}
@@ -1108,7 +1115,7 @@ EOTXT
return $code."\n return \$instance;\n";
}
private function addServices(array &$services = null): string
private function addServices(?array &$services = null): string
{
$publicServices = $privateServices = '';
$definitions = $this->container->getDefinitions();
@@ -1150,7 +1157,7 @@ EOTXT
}
}
private function addNewInstance(Definition $definition, string $return = '', string $id = null, bool $asGhostObject = false): string
private function addNewInstance(Definition $definition, string $return = '', ?string $id = null, bool $asGhostObject = false): string
{
$tail = $return ? str_repeat(')', substr_count($return, '(') - substr_count($return, ')')).";\n" : '';
@@ -1168,9 +1175,7 @@ EOTXT
$arguments[] = (\is_string($i) ? $i.': ' : '').$this->dumpValue($value);
}
if (null !== $definition->getFactory()) {
$callable = $definition->getFactory();
if ($callable = $definition->getFactory()) {
if ('current' === $callable && [0] === array_keys($definition->getArguments()) && \is_array($value) && [0] === array_keys($value)) {
return $return.$this->dumpValue($value[0]).$tail;
}
@@ -1189,50 +1194,51 @@ EOTXT
}
if (\is_string($callable) && str_starts_with($callable, '@=')) {
return $return.sprintf('(($args = %s) ? (%s) : null)',
return $return.\sprintf('(($args = %s) ? (%s) : null)',
$this->dumpValue(new ServiceLocatorArgument($definition->getArguments())),
$this->getExpressionLanguage()->compile(substr($callable, 2), ['container' => 'container', 'args' => 'args'])
).$tail;
}
if (!\is_array($callable)) {
return $return.sprintf('%s(%s)', $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : '').$tail;
return $return.\sprintf('%s(%s)', $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : '').$tail;
}
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s).', $callable[1] ?: 'n/a'));
throw new RuntimeException(\sprintf('Cannot dump definition because of invalid factory method (%s).', $callable[1] ?: 'n/a'));
}
if (['...'] === $arguments && ($definition->isLazy() || 'Closure' !== ($definition->getClass() ?? 'Closure')) && (
if (['...'] === $arguments && ('Closure' !== ($class = $definition->getClass() ?: 'Closure') || $definition->isLazy() && (
$callable[0] instanceof Reference
|| ($callable[0] instanceof Definition && !$this->definitionVariables->contains($callable[0]))
)) {
|| ($callable[0] instanceof Definition && !$this->definitionVariables->offsetExists($callable[0]))
))) {
$initializer = 'fn () => '.$this->dumpValue($callable[0]);
$this->preload[LazyClosure::class] = LazyClosure::class;
return $return.LazyClosure::getCode($initializer, $callable, $definition, $this->container, $id).$tail;
return $return.LazyClosure::getCode($initializer, $callable, $class, $this->container, $id).$tail;
}
if ($callable[0] instanceof Reference
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))
|| ($callable[0] instanceof Definition && $this->definitionVariables->offsetExists($callable[0]))
) {
return $return.sprintf('%s->%s(%s)', $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
return $return.\sprintf('%s->%s(%s)', $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
}
$class = $this->dumpValue($callable[0]);
// If the class is a string we can optimize away
if (str_starts_with($class, "'") && !str_contains($class, '$')) {
if ("''" === $class) {
throw new RuntimeException(sprintf('Cannot dump definition: "%s" service is defined to be created by a factory but is missing the service reference, did you forget to define the factory service id or class?', $id ? 'The "'.$id.'"' : 'inline'));
throw new RuntimeException(\sprintf('Cannot dump definition: "%s" service is defined to be created by a factory but is missing the service reference, did you forget to define the factory service id or class?', $id ? 'The "'.$id.'"' : 'inline'));
}
return $return.sprintf('%s::%s(%s)', $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
return $return.\sprintf('%s::%s(%s)', $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
}
if (str_starts_with($class, 'new ')) {
return $return.sprintf('(%s)->%s(%s)', $class, $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
return $return.\sprintf('(%s)->%s(%s)', $class, $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
}
return $return.sprintf("[%s, '%s'](%s)", $class, $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
return $return.\sprintf("[%s, '%s'](%s)", $class, $callable[1], $arguments ? implode(', ', $arguments) : '').$tail;
}
if (null === $class = $definition->getClass()) {
@@ -1240,14 +1246,14 @@ EOTXT
}
if (!$asGhostObject) {
return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail;
return $return.\sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail;
}
if (!method_exists($this->container->getParameterBag()->resolveValue($class), '__construct')) {
return $return.'$lazyLoad'.$tail;
}
return $return.sprintf('($lazyLoad->__construct(%s) && false ?: $lazyLoad)', implode(', ', $arguments)).$tail;
return $return.\sprintf('($lazyLoad->__construct(%s) && false ?: $lazyLoad)', implode(', ', $arguments)).$tail;
}
private function startClass(string $class, string $baseClass, bool $hasProxyClasses): string
@@ -1473,7 +1479,7 @@ EOF;
ksort($definitions);
foreach ($definitions as $id => $definition) {
if (!$definition->isSynthetic() && $definition->isPublic() && !$this->isHotPath($definition)) {
$code .= sprintf(" %s => '%s',\n", $this->doExport($id), $this->generateMethodName($id));
$code .= \sprintf(" %s => '%s',\n", $this->doExport($id), $this->generateMethodName($id));
}
}
@@ -1565,7 +1571,7 @@ EOF;
foreach ($lineage as $file) {
if (!isset($this->inlinedRequires[$file])) {
$this->inlinedRequires[$file] = true;
$code .= sprintf("\n include_once %s;", $file);
$code .= \sprintf("\n include_once %s;", $file);
}
}
@@ -1573,7 +1579,7 @@ EOF;
$code .= "\n include_once __DIR__.'/proxy-classes.php';";
}
return $code ? sprintf("\n \$this->privates['service_container'] = static function (\$container) {%s\n };\n", $code) : '';
return $code ? \sprintf("\n \$this->privates['service_container'] = static function (\$container) {%s\n };\n", $code) : '';
}
private function addDefaultParametersMethod(): string
@@ -1587,20 +1593,20 @@ EOF;
foreach ($this->container->getParameterBag()->all() as $key => $value) {
if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) {
throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: "%s".', $resolvedKey));
throw new InvalidArgumentException(\sprintf('Parameter name cannot use env parameters: "%s".', $resolvedKey));
}
$hasEnum = false;
$export = $this->exportParameters([$value], '', 12, $hasEnum);
$export = explode('0 => ', substr(rtrim($export, " ]\n"), 2, -1), 2);
if ($hasEnum || preg_match("/\\\$container->(?:getEnv\('(?:[-.\w\\\\]*+:)*+\w*+'\)|targetDir\.'')/", $export[1])) {
$dynamicPhp[$key] = sprintf('%s%s => %s,', $export[0], $this->export($key), $export[1]);
$dynamicPhp[$key] = \sprintf('%s%s => %s,', $export[0], $this->export($key), $export[1]);
$this->dynamicParameters[$key] = true;
} else {
$php[] = sprintf('%s%s => %s,', $export[0], $this->export($key), $export[1]);
$php[] = \sprintf('%s%s => %s,', $export[0], $this->export($key), $export[1]);
}
}
$parameters = sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', 8));
$parameters = \sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', 8));
$code = <<<'EOF'
@@ -1610,27 +1616,28 @@ EOF;
trigger_deprecation(...self::DEPRECATED_PARAMETERS[$name]);
}
if (isset($this->buildParameters[$name])) {
if (\array_key_exists($name, $this->buildParameters)) {
return $this->buildParameters[$name];
}
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || \array_key_exists($name, $this->parameters))) {
throw new ParameterNotFoundException($name);
}
if (isset($this->loadedDynamicParameters[$name])) {
return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
}
if (!\array_key_exists($name, $this->parameters) || '.' === ($name[0] ?? '')) {
throw new ParameterNotFoundException($name);
}
return $this->parameters[$name];
}
public function hasParameter(string $name): bool
{
if (isset($this->buildParameters[$name])) {
if (\array_key_exists($name, $this->buildParameters)) {
return true;
}
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || \array_key_exists($name, $this->parameters);
return \array_key_exists($name, $this->parameters) || isset($this->loadedDynamicParameters[$name]);
}
public function setParameter(string $name, $value): void
@@ -1677,7 +1684,7 @@ EOF;
return $this->dynamicParameters[$name] = $value;
EOF;
$getDynamicParameter = sprintf($getDynamicParameter, implode("\n", $dynamicPhp));
$getDynamicParameter = \sprintf($getDynamicParameter, implode("\n", $dynamicPhp));
} else {
$loadedDynamicParameters = '[]';
$getDynamicParameter = str_repeat(' ', 8).'throw new ParameterNotFoundException($name);';
@@ -1713,26 +1720,26 @@ EOF;
if (\is_array($value)) {
$value = $this->exportParameters($value, $path.'/'.$key, $indent + 4, $hasEnum);
} elseif ($value instanceof ArgumentInterface) {
throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain special arguments. "%s" found in "%s".', get_debug_type($value), $path.'/'.$key));
throw new InvalidArgumentException(\sprintf('You cannot dump a container with parameters that contain special arguments. "%s" found in "%s".', get_debug_type($value), $path.'/'.$key));
} elseif ($value instanceof Variable) {
throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
throw new InvalidArgumentException(\sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
} elseif ($value instanceof Definition) {
throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain service definitions. Definition for "%s" found in "%s".', $value->getClass(), $path.'/'.$key));
throw new InvalidArgumentException(\sprintf('You cannot dump a container with parameters that contain service definitions. Definition for "%s" found in "%s".', $value->getClass(), $path.'/'.$key));
} elseif ($value instanceof Reference) {
throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain references to other services (reference to service "%s" found in "%s").', $value, $path.'/'.$key));
throw new InvalidArgumentException(\sprintf('You cannot dump a container with parameters that contain references to other services (reference to service "%s" found in "%s").', $value, $path.'/'.$key));
} elseif ($value instanceof Expression) {
throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".', $value, $path.'/'.$key));
throw new InvalidArgumentException(\sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".', $value, $path.'/'.$key));
} elseif ($value instanceof \UnitEnum) {
$hasEnum = true;
$value = sprintf('\%s::%s', $value::class, $value->name);
$value = \sprintf('\%s::%s', $value::class, $value->name);
} else {
$value = $this->export($value);
}
$php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), $this->export($key), $value);
$php[] = \sprintf('%s%s => %s,', str_repeat(' ', $indent), $this->export($key), $value);
}
return sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', $indent - 4));
return \sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', $indent - 4));
}
private function endClass(): string
@@ -1752,7 +1759,7 @@ EOF;
// re-indent the wrapped code
$code = implode("\n", array_map(fn ($line) => $line ? ' '.$line : $line, explode("\n", $code)));
return sprintf(" if (%s) {\n%s }\n", $condition, $code);
return \sprintf(" if (%s) {\n%s }\n", $condition, $code);
}
private function getServiceConditionals(mixed $value): string
@@ -1762,14 +1769,14 @@ EOF;
if (!$this->container->hasDefinition($service)) {
return 'false';
}
$conditions[] = sprintf('isset($container->%s[%s])', $this->container->getDefinition($service)->isPublic() ? 'services' : 'privates', $this->doExport($service));
$conditions[] = \sprintf('isset($container->%s[%s])', $this->container->getDefinition($service)->isPublic() ? 'services' : 'privates', $this->doExport($service));
}
foreach (ContainerBuilder::getServiceConditionals($value) as $service) {
if ($this->container->hasDefinition($service) && !$this->container->getDefinition($service)->isPublic()) {
continue;
}
$conditions[] = sprintf('$container->has(%s)', $this->doExport($service));
$conditions[] = \sprintf('$container->has(%s)', $this->doExport($service));
}
if (!$conditions) {
@@ -1779,7 +1786,7 @@ EOF;
return implode(' && ', $conditions);
}
private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = [], bool $byConstructor = null): \SplObjectStorage
private function getDefinitionsFromArguments(array $arguments, ?\SplObjectStorage $definitions = null, array &$calls = [], ?bool $byConstructor = null): \SplObjectStorage
{
$definitions ??= new \SplObjectStorage();
@@ -1828,10 +1835,10 @@ EOF;
$isList = array_is_list($value);
$code = [];
foreach ($value as $k => $v) {
$code[] = $isList ? $this->dumpValue($v, $interpolate) : sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
$code[] = $isList ? $this->dumpValue($v, $interpolate) : \sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
}
return sprintf('[%s]', implode(', ', $code));
return \sprintf('[%s]', implode(', ', $code));
} elseif ($value instanceof ArgumentInterface) {
$scope = [$this->definitionVariables, $this->referenceVariables];
$this->definitionVariables = $this->referenceVariables = null;
@@ -1843,7 +1850,15 @@ EOF;
$returnedType = '';
if ($value instanceof TypedReference) {
$returnedType = sprintf(': %s\%s', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() ? '' : '?', str_replace(['|', '&'], ['|\\', '&\\'], $value->getType()));
$type = $value->getType();
$nullable = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() ? '' : '?';
if ('?' === ($type[0] ?? '')) {
$type = substr($type, 1);
$nullable = '?';
}
$returnedType = \sprintf(': %s\%s', $nullable, str_replace(['|', '&'], ['|\\', '&\\'], $type));
}
$attribute = '';
@@ -1854,10 +1869,10 @@ EOF;
$attribute .= ', class: '.$this->dumpValue($class, $interpolate);
}
$attribute = sprintf('#[\Closure(%s)] ', $attribute);
$attribute = \sprintf('#[\Closure(%s)] ', $attribute);
}
return sprintf('%sfn ()%s => %s', $attribute, $returnedType, $code);
return \sprintf('%sfn ()%s => %s', $attribute, $returnedType, $code);
}
if ($value instanceof IteratorArgument) {
@@ -1871,7 +1886,7 @@ EOF;
$operands = [0];
foreach ($values as $k => $v) {
($c = $this->getServiceConditionals($v)) ? $operands[] = "(int) ($c)" : ++$operands[0];
$v = $this->wrapServiceConditionals($v, sprintf(" yield %s => %s;\n", $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate)));
$v = $this->wrapServiceConditionals($v, \sprintf(" yield %s => %s;\n", $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate)));
foreach (explode("\n", $v) as $v) {
if ($v) {
$code[] = ' '.$v;
@@ -1879,7 +1894,7 @@ EOF;
}
}
$code[] = sprintf(' }, %s)', \count($operands) > 1 ? 'fn () => '.implode(' + ', $operands) : $operands[0]);
$code[] = \sprintf(' }, %s)', \count($operands) > 1 ? 'fn () => '.implode(' + ', $operands) : $operands[0]);
return implode("\n", $code);
}
@@ -1889,8 +1904,8 @@ EOF;
$serviceTypes = '';
foreach ($value->getValues() as $k => $v) {
if (!$v instanceof Reference) {
$serviceMap .= sprintf("\n %s => [%s],", $this->export($k), $this->dumpValue($v));
$serviceTypes .= sprintf("\n %s => '?',", $this->export($k));
$serviceMap .= \sprintf("\n %s => [%s],", $this->export($k), $this->dumpValue($v));
$serviceTypes .= \sprintf("\n %s => '?',", $this->export($k));
continue;
}
$id = (string) $v;
@@ -1899,28 +1914,28 @@ EOF;
}
$definition = $this->container->getDefinition($id);
$load = !($definition->hasErrors() && $e = $definition->getErrors()) ? $this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition) : reset($e);
$serviceMap .= sprintf("\n %s => [%s, %s, %s, %s],",
$serviceMap .= \sprintf("\n %s => [%s, %s, %s, %s],",
$this->export($k),
$this->export($definition->isShared() ? ($definition->isPublic() ? 'services' : 'privates') : false),
$this->doExport($id),
$this->export(ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $v->getInvalidBehavior() && !\is_string($load) ? $this->generateMethodName($id) : null),
$this->export($load)
);
$serviceTypes .= sprintf("\n %s => %s,", $this->export($k), $this->export($v instanceof TypedReference ? $v->getType() : '?'));
$serviceTypes .= \sprintf("\n %s => %s,", $this->export($k), $this->export($v instanceof TypedReference ? $v->getType() : '?'));
$this->locatedIds[$id] = true;
}
$this->addGetService = true;
return sprintf('new \%s($container->getService ??= $container->getService(...), [%s%s], [%s%s])', ServiceLocator::class, $serviceMap, $serviceMap ? "\n " : '', $serviceTypes, $serviceTypes ? "\n " : '');
return \sprintf('new \%s($container->getService ??= $container->getService(...), [%s%s], [%s%s])', ServiceLocator::class, $serviceMap, $serviceMap ? "\n " : '', $serviceTypes, $serviceTypes ? "\n " : '');
}
} finally {
[$this->definitionVariables, $this->referenceVariables] = $scope;
}
} elseif ($value instanceof Definition) {
if ($value->hasErrors() && $e = $value->getErrors()) {
return sprintf('throw new RuntimeException(%s)', $this->export(reset($e)));
return \sprintf('throw new RuntimeException(%s)', $this->export(reset($e)));
}
if ($this->definitionVariables?->contains($value)) {
if ($this->definitionVariables?->offsetExists($value)) {
return $this->dumpValue($this->definitionVariables[$value], $interpolate);
}
if ($value->getMethodCalls()) {
@@ -1965,11 +1980,11 @@ EOF;
return $code;
}
} elseif ($value instanceof \UnitEnum) {
return sprintf('\%s::%s', $value::class, $value->name);
return \sprintf('\%s::%s', $value::class, $value->name);
} elseif ($value instanceof AbstractArgument) {
throw new RuntimeException($value->getTextWithContext());
} elseif (\is_object($value) || \is_resource($value)) {
throw new RuntimeException(sprintf('Unable to dump a service container if a parameter is an object or a resource, got "%s".', get_debug_type($value)));
throw new RuntimeException(\sprintf('Unable to dump a service container if a parameter is an object or a resource, got "%s".', get_debug_type($value)));
}
return $this->export($value);
@@ -1983,10 +1998,10 @@ EOF;
private function dumpLiteralClass(string $class): string
{
if (str_contains($class, '$')) {
return sprintf('${($_ = %s) && false ?: "_"}', $class);
return \sprintf('${($_ = %s) && false ?: "_"}', $class);
}
if (!str_starts_with($class, "'") || !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s).', $class ?: 'n/a'));
throw new RuntimeException(\sprintf('Cannot dump definition because of invalid class name (%s).', $class ?: 'n/a'));
}
$class = substr(str_replace('\\\\', '\\', $class), 1, -1);
@@ -1997,7 +2012,7 @@ EOF;
private function dumpParameter(string $name): string
{
if (!$this->container->hasParameter($name) || ($this->dynamicParameters[$name] ?? false)) {
return sprintf('$container->getParameter(%s)', $this->doExport($name));
return \sprintf('$container->getParameter(%s)', $this->doExport($name));
}
$value = $this->container->getParameter($name);
@@ -2007,10 +2022,10 @@ EOF;
return $dumpedValue;
}
return sprintf('$container->parameters[%s]', $this->doExport($name));
return \sprintf('$container->parameters[%s]', $this->doExport($name));
}
private function getServiceCall(string $id, Reference $reference = null): string
private function getServiceCall(string $id, ?Reference $reference = null): string
{
while ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
@@ -2022,7 +2037,7 @@ EOF;
if ($this->container->hasDefinition($id) && $definition = $this->container->getDefinition($id)) {
if ($definition->isSynthetic()) {
$code = sprintf('$container->get(%s%s)', $this->doExport($id), null !== $reference ? ', '.$reference->getInvalidBehavior() : '');
$code = \sprintf('$container->get(%s%s)', $this->doExport($id), null !== $reference ? ', '.$reference->getInvalidBehavior() : '');
} elseif (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
$code = 'null';
if (!$definition->isShared()) {
@@ -2030,24 +2045,24 @@ EOF;
}
} elseif ($this->isTrivialInstance($definition)) {
if ($definition->hasErrors() && $e = $definition->getErrors()) {
return sprintf('throw new RuntimeException(%s)', $this->export(reset($e)));
return \sprintf('throw new RuntimeException(%s)', $this->export(reset($e)));
}
$code = $this->addNewInstance($definition, '', $id);
if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) {
return sprintf('($container->%s[%s] ??= %s)', $definition->isPublic() ? 'services' : 'privates', $this->doExport($id), $code);
return \sprintf('($container->%s[%s] ??= %s)', $definition->isPublic() ? 'services' : 'privates', $this->doExport($id), $code);
}
$code = "($code)";
} else {
$code = $this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition) ? "\$container->load('%s')" : 'self::%s($container)';
$code = sprintf($code, $this->generateMethodName($id));
$code = \sprintf($code, $this->generateMethodName($id));
if (!$definition->isShared()) {
$factory = sprintf('$container->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id));
$code = sprintf('(isset(%s) ? %1$s($container) : %s)', $factory, $code);
$factory = \sprintf('$container->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id));
$code = \sprintf('(isset(%s) ? %1$s($container) : %s)', $factory, $code);
}
}
if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) {
$code = sprintf('($container->%s[%s] ?? %s)', $definition->isPublic() ? 'services' : 'privates', $this->doExport($id), $code);
$code = \sprintf('($container->%s[%s] ?? %s)', $definition->isPublic() ? 'services' : 'privates', $this->doExport($id), $code);
}
return $code;
@@ -2056,12 +2071,12 @@ EOF;
return 'null';
}
if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $reference->getInvalidBehavior()) {
$code = sprintf('$container->get(%s, ContainerInterface::NULL_ON_INVALID_REFERENCE)', $this->doExport($id));
$code = \sprintf('$container->get(%s, ContainerInterface::NULL_ON_INVALID_REFERENCE)', $this->doExport($id));
} else {
$code = sprintf('$container->get(%s)', $this->doExport($id));
$code = \sprintf('$container->get(%s)', $this->doExport($id));
}
return sprintf('($container->services[%s] ?? %s)', $this->doExport($id), $code);
return \sprintf('($container->services[%s] ?? %s)', $this->doExport($id), $code);
}
/**
@@ -2152,7 +2167,7 @@ EOF;
return $this->getServiceCall($id);
}
return sprintf('$container->get(%s)', $arg);
return \sprintf('$container->get(%s)', $arg);
});
if ($this->container->isTrackingResources()) {
@@ -2180,7 +2195,13 @@ EOF;
if (!$value = $edge->getSourceNode()->getValue()) {
continue;
}
if ($edge->isLazy() || !$value instanceof Definition || !$value->isShared()) {
if ($edge->isLazy() || !$value instanceof Definition || !$value->isShared() || $edge->isFromMultiUseArgument()) {
return false;
}
// When the source node is a proxy or ghost, it will construct its references only when the node itself is initialized.
// Since the node can be cloned before being fully initialized, we do not know how often its references are used.
if ($this->getProxyDumper()->isProxyCandidate($value)) {
return false;
}
$ids[$edge->getSourceNode()->getId()] = true;
@@ -2208,13 +2229,13 @@ EOF;
$offset = 2 + $this->targetDirMaxMatches - \count($matches);
if (0 < $offset) {
$dirname = sprintf('\dirname(__DIR__, %d)', $offset + (int) $this->asFiles);
$dirname = \sprintf('\dirname(__DIR__, %d)', $offset + (int) $this->asFiles);
} elseif ($this->asFiles) {
$dirname = "\$container->targetDir.''"; // empty string concatenation on purpose
}
if ($prefix || $suffix) {
return sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
return \sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
}
return $dirname;
@@ -2291,36 +2312,35 @@ EOF;
private function getClasses(Definition $definition, string $id): array
{
$classes = [];
$resolve = $this->container->getParameterBag()->resolveValue(...);
while ($definition instanceof Definition) {
foreach ($definition->getTag($this->preloadTags[0]) as $tag) {
if (!isset($tag['class'])) {
throw new InvalidArgumentException(sprintf('Missing attribute "class" on tag "%s" for service "%s".', $this->preloadTags[0], $id));
throw new InvalidArgumentException(\sprintf('Missing attribute "class" on tag "%s" for service "%s".', $this->preloadTags[0], $id));
}
$classes[] = trim($tag['class'], '\\');
}
if ($class = $definition->getClass()) {
$classes[] = trim($resolve($class), '\\');
$classes[] = trim($class, '\\');
}
$factory = $definition->getFactory();
if (!\is_array($factory)) {
$factory = [$factory];
if (\is_string($factory) && !str_starts_with($factory, '@=') && str_contains($factory, '::')) {
$factory = explode('::', $factory);
}
if (\is_string($factory[0])) {
$factory[0] = $resolve($factory[0]);
if (!\is_array($factory)) {
$definition = $factory;
continue;
}
if (false !== $i = strrpos($factory[0], '::')) {
$factory[0] = substr($factory[0], 0, $i);
}
$definition = $factory[0] ?? null;
if (\is_string($definition)) {
$classes[] = trim($factory[0], '\\');
}
$definition = $factory[0];
}
return $classes;