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

@@ -117,7 +117,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
private array $vendors;
/**
* @var string[] the list of paths in vendor directories
* @var array<string, bool> the cache for paths being in vendor directories
*/
private array $pathsInVendor = [];
@@ -155,7 +155,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
'mixed' => true,
];
public function __construct(ParameterBagInterface $parameterBag = null)
public function __construct(?ParameterBagInterface $parameterBag = null)
{
parent::__construct($parameterBag);
@@ -207,7 +207,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$this->extensions[$extension->getAlias()] = $extension;
if (false !== $extension->getNamespace()) {
$this->extensionsByNs[$extension->getNamespace()] = $extension;
$this->extensionsByNs[$extension->getNamespace() ?? ''] = $extension;
}
}
@@ -226,7 +226,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
return $this->extensionsByNs[$name];
}
throw new LogicException(sprintf('Container extension "%s" is not registered.', $name));
throw new LogicException(\sprintf('Container extension "%s" is not registered.', $name));
}
/**
@@ -360,7 +360,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$resource = new ClassExistenceResource($class, false);
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
} else {
$classReflector = class_exists($class) ? new \ReflectionClass($class) : false;
$classReflector = class_exists($class) || interface_exists($class, false) ? new \ReflectionClass($class) : false;
}
} catch (\ReflectionException $e) {
if ($throw) {
@@ -431,7 +431,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @throws BadMethodCallException When this ContainerBuilder is compiled
* @throws \LogicException if the extension is not registered
*/
public function loadFromExtension(string $extension, array $values = null): static
public function loadFromExtension(string $extension, ?array $values = null): static
{
if ($this->isCompiled()) {
throw new BadMethodCallException('Cannot load from an extension on a compiled container.');
@@ -488,7 +488,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
{
if ($this->isCompiled() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
// setting a synthetic service on a compiled container is alright
throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a compiled container is not allowed.', $id));
throw new BadMethodCallException(\sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a compiled container is not allowed.', $id));
}
unset($this->definitions[$id], $this->aliasDefinitions[$id], $this->removedIds[$id]);
@@ -531,7 +531,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
return $this->doGet($id, $invalidBehavior);
}
private function doGet(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = null, bool $isConstructorArgument = false): mixed
private function doGet(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, ?array &$inlineServices = null, bool $isConstructorArgument = false): mixed
{
if (isset($inlineServices[$id])) {
return $inlineServices[$id];
@@ -669,7 +669,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
foreach ($container->getAutoconfiguredInstanceof() as $interface => $childDefinition) {
if (isset($this->autoconfiguredInstanceof[$interface])) {
throw new InvalidArgumentException(sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.', $interface));
throw new InvalidArgumentException(\sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.', $interface));
}
$this->autoconfiguredInstanceof[$interface] = $childDefinition;
@@ -677,7 +677,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
foreach ($container->getAutoconfiguredAttributes() as $attribute => $configurator) {
if (isset($this->autoconfiguredAttributes[$attribute])) {
throw new InvalidArgumentException(sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same attribute.', $attribute));
throw new InvalidArgumentException(\sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same attribute.', $attribute));
}
$this->autoconfiguredAttributes[$attribute] = $configurator;
@@ -722,7 +722,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
public function deprecateParameter(string $name, string $package, string $version, string $message = 'The parameter "%s" is deprecated.'): void
{
if (!$this->parameterBag instanceof ParameterBag) {
throw new BadMethodCallException(sprintf('The parameter bag must be an instance of "%s" to call "%s".', ParameterBag::class, __METHOD__));
throw new BadMethodCallException(\sprintf('The parameter bag must be an instance of "%s" to call "%s".', ParameterBag::class, __METHOD__));
}
$this->parameterBag->deprecate($name, $package, $version, $message);
@@ -742,10 +742,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* * The parameter bag is frozen;
* * Extension loading is disabled.
*
* @param bool $resolveEnvPlaceholders Whether %env()% parameters should be resolved using the current
* env vars or be replaced by uniquely identifiable placeholders.
* Set to "true" when you want to use the current ContainerBuilder
* directly, keep to "false" when the container is dumped instead.
* @param bool $resolveEnvPlaceholders Whether %env()% parameters should be resolved at build time using
* the current env var values (true), or be resolved at runtime based
* on the environment (false). In general, this should be set to "true"
* when you want to use the current ContainerBuilder directly, and to
* "false" when the container is dumped instead.
*
* @return void
*/
@@ -776,7 +777,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if ($bag instanceof EnvPlaceholderParameterBag) {
if ($resolveEnvPlaceholders) {
$this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true));
$this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($this->escapeParameters($bag->all()), true));
}
$this->envPlaceholders = $bag->getEnvPlaceholders();
@@ -842,7 +843,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
public function setAlias(string $alias, string|Alias $id): Alias
{
if ('' === $alias || '\\' === $alias[-1] || \strlen($alias) !== strcspn($alias, "\0\r\n'")) {
throw new InvalidArgumentException(sprintf('Invalid alias id: "%s".', $alias));
throw new InvalidArgumentException(\sprintf('Invalid alias id: "%s".', $alias));
}
if (\is_string($id)) {
@@ -850,7 +851,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
}
if ($alias === (string) $id) {
throw new InvalidArgumentException(sprintf('An alias cannot reference itself, got a circular reference on "%s".', $alias));
throw new InvalidArgumentException(\sprintf('An alias cannot reference itself, got a circular reference on "%s".', $alias));
}
unset($this->definitions[$alias], $this->removedIds[$alias]);
@@ -888,7 +889,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
public function getAlias(string $id): Alias
{
if (!isset($this->aliasDefinitions[$id])) {
throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
throw new InvalidArgumentException(\sprintf('The service alias "%s" does not exist.', $id));
}
return $this->aliasDefinitions[$id];
@@ -900,7 +901,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* This methods allows for simple registration of service definition
* with a fluid interface.
*/
public function register(string $id, string $class = null): Definition
public function register(string $id, ?string $class = null): Definition
{
return $this->setDefinition($id, new Definition($class));
}
@@ -911,7 +912,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* This method implements a shortcut for using setDefinition() with
* an autowired definition.
*/
public function autowire(string $id, string $class = null): Definition
public function autowire(string $id, ?string $class = null): Definition
{
return $this->setDefinition($id, (new Definition($class))->setAutowired(true));
}
@@ -965,7 +966,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
}
if ('' === $id || '\\' === $id[-1] || \strlen($id) !== strcspn($id, "\0\r\n'")) {
throw new InvalidArgumentException(sprintf('Invalid service id: "%s".', $id));
throw new InvalidArgumentException(\sprintf('Invalid service id: "%s".', $id));
}
unset($this->aliasDefinitions[$id], $this->removedIds[$id]);
@@ -1029,18 +1030,18 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @throws RuntimeException When the service is a synthetic service
* @throws InvalidArgumentException When configure callable is not callable
*/
private function createService(Definition $definition, array &$inlineServices, bool $isConstructorArgument = false, string $id = null, bool|object $tryProxy = true): mixed
private function createService(Definition $definition, array &$inlineServices, bool $isConstructorArgument = false, ?string $id = null, bool|object $tryProxy = true): mixed
{
if (null === $id && isset($inlineServices[$h = spl_object_hash($definition)])) {
return $inlineServices[$h];
}
if ($definition instanceof ChildDefinition) {
throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
throw new RuntimeException(\sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
}
if ($definition->isSynthetic()) {
throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
throw new RuntimeException(\sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
}
if ($definition->isDeprecated()) {
@@ -1059,14 +1060,15 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
}
if (\is_array($callable) && (
$callable[0] instanceof Reference
'Closure' !== $class
|| $callable[0] instanceof Reference
|| $callable[0] instanceof Definition && !isset($inlineServices[spl_object_hash($callable[0])])
)) {
$initializer = function () use ($callable, &$inlineServices) {
return $this->doResolveServices($callable[0], $inlineServices);
};
$proxy = eval('return '.LazyClosure::getCode('$initializer', $callable, $definition, $this, $id).';');
$proxy = eval('return '.LazyClosure::getCode('$initializer', $callable, $class, $this, $id).';');
$this->shareService($definition, $proxy, $id, $inlineServices);
return $proxy;
@@ -1100,7 +1102,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if (\is_array($factory)) {
$factory = [$this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlineServices, $isConstructorArgument), $factory[1]];
} elseif (!\is_string($factory)) {
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory.', $id));
throw new RuntimeException(\sprintf('Cannot create service "%s" because of invalid factory.', $id));
} elseif (str_starts_with($factory, '@=')) {
$factory = fn (ServiceLocator $arguments) => $this->getExpressionLanguage()->evaluate(substr($factory, 2), ['container' => $this, 'args' => $arguments]);
$arguments = [new ServiceLocatorArgument($arguments)];
@@ -1123,7 +1125,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) {
$r = new \ReflectionClass($factory[0]);
if (0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
if (0 < strpos($r->getDocComment() ?: '', "\n * @deprecated ")) {
trigger_deprecation('', '', 'The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.', $id, $r->name);
}
}
@@ -1140,7 +1142,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$service = $r->getConstructor() ? $r->newInstanceArgs($arguments) : $r->newInstance();
}
if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment() ?: '', "\n * @deprecated ")) {
trigger_deprecation('', '', 'The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name);
}
}
@@ -1183,7 +1185,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
}
if (!\is_callable($callable)) {
throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_debug_type($service)));
throw new InvalidArgumentException(\sprintf('The configure callable for class "%s" is not a callable.', get_debug_type($service)));
}
$callable($service);
@@ -1292,7 +1294,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
foreach ($this->getDefinitions() as $id => $definition) {
if ($definition->hasTag($name) && !$definition->hasTag('container.excluded')) {
if ($throwOnAbstract && $definition->isAbstract()) {
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must not be abstract.', $id, $name));
throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must not be abstract.', $id, $name));
}
$tags[$id] = $definition->getTag($name);
}
@@ -1380,16 +1382,16 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* "$fooBar"-named arguments with $type as type-hint. Such arguments will
* receive the service $id when autowiring is used.
*/
public function registerAliasForArgument(string $id, string $type, string $name = null): Alias
public function registerAliasForArgument(string $id, string $type, ?string $name = null): Alias
{
$parsedName = (new Target($name ??= $id))->getParsedName();
if (!preg_match('/^[a-zA-Z_\x7f-\xff]/', $parsedName)) {
if ($id !== $name) {
$id = sprintf(' for service "%s"', $id);
$id = \sprintf(' for service "%s"', $id);
}
throw new InvalidArgumentException(sprintf('Invalid argument name "%s"'.$id.': the first character must be a letter.', $name));
throw new InvalidArgumentException(\sprintf('Invalid argument name "%s"'.$id.': the first character must be a letter.', $name));
}
if ($parsedName !== $name) {
@@ -1427,7 +1429,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*
* @return mixed The value with env parameters resolved if a string or an array is passed
*/
public function resolveEnvPlaceholders(mixed $value, string|bool $format = null, array &$usedEnvs = null): mixed
public function resolveEnvPlaceholders(mixed $value, string|bool|null $format = null, ?array &$usedEnvs = null): mixed
{
$bag = $this->getParameterBag();
if (true === $format ??= '%%env(%s)%%') {
@@ -1461,14 +1463,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if (true === $format) {
$resolved = $bag->escapeValue($this->getEnv($env));
} else {
$resolved = sprintf($format, $env);
$resolved = \sprintf($format, $env);
}
if ($placeholder === $value) {
$value = $resolved;
$completed = true;
} else {
if (!\is_string($resolved) && !is_numeric($resolved)) {
throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "env(%s)" of type "%s" inside string value "%s".', $env, get_debug_type($resolved), $this->resolveEnvPlaceholders($value)));
throw new RuntimeException(\sprintf('A string value must be composed of strings and/or numbers, but found parameter "env(%s)" of type "%s" inside string value "%s".', $env, get_debug_type($resolved), $this->resolveEnvPlaceholders($value)));
}
$value = str_ireplace($placeholder, $resolved, $value);
}
@@ -1523,7 +1525,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
final public static function willBeAvailable(string $package, string $class, array $parentPackages): bool
{
if (!class_exists(InstalledVersions::class)) {
throw new \LogicException(sprintf('Calling "%s" when dependencies have been installed with Composer 1 is not supported. Consider upgrading to Composer 2.', __METHOD__));
throw new \LogicException(\sprintf('Calling "%s" when dependencies have been installed with Composer 1 is not supported. Consider upgrading to Composer 2.', __METHOD__));
}
if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) {
@@ -1726,4 +1728,18 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
return $this->pathsInVendor[$path] = false;
}
private function escapeParameters(array $parameters): array
{
$params = [];
foreach ($parameters as $k => $v) {
$params[$k] = match (true) {
\is_array($v) => $this->escapeParameters($v),
\is_string($v) => str_replace('%', '%%', $v),
default => $v,
};
}
return $params;
}
}