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

@@ -63,11 +63,11 @@ class ClassBuilder
}
unset($path[$key]);
}
$require .= sprintf('require_once __DIR__.\DIRECTORY_SEPARATOR.\'%s\';', implode('\'.\DIRECTORY_SEPARATOR.\'', $path))."\n";
$require .= \sprintf('require_once __DIR__.\DIRECTORY_SEPARATOR.\'%s\';', implode('\'.\DIRECTORY_SEPARATOR.\'', $path))."\n";
}
$use = $require ? "\n" : '';
foreach (array_keys($this->use) as $statement) {
$use .= sprintf('use %s;', $statement)."\n";
$use .= \sprintf('use %s;', $statement)."\n";
}
$implements = [] === $this->implements ? '' : 'implements '.implode(', ', $this->implements);
@@ -119,15 +119,15 @@ BODY
$this->methods[] = new Method(strtr($body, ['NAME' => $this->camelCase($name)] + $params));
}
public function addProperty(string $name, string $classType = null, string $defaultValue = null): Property
public function addProperty(string $name, ?string $classType = null, ?string $defaultValue = null): Property
{
$property = new Property($name, '_' !== $name[0] ? $this->camelCase($name) : $name);
if (null !== $classType) {
$property->setType($classType);
}
$this->properties[] = $property;
$defaultValue = null !== $defaultValue ? sprintf(' = %s', $defaultValue) : '';
$property->setContent(sprintf('private $%s%s;', $property->getName(), $defaultValue));
$defaultValue = null !== $defaultValue ? \sprintf(' = %s', $defaultValue) : '';
$property->setContent(\sprintf('private $%s%s;', $property->getName(), $defaultValue));
return $property;
}

View File

@@ -115,7 +115,7 @@ public function NAME(): string
$child instanceof PrototypedArrayNode => $this->handlePrototypedArrayNode($child, $class, $namespace),
$child instanceof VariableNode => $this->handleVariableNode($child, $class),
$child instanceof ArrayNode => $this->handleArrayNode($child, $class, $namespace),
default => throw new \RuntimeException(sprintf('Unknown node "%s".', $child::class)),
default => throw new \RuntimeException(\sprintf('Unknown node "%s".', $child::class)),
};
}
}
@@ -127,12 +127,15 @@ public function NAME(): string
$class->addRequire($childClass);
$this->classes[] = $childClass;
$nodeTypes = $this->getParameterTypes($node);
$paramType = $this->getParamType($nodeTypes);
$hasNormalizationClosures = $this->hasNormalizationClosures($node);
$comment = $this->getComment($node);
if ($hasNormalizationClosures) {
$comment = sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment);
$comment .= sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
$comment .= sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
if ($hasNormalizationClosures && 'array' !== $paramType) {
$comment = \sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment);
$comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
}
if ('' !== $comment) {
$comment = "/**\n$comment*/\n";
@@ -142,8 +145,7 @@ public function NAME(): string
$node->getName(),
$this->getType($childClass->getFqcn(), $hasNormalizationClosures)
);
$nodeTypes = $this->getParameterTypes($node);
$body = $hasNormalizationClosures ? '
$body = $hasNormalizationClosures && 'array' !== $paramType ? '
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
{
if (!\is_array($value)) {
@@ -178,7 +180,7 @@ COMMENTpublic function NAME(array $value = []): CLASS
'COMMENT' => $comment,
'PROPERTY' => $property->getName(),
'CLASS' => $childClass->getFqcn(),
'PARAM_TYPE' => \in_array('mixed', $nodeTypes, true) ? 'mixed' : implode('|', $nodeTypes),
'PARAM_TYPE' => $paramType,
]);
$this->buildNode($node, $childClass, $this->getSubNamespace($childClass));
@@ -218,10 +220,11 @@ public function NAME(mixed $valueDEFAULT): static
$nodeParameterTypes = $this->getParameterTypes($node);
$prototypeParameterTypes = $this->getParameterTypes($prototype);
$noKey = null === $key = $node->getKeyAttribute();
if (!$prototype instanceof ArrayNode || ($prototype instanceof PrototypedArrayNode && $prototype->getPrototype() instanceof ScalarNode)) {
$class->addUse(ParamConfigurator::class);
$property = $class->addProperty($node->getName());
if (null === $key = $node->getKeyAttribute()) {
if ($noKey) {
// This is an array of values; don't use singular name
$nodeTypesWithoutArray = array_filter($nodeParameterTypes, static fn ($type) => 'array' !== $type);
$body = '
@@ -242,7 +245,7 @@ public function NAME(PARAM_TYPE $value): static
'PROPERTY' => $property->getName(),
'PROTOTYPE_TYPE' => implode('|', $prototypeParameterTypes),
'EXTRA_TYPE' => $nodeTypesWithoutArray ? '|'.implode('|', $nodeTypesWithoutArray) : '',
'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $nodeParameterTypes),
'PARAM_TYPE' => $this->getParamType($nodeParameterTypes, true),
]);
} else {
$body = '
@@ -259,7 +262,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
$class->addMethod($methodName, $body, [
'PROPERTY' => $property->getName(),
'TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $prototypeParameterTypes),
'TYPE' => $this->getParamType($prototypeParameterTypes, true),
'VAR' => '' === $key ? 'key' : $key,
'VALUE' => 'value' === $key ? 'data' : 'value',
]);
@@ -280,18 +283,20 @@ public function NAME(string $VAR, TYPE $VALUE): static
$this->getType($childClass->getFqcn().'[]', $hasNormalizationClosures)
);
$paramType = $this->getParamType($noKey ? $nodeParameterTypes : $prototypeParameterTypes);
$comment = $this->getComment($node);
if ($hasNormalizationClosures) {
$comment = sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment);
$comment .= sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
$comment .= sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
if ($hasNormalizationClosures && 'array' !== $paramType) {
$comment = \sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment);
$comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
}
if ('' !== $comment) {
$comment = "/**\n$comment*/\n";
}
if (null === $key = $node->getKeyAttribute()) {
$body = $hasNormalizationClosures ? '
if ($noKey) {
$body = $hasNormalizationClosures && 'array' !== $paramType ? '
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
{
$this->_usedProperties[\'PROPERTY\'] = true;
@@ -313,10 +318,10 @@ COMMENTpublic function NAME(array $value = []): CLASS
'COMMENT' => $comment,
'PROPERTY' => $property->getName(),
'CLASS' => $childClass->getFqcn(),
'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : implode('|', $nodeParameterTypes),
'PARAM_TYPE' => $paramType,
]);
} else {
$body = $hasNormalizationClosures ? '
$body = $hasNormalizationClosures && 'array' !== $paramType ? '
COMMENTpublic function NAME(string $VAR, PARAM_TYPE $VALUE = []): CLASS|static
{
if (!\is_array($VALUE)) {
@@ -352,7 +357,7 @@ COMMENTpublic function NAME(string $VAR, array $VALUE = []): CLASS
'CLASS' => $childClass->getFqcn(),
'VAR' => '' === $key ? 'key' : $key,
'VALUE' => 'value' === $key ? 'data' : 'value',
'PARAM_TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : implode('|', $prototypeParameterTypes),
'PARAM_TYPE' => $paramType,
]);
}
@@ -413,39 +418,39 @@ public function NAME($value): static
{
$comment = '';
if ('' !== $info = (string) $node->getInfo()) {
$comment .= ' * '.$info."\n";
$comment .= $info."\n";
}
if (!$node instanceof ArrayNode) {
foreach ((array) ($node->getExample() ?? []) as $example) {
$comment .= ' * @example '.$example."\n";
$comment .= '@example '.$example."\n";
}
if ('' !== $default = $node->getDefaultValue()) {
$comment .= ' * @default '.(null === $default ? 'null' : var_export($default, true))."\n";
$comment .= '@default '.(null === $default ? 'null' : var_export($default, true))."\n";
}
if ($node instanceof EnumNode) {
$comment .= sprintf(' * @param ParamConfigurator|%s $value', implode('|', array_unique(array_map(fn ($a) => !$a instanceof \UnitEnum ? var_export($a, true) : '\\'.ltrim(var_export($a, true), '\\'), $node->getValues()))))."\n";
$comment .= \sprintf('@param ParamConfigurator|%s $value', implode('|', array_unique(array_map(fn ($a) => !$a instanceof \UnitEnum ? var_export($a, true) : '\\'.ltrim(var_export($a, true), '\\'), $node->getValues()))))."\n";
} else {
$parameterTypes = $this->getParameterTypes($node);
$comment .= ' * @param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n";
$comment .= '@param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n";
}
} else {
foreach ((array) ($node->getExample() ?? []) as $example) {
$comment .= ' * @example '.json_encode($example)."\n";
$comment .= '@example '.json_encode($example)."\n";
}
if ($node->hasDefaultValue() && [] != $default = $node->getDefaultValue()) {
$comment .= ' * @default '.json_encode($default)."\n";
$comment .= '@default '.json_encode($default)."\n";
}
}
if ($node->isDeprecated()) {
$comment .= ' * @deprecated '.$node->getDeprecation($node->getName(), $node->getParent()->getName())['message']."\n";
$comment .= '@deprecated '.$node->getDeprecation($node->getName(), $node->getParent()->getName())['message']."\n";
}
return $comment;
return $comment ? ' * '.str_replace("\n", "\n * ", rtrim($comment, "\n"))."\n" : '';
}
/**
@@ -579,7 +584,7 @@ public function NAME(string $key, mixed $value): static
private function getSubNamespace(ClassBuilder $rootClass): string
{
return sprintf('%s\\%s', $rootClass->getNamespace(), substr($rootClass->getName(), 0, -6));
return \sprintf('%s\\%s', $rootClass->getNamespace(), substr($rootClass->getName(), 0, -6));
}
private function hasNormalizationClosures(NodeInterface $node): bool
@@ -597,4 +602,9 @@ public function NAME(string $key, mixed $value): static
{
return $classType.($hasNormalizationClosures ? '|scalar' : '');
}
private function getParamType(array $types, bool $withParamConfigurator = false): string
{
return \in_array('mixed', $types, true) ? 'mixed' : ($withParamConfigurator ? 'ParamConfigurator|' : '').implode('|', $types);
}
}

View File

@@ -43,5 +43,5 @@ interface ConfigCacheInterface
*
* @throws \RuntimeException When the cache file cannot be written
*/
public function write(string $content, array $metadata = null);
public function write(string $content, ?array $metadata = null);
}

View File

@@ -177,7 +177,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
public function getDefaultValue(): mixed
{
if (!$this->hasDefaultValue()) {
throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
throw new \RuntimeException(\sprintf('The node at path "%s" has no default value.', $this->getPath()));
}
$defaults = [];
@@ -205,7 +205,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
throw new \InvalidArgumentException('Child nodes must be named.');
}
if (isset($this->children[$name])) {
throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name));
throw new \InvalidArgumentException(\sprintf('A child node named "%s" already exists.', $name));
}
$this->children[$name] = $node;
@@ -218,15 +218,15 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
protected function finalizeValue(mixed $value): mixed
{
if (false === $value) {
throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value)));
throw new UnsetKeyException(\sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value)));
}
foreach ($this->children as $name => $child) {
if (!\array_key_exists($name, $value)) {
if ($child->isRequired()) {
$message = sprintf('The child config "%s" under "%s" must be configured', $name, $this->getPath());
$message = \sprintf('The child config "%s" under "%s" must be configured', $name, $this->getPath());
if ($child->getInfo()) {
$message .= sprintf(': %s', $child->getInfo());
$message .= \sprintf(': %s', $child->getInfo());
} else {
$message .= '.';
}
@@ -264,7 +264,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
protected function validateType(mixed $value)
{
if (!\is_array($value) && (!$this->allowFalse || false !== $value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "array", but got "%s"', $this->getPath(), get_debug_type($value)));
$ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "array", but got "%s"', $this->getPath(), get_debug_type($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
@@ -315,13 +315,13 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
}
}
$msg = sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath());
$msg = \sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath());
if (\count($guesses)) {
asort($guesses);
$msg .= sprintf('. Did you mean "%s"?', implode('", "', array_keys($guesses)));
$msg .= \sprintf('. Did you mean "%s"?', implode('", "', array_keys($guesses)));
} else {
$msg .= sprintf('. Available option%s %s "%s".', 1 === \count($proposals) ? '' : 's', 1 === \count($proposals) ? 'is' : 'are', implode('", "', $proposals));
$msg .= \sprintf('. Available option%s %s "%s".', 1 === \count($proposals) ? '' : 's', 1 === \count($proposals) ? 'is' : 'are', implode('", "', $proposals));
}
$ex = new InvalidConfigurationException($msg);
@@ -370,7 +370,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
// no conflict
if (!\array_key_exists($k, $leftSide)) {
if (!$this->allowNewKeys) {
$ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file. If you are trying to overwrite an element, make sure you redefine it with the same name.', $this->getPath()));
$ex = new InvalidConfigurationException(\sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file. If you are trying to overwrite an element, make sure you redefine it with the same name.', $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;

View File

@@ -46,7 +46,7 @@ abstract class BaseNode implements NodeInterface
/**
* @throws \InvalidArgumentException if the name contains a period
*/
public function __construct(?string $name, NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR)
public function __construct(?string $name, ?NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR)
{
if (str_contains($name = (string) $name, $pathSeparator)) {
throw new \InvalidArgumentException('The name must not contain ".'.$pathSeparator.'".');
@@ -313,7 +313,7 @@ abstract class BaseNode implements NodeInterface
final public function merge(mixed $leftSide, mixed $rightSide): mixed
{
if (!$this->allowOverwrite) {
throw new ForbiddenOverwriteException(sprintf('Configuration path "%s" cannot be overwritten. You have to define all options for this path, and any of its sub-paths in one configuration section.', $this->getPath()));
throw new ForbiddenOverwriteException(\sprintf('Configuration path "%s" cannot be overwritten. You have to define all options for this path, and any of its sub-paths in one configuration section.', $this->getPath()));
}
if ($leftSide !== $leftPlaceholders = self::resolvePlaceholderValue($leftSide)) {
@@ -432,7 +432,7 @@ abstract class BaseNode implements NodeInterface
throw $e;
} catch (\Exception $e) {
throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": ', $this->getPath()).$e->getMessage(), $e->getCode(), $e);
throw new InvalidConfigurationException(\sprintf('Invalid configuration for path "%s": ', $this->getPath()).$e->getMessage(), $e->getCode(), $e);
}
}
@@ -507,7 +507,7 @@ abstract class BaseNode implements NodeInterface
private function doValidateType(mixed $value): void
{
if (null !== $this->handlingPlaceholder && !$this->allowPlaceholders()) {
$e = new InvalidTypeException(sprintf('A dynamic value is not compatible with a "%s" node type at path "%s".', static::class, $this->getPath()));
$e = new InvalidTypeException(\sprintf('A dynamic value is not compatible with a "%s" node type at path "%s".', static::class, $this->getPath()));
$e->setPath($this->getPath());
throw $e;
@@ -523,7 +523,7 @@ abstract class BaseNode implements NodeInterface
$validTypes = $this->getValidPlaceholderTypes();
if ($validTypes && array_diff($knownTypes, $validTypes)) {
$e = new InvalidTypeException(sprintf(
$e = new InvalidTypeException(\sprintf(
'Invalid type for path "%s". Expected %s, but got %s.',
$this->getPath(),
1 === \count($validTypes) ? '"'.reset($validTypes).'"' : 'one of "'.implode('", "', $validTypes).'"',

View File

@@ -26,7 +26,7 @@ class BooleanNode extends ScalarNode
protected function validateType(mixed $value)
{
if (!\is_bool($value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "bool", but got "%s".', $this->getPath(), get_debug_type($value)));
$ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "bool", but got "%s".', $this->getPath(), get_debug_type($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}

View File

@@ -37,7 +37,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
protected $nodeBuilder;
protected $normalizeKeys = true;
public function __construct(?string $name, NodeParentInterface $parent = null)
public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
@@ -126,7 +126,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
*
* @return $this
*/
public function addDefaultChildrenIfNoneSet(int|string|array $children = null): static
public function addDefaultChildrenIfNoneSet(int|string|array|null $children = null): static
{
$this->addDefaultChildren = $children;
@@ -169,7 +169,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
*
* @return $this
*/
public function fixXmlConfig(string $singular, string $plural = null): static
public function fixXmlConfig(string $singular, ?string $plural = null): static
{
$this->normalization()->remap($singular, $plural);
@@ -331,7 +331,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
public function append(NodeDefinition $node): static
{
$this->children[$node->name] = $node->setParent($this);
$this->children[$node->name ?? ''] = $node->setParent($this);
return $this;
}
@@ -374,7 +374,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
if ($this->default) {
if (!\is_array($this->defaultValue)) {
throw new \InvalidArgumentException(sprintf('%s: the default value of an array node has to be an array.', $node->getPath()));
throw new \InvalidArgumentException(\sprintf('%s: the default value of an array node has to be an array.', $node->getPath()));
}
$node->setDefaultValue($this->defaultValue);
@@ -434,23 +434,23 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
$path = $node->getPath();
if (null !== $this->key) {
throw new InvalidDefinitionException(sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s".', $path));
}
if (false === $this->allowEmptyValue) {
throw new InvalidDefinitionException(sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s".', $path));
}
if (true === $this->atLeastOne) {
throw new InvalidDefinitionException(sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s".', $path));
}
if ($this->default) {
throw new InvalidDefinitionException(sprintf('->defaultValue() is not applicable to concrete nodes at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->defaultValue() is not applicable to concrete nodes at path "%s".', $path));
}
if (false !== $this->addDefaultChildren) {
throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s".', $path));
}
}
@@ -466,20 +466,20 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
$path = $node->getPath();
if ($this->addDefaults) {
throw new InvalidDefinitionException(sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s".', $path));
}
if (false !== $this->addDefaultChildren) {
if ($this->default) {
throw new InvalidDefinitionException(sprintf('A default value and default children might not be used together at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('A default value and default children might not be used together at path "%s".', $path));
}
if (null !== $this->key && (null === $this->addDefaultChildren || \is_int($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s".', $path));
}
if (null === $this->key && (\is_string($this->addDefaultChildren) || \is_array($this->addDefaultChildren))) {
throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s".', $path));
throw new InvalidDefinitionException(\sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s".', $path));
}
}
}
@@ -504,7 +504,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
: substr($nodePath, 0, $pathSeparatorPos);
if (null === $node = ($this->children[$firstPathSegment] ?? null)) {
throw new \RuntimeException(sprintf('Node with name "%s" does not exist in the current node "%s".', $firstPathSegment, $this->name));
throw new \RuntimeException(\sprintf('Node with name "%s" does not exist in the current node "%s".', $firstPathSegment, $this->name));
}
if (false === $pathSeparatorPos) {

View File

@@ -21,7 +21,7 @@ use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
*/
class BooleanNodeDefinition extends ScalarNodeDefinition
{
public function __construct(?string $name, NodeParentInterface $parent = null)
public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);

View File

@@ -42,7 +42,7 @@ class ExprBuilder
*
* @return $this
*/
public function always(\Closure $then = null): static
public function always(?\Closure $then = null): static
{
$this->ifPart = static fn () => true;
$this->allowedTypes = self::TYPE_ANY;
@@ -61,7 +61,7 @@ class ExprBuilder
*
* @return $this
*/
public function ifTrue(\Closure $closure = null): static
public function ifTrue(?\Closure $closure = null): static
{
$this->ifPart = $closure ?? static fn ($v) => true === $v;
$this->allowedTypes = self::TYPE_ANY;
@@ -196,7 +196,7 @@ class ExprBuilder
*/
public function thenInvalid(string $message): static
{
$this->thenPart = static fn ($v) => throw new \InvalidArgumentException(sprintf($message, json_encode($v)));
$this->thenPart = static fn ($v) => throw new \InvalidArgumentException(\sprintf($message, json_encode($v)));
return $this;
}

View File

@@ -39,7 +39,7 @@ class NodeBuilder implements NodeParentInterface
*
* @return $this
*/
public function setParent(ParentNodeDefinitionInterface $parent = null): static
public function setParent(?ParentNodeDefinitionInterface $parent = null): static
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/form', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
@@ -190,13 +190,13 @@ class NodeBuilder implements NodeParentInterface
$type = strtolower($type);
if (!isset($this->nodeMapping[$type])) {
throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
throw new \RuntimeException(\sprintf('The node type "%s" is not registered.', $type));
}
$class = $this->nodeMapping[$type];
if (!class_exists($class)) {
throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
throw new \RuntimeException(\sprintf('The node class "%s" does not exist.', $class));
}
return $class;

View File

@@ -38,7 +38,7 @@ abstract class NodeDefinition implements NodeParentInterface
protected $parent;
protected $attributes = [];
public function __construct(?string $name, NodeParentInterface $parent = null)
public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
$this->parent = $parent;
$this->name = $name;

View File

@@ -36,7 +36,7 @@ class NormalizationBuilder
*
* @return $this
*/
public function remap(string $key, string $plural = null): static
public function remap(string $key, ?string $plural = null): static
{
$this->remappings[] = [$key, null === $plural ? $key.'s' : $plural];
@@ -48,7 +48,7 @@ class NormalizationBuilder
*
* @return ExprBuilder|$this
*/
public function before(\Closure $closure = null): ExprBuilder|static
public function before(?\Closure $closure = null): ExprBuilder|static
{
if (null !== $closure) {
$this->before[] = $closure;

View File

@@ -33,7 +33,7 @@ abstract class NumericNodeDefinition extends ScalarNodeDefinition
public function max(int|float $max): static
{
if (isset($this->min) && $this->min > $max) {
throw new \InvalidArgumentException(sprintf('You cannot define a max(%s) as you already have a min(%s).', $max, $this->min));
throw new \InvalidArgumentException(\sprintf('You cannot define a max(%s) as you already have a min(%s).', $max, $this->min));
}
$this->max = $max;
@@ -50,7 +50,7 @@ abstract class NumericNodeDefinition extends ScalarNodeDefinition
public function min(int|float $min): static
{
if (isset($this->max) && $this->max < $min) {
throw new \InvalidArgumentException(sprintf('You cannot define a min(%s) as you already have a max(%s).', $min, $this->max));
throw new \InvalidArgumentException(\sprintf('You cannot define a min(%s) as you already have a max(%s).', $min, $this->max));
}
$this->min = $min;

View File

@@ -30,7 +30,7 @@ class TreeBuilder implements NodeParentInterface
*/
protected $root;
public function __construct(string $name, string $type = 'array', NodeBuilder $builder = null)
public function __construct(string $name, string $type = 'array', ?NodeBuilder $builder = null)
{
$builder ??= new NodeBuilder();
$this->root = $builder->node($name, $type)->setParent($this);

View File

@@ -31,7 +31,7 @@ class ValidationBuilder
*
* @return ExprBuilder|$this
*/
public function rule(\Closure $closure = null): ExprBuilder|static
public function rule(?\Closure $closure = null): ExprBuilder|static
{
if (null !== $closure) {
$this->rules[] = $closure;

View File

@@ -29,7 +29,7 @@ class DefinitionConfigurator
) {
}
public function import(string $resource, string $type = null, bool $ignoreErrors = false): void
public function import(string $resource, ?string $type = null, bool $ignoreErrors = false): void
{
$this->loader->setCurrentDir(\dirname($this->path));
$this->loader->import($resource, $type, $ignoreErrors, $this->file);

View File

@@ -34,7 +34,7 @@ class XmlReferenceDumper
/**
* @return string
*/
public function dump(ConfigurationInterface $configuration, string $namespace = null)
public function dump(ConfigurationInterface $configuration, ?string $namespace = null)
{
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
}
@@ -42,7 +42,7 @@ class XmlReferenceDumper
/**
* @return string
*/
public function dumpNode(NodeInterface $node, string $namespace = null)
public function dumpNode(NodeInterface $node, ?string $namespace = null)
{
$this->reference = '';
$this->writeNode($node, 0, true, $namespace);
@@ -52,7 +52,7 @@ class XmlReferenceDumper
return $ref;
}
private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, string $namespace = null): void
private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, ?string $namespace = null): void
{
$rootName = ($root ? 'config' : $node->getName());
$rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
@@ -151,7 +151,7 @@ class XmlReferenceDumper
if ($child instanceof BaseNode && $child->isDeprecated()) {
$deprecation = $child->getDeprecation($child->getName(), $node->getPath());
$comments[] = sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']);
$comments[] = \sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']);
}
if ($child instanceof EnumNode) {
@@ -205,7 +205,7 @@ class XmlReferenceDumper
$rootOpenTag = '<'.$rootName;
if (1 >= ($attributesCount = \count($rootAttributes))) {
if (1 === $attributesCount) {
$rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
$rootOpenTag .= \sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
}
$rootOpenTag .= $rootIsEmptyTag ? ' />' : '>';
@@ -221,7 +221,7 @@ class XmlReferenceDumper
$i = 1;
foreach ($rootAttributes as $attrName => $attrValue) {
$attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
$attr = \sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
$this->writeLine($attr, $depth + 4);
@@ -258,7 +258,7 @@ class XmlReferenceDumper
$indent = \strlen($text) + $indent;
$format = '%'.$indent.'s';
$this->reference .= sprintf($format, $text).\PHP_EOL;
$this->reference .= \sprintf($format, $text).\PHP_EOL;
}
/**

View File

@@ -18,7 +18,6 @@ use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\NodeInterface;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
use Symfony\Component\Config\Definition\ScalarNode;
use Symfony\Component\Config\Definition\VariableNode;
use Symfony\Component\Yaml\Inline;
/**
@@ -47,7 +46,7 @@ class YamlReferenceDumper
foreach (explode('.', $path) as $step) {
if (!$node instanceof ArrayNode) {
throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path));
throw new \UnexpectedValueException(\sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path));
}
/** @var NodeInterface[] $children */
@@ -61,7 +60,7 @@ class YamlReferenceDumper
}
}
throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path));
throw new \UnexpectedValueException(\sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path));
}
return $this->dumpNode($node);
@@ -80,7 +79,7 @@ class YamlReferenceDumper
return $ref;
}
private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void
private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void
{
$comments = [];
$default = '';
@@ -99,19 +98,12 @@ class YamlReferenceDumper
$children = $this->getPrototypeChildren($node);
}
if (!$children) {
if ($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue())) {
$default = '';
} elseif (!\is_array($example)) {
$default = '[]';
}
if (!$children && !($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue()))) {
$default = '[]';
}
} elseif ($node instanceof EnumNode) {
$comments[] = 'One of '.$node->getPermissibleValues('; ');
$default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~';
} elseif (VariableNode::class === $node::class && \is_array($example)) {
// If there is an array example, we are sure we dont need to print a default value
$default = '';
} else {
$default = '~';
@@ -138,7 +130,7 @@ class YamlReferenceDumper
// deprecated?
if ($node instanceof BaseNode && $node->isDeprecated()) {
$deprecation = $node->getDeprecation($node->getName(), $parentNode ? $parentNode->getPath() : $node->getPath());
$comments[] = sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']);
$comments[] = \sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']);
}
// example
@@ -150,12 +142,12 @@ class YamlReferenceDumper
$comments = \count($comments) ? '# '.implode(', ', $comments) : '';
$key = $prototypedArray ? '-' : $node->getName().':';
$text = rtrim(sprintf('%-21s%s %s', $key, $default, $comments), ' ');
$text = rtrim(\sprintf('%-21s%s %s', $key, $default, $comments), ' ');
if ($node instanceof BaseNode && $info = $node->getInfo()) {
$this->writeLine('');
// indenting multi-line info
$info = str_replace("\n", sprintf("\n%".($depth * 4).'s# ', ' '), $info);
$info = str_replace("\n", \sprintf("\n%".($depth * 4).'s# ', ' '), $info);
$this->writeLine('# '.$info, $depth * 4);
}
@@ -179,7 +171,7 @@ class YamlReferenceDumper
$this->writeLine('# '.$message.':', $depth * 4 + 4);
$this->writeArray(array_map(Inline::dump(...), $example), $depth + 1);
$this->writeArray(array_map(Inline::dump(...), $example), $depth + 1, true);
}
if ($children) {
@@ -197,10 +189,10 @@ class YamlReferenceDumper
$indent = \strlen($text) + $indent;
$format = '%'.$indent.'s';
$this->reference .= sprintf($format, $text)."\n";
$this->reference .= \sprintf($format, $text)."\n";
}
private function writeArray(array $array, int $depth): void
private function writeArray(array $array, int $depth, bool $asComment = false): void
{
$isIndexed = array_is_list($array);
@@ -211,14 +203,16 @@ class YamlReferenceDumper
$val = $value;
}
$prefix = $asComment ? '# ' : '';
if ($isIndexed) {
$this->writeLine('- '.$val, $depth * 4);
$this->writeLine($prefix.'- '.$val, $depth * 4);
} else {
$this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
$this->writeLine(\sprintf('%s%-20s %s', $prefix, $key.':', $val), $depth * 4);
}
if (\is_array($value)) {
$this->writeArray($value, $depth + 1);
$this->writeArray($value, $depth + 1, $asComment);
}
}
}
@@ -255,6 +249,6 @@ class YamlReferenceDumper
}
$keyNode->setInfo($info);
return [$key => $keyNode];
return [$key ?? '' => $keyNode];
}
}

View File

@@ -22,7 +22,7 @@ class EnumNode extends ScalarNode
{
private array $values;
public function __construct(?string $name, NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
public function __construct(?string $name, ?NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
if (!$values) {
throw new \InvalidArgumentException('$values must contain at least one element.');
@@ -34,11 +34,11 @@ class EnumNode extends ScalarNode
}
if (!$value instanceof \UnitEnum) {
throw new \InvalidArgumentException(sprintf('"%s" only supports scalar, enum, or null values, "%s" given.', __CLASS__, get_debug_type($value)));
throw new \InvalidArgumentException(\sprintf('"%s" only supports scalar, enum, or null values, "%s" given.', __CLASS__, get_debug_type($value)));
}
if ($value::class !== ($enumClass ??= $value::class)) {
throw new \InvalidArgumentException(sprintf('"%s" only supports one type of enum, "%s" and "%s" passed.', __CLASS__, $enumClass, $value::class));
throw new \InvalidArgumentException(\sprintf('"%s" only supports one type of enum, "%s" and "%s" passed.', __CLASS__, $enumClass, $value::class));
}
}
@@ -85,7 +85,7 @@ class EnumNode extends ScalarNode
$value = parent::finalizeValue($value);
if (!\in_array($value, $this->values, true)) {
$ex = new InvalidConfigurationException(sprintf('The value %s is not allowed for path "%s". Permissible values: %s', json_encode($value), $this->getPath(), $this->getPermissibleValues(', ')));
$ex = new InvalidConfigurationException(\sprintf('The value %s is not allowed for path "%s". Permissible values: %s', json_encode($value), $this->getPath(), $this->getPermissibleValues(', ')));
$ex->setPath($this->getPath());
throw $ex;

View File

@@ -31,7 +31,7 @@ class FloatNode extends NumericNode
}
if (!\is_float($value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "float", but got "%s".', $this->getPath(), get_debug_type($value)));
$ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "float", but got "%s".', $this->getPath(), get_debug_type($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}

View File

@@ -26,7 +26,7 @@ class IntegerNode extends NumericNode
protected function validateType(mixed $value)
{
if (!\is_int($value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "int", but got "%s".', $this->getPath(), get_debug_type($value)));
$ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "int", but got "%s".', $this->getPath(), get_debug_type($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}

View File

@@ -34,7 +34,7 @@ class DefinitionFileLoader extends FileLoader
parent::__construct($locator);
}
public function load(mixed $resource, string $type = null): mixed
public function load(mixed $resource, ?string $type = null): mixed
{
// the loader variable is exposed to the included file below
$loader = $this;
@@ -57,7 +57,7 @@ class DefinitionFileLoader extends FileLoader
return null;
}
public function supports(mixed $resource, string $type = null): bool
public function supports(mixed $resource, ?string $type = null): bool
{
if (!\is_string($resource)) {
return false;
@@ -81,7 +81,7 @@ class DefinitionFileLoader extends FileLoader
$reflectionType = $parameter->getType();
if (!$reflectionType instanceof \ReflectionNamedType) {
throw new \InvalidArgumentException(sprintf('Could not resolve argument "$%s" for "%s". You must typehint it (for example with "%s").', $parameter->getName(), $path, DefinitionConfigurator::class));
throw new \InvalidArgumentException(\sprintf('Could not resolve argument "$%s" for "%s". You must typehint it (for example with "%s").', $parameter->getName(), $path, DefinitionConfigurator::class));
}
$arguments[] = match ($reflectionType->getName()) {

View File

@@ -23,7 +23,7 @@ class NumericNode extends ScalarNode
protected $min;
protected $max;
public function __construct(?string $name, NodeInterface $parent = null, int|float $min = null, int|float $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
public function __construct(?string $name, ?NodeInterface $parent = null, int|float|null $min = null, int|float|null $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
parent::__construct($name, $parent, $pathSeparator);
$this->min = $min;
@@ -36,10 +36,10 @@ class NumericNode extends ScalarNode
$errorMsg = null;
if (isset($this->min) && $value < $this->min) {
$errorMsg = sprintf('The value %s is too small for path "%s". Should be greater than or equal to %s', $value, $this->getPath(), $this->min);
$errorMsg = \sprintf('The value %s is too small for path "%s". Should be greater than or equal to %s', $value, $this->getPath(), $this->min);
}
if (isset($this->max) && $value > $this->max) {
$errorMsg = sprintf('The value %s is too big for path "%s". Should be less than or equal to %s', $value, $this->getPath(), $this->max);
$errorMsg = \sprintf('The value %s is too big for path "%s". Should be less than or equal to %s', $value, $this->getPath(), $this->max);
}
if (isset($errorMsg)) {
$ex = new InvalidConfigurationException($errorMsg);

View File

@@ -67,7 +67,7 @@ class Processor
* @param string $key The key to normalize
* @param string|null $plural The plural form of the key if it is irregular
*/
public static function normalizeConfig(array $config, string $key, string $plural = null): array
public static function normalizeConfig(array $config, string $key, ?string $plural = null): array
{
$plural ??= $key.'s';

View File

@@ -168,7 +168,7 @@ class PrototypedArrayNode extends ArrayNode
protected function finalizeValue(mixed $value): mixed
{
if (false === $value) {
throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value)));
throw new UnsetKeyException(\sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value)));
}
foreach ($value as $k => $v) {
@@ -181,7 +181,7 @@ class PrototypedArrayNode extends ArrayNode
}
if (\count($value) < $this->minNumberOfElements) {
$ex = new InvalidConfigurationException(sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements));
$ex = new InvalidConfigurationException(\sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements));
$ex->setPath($this->getPath());
throw $ex;
@@ -206,7 +206,7 @@ class PrototypedArrayNode extends ArrayNode
foreach ($value as $k => $v) {
if (null !== $this->keyAttribute && \is_array($v)) {
if (!isset($v[$this->keyAttribute]) && \is_int($k) && $isList) {
$ex = new InvalidConfigurationException(sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath()));
$ex = new InvalidConfigurationException(\sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
@@ -239,7 +239,7 @@ class PrototypedArrayNode extends ArrayNode
}
if (\array_key_exists($k, $normalized)) {
$ex = new DuplicateKeyException(sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath()));
$ex = new DuplicateKeyException(\sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
@@ -280,7 +280,7 @@ class PrototypedArrayNode extends ArrayNode
// no conflict
if (!\array_key_exists($k, $leftSide)) {
if (!$this->allowNewKeys) {
$ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file.', $this->getPath()));
$ex = new InvalidConfigurationException(\sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file.', $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;

View File

@@ -33,7 +33,7 @@ class ScalarNode extends VariableNode
protected function validateType(mixed $value)
{
if (!\is_scalar($value) && null !== $value) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "scalar", but got "%s".', $this->getPath(), get_debug_type($value)));
$ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "scalar", but got "%s".', $this->getPath(), get_debug_type($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}

View File

@@ -80,7 +80,7 @@ class VariableNode extends BaseNode implements PrototypeNodeInterface
// deny environment variables only when using custom validators
// this avoids ever passing an empty value to final validation closures
if (!$this->allowEmptyValue && $this->isHandlingPlaceholder() && $this->finalValidationClosures) {
$e = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an environment variable when empty values are not allowed by definition and are validated.', $this->getPath()));
$e = new InvalidConfigurationException(\sprintf('The path "%s" cannot contain an environment variable when empty values are not allowed by definition and are validated.', $this->getPath()));
if ($hint = $this->getInfo()) {
$e->addHint($hint);
}
@@ -90,7 +90,7 @@ class VariableNode extends BaseNode implements PrototypeNodeInterface
}
if (!$this->allowEmptyValue && $this->isValueEmpty($value)) {
$ex = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value)));
$ex = new InvalidConfigurationException(\sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}

View File

@@ -18,9 +18,9 @@ namespace Symfony\Component\Config\Exception;
*/
class FileLoaderImportCircularReferenceException extends LoaderLoadException
{
public function __construct(array $resources, int $code = 0, \Throwable $previous = null)
public function __construct(array $resources, int $code = 0, ?\Throwable $previous = null)
{
$message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
$message = \sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
\Exception::__construct($message, $code, $previous);
}

View File

@@ -20,7 +20,7 @@ class FileLocatorFileNotFoundException extends \InvalidArgumentException
{
private array $paths;
public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, array $paths = [])
public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, array $paths = [])
{
parent::__construct($message, $code, $previous);

View File

@@ -25,13 +25,13 @@ class LoaderLoadException extends \Exception
* @param \Throwable|null $previous A previous exception
* @param string|null $type The type of resource
*/
public function __construct(mixed $resource, string $sourceResource = null, int $code = 0, \Throwable $previous = null, string $type = null)
public function __construct(mixed $resource, ?string $sourceResource = null, int $code = 0, ?\Throwable $previous = null, ?string $type = null)
{
if (!\is_string($resource)) {
try {
$resource = json_encode($resource, \JSON_THROW_ON_ERROR);
} catch (\JsonException) {
$resource = sprintf('resource of type "%s"', get_debug_type($resource));
$resource = \sprintf('resource of type "%s"', get_debug_type($resource));
}
}
@@ -42,35 +42,35 @@ class LoaderLoadException extends \Exception
// Trim the trailing period of the previous message. We only want 1 period remove so no rtrim...
if (str_ends_with($previous->getMessage(), '.')) {
$trimmedMessage = substr($previous->getMessage(), 0, -1);
$message .= sprintf('%s', $trimmedMessage).' in ';
$message .= \sprintf('%s', $trimmedMessage).' in ';
} else {
$message .= sprintf('%s', $previous->getMessage()).' in ';
$message .= \sprintf('%s', $previous->getMessage()).' in ';
}
$message .= $resource.' ';
// show tweaked trace to complete the human readable sentence
if (null === $sourceResource) {
$message .= sprintf('(which is loaded in resource "%s")', $resource);
$message .= \sprintf('(which is loaded in resource "%s")', $resource);
} else {
$message .= sprintf('(which is being imported from "%s")', $sourceResource);
$message .= \sprintf('(which is being imported from "%s")', $sourceResource);
}
$message .= '.';
// if there's no previous message, present it the default way
} elseif (null === $sourceResource) {
$message .= sprintf('Cannot load resource "%s".', $resource);
$message .= \sprintf('Cannot load resource "%s".', $resource);
} else {
$message .= sprintf('Cannot import resource "%s" from "%s".', $resource, $sourceResource);
$message .= \sprintf('Cannot import resource "%s" from "%s".', $resource, $sourceResource);
}
// Is the resource located inside a bundle?
if ('@' === $resource[0]) {
$parts = explode(\DIRECTORY_SEPARATOR, $resource);
$bundle = substr($parts[0], 1);
$message .= sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
$message .= sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource);
$message .= \sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
$message .= \sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource);
} elseif (null !== $type) {
$message .= sprintf(' Make sure there is a loader supporting the "%s" type.', $type);
$message .= \sprintf(' Make sure there is a loader supporting the "%s" type.', $type);
}
parent::__construct($message, $code, $previous);
@@ -82,20 +82,20 @@ class LoaderLoadException extends \Exception
protected function varToString(mixed $var)
{
if (\is_object($var)) {
return sprintf('Object(%s)', $var::class);
return \sprintf('Object(%s)', $var::class);
}
if (\is_array($var)) {
$a = [];
foreach ($var as $k => $v) {
$a[] = sprintf('%s => %s', $k, $this->varToString($v));
$a[] = \sprintf('%s => %s', $k, $this->varToString($v));
}
return sprintf('Array(%s)', implode(', ', $a));
return \sprintf('Array(%s)', implode(', ', $a));
}
if (\is_resource($var)) {
return sprintf('Resource(%s)', get_resource_type($var));
return \sprintf('Resource(%s)', get_resource_type($var));
}
if (null === $var) {

View File

@@ -31,9 +31,11 @@ class FileLocator implements FileLocatorInterface
}
/**
* @return string|array
* @return string|string[]
*
* @psalm-return ($first is true ? string : string[])
*/
public function locate(string $name, string $currentPath = null, bool $first = true)
public function locate(string $name, ?string $currentPath = null, bool $first = true)
{
if ('' === $name) {
throw new \InvalidArgumentException('An empty file name is not valid to be located.');
@@ -41,7 +43,7 @@ class FileLocator implements FileLocatorInterface
if ($this->isAbsolutePath($name)) {
if (!file_exists($name)) {
throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist.', $name), 0, null, [$name]);
throw new FileLocatorFileNotFoundException(\sprintf('The file "%s" does not exist.', $name), 0, null, [$name]);
}
return $name;
@@ -68,7 +70,7 @@ class FileLocator implements FileLocatorInterface
}
if (!$filepaths) {
throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist (in: "%s").', $name, implode('", "', $paths)), 0, null, $notfound);
throw new FileLocatorFileNotFoundException(\sprintf('The file "%s" does not exist (in: "%s").', $name, implode('", "', $paths)), 0, null, $notfound);
}
return $filepaths;
@@ -84,7 +86,8 @@ class FileLocator implements FileLocatorInterface
&& ':' === $file[1]
&& ('\\' === $file[2] || '/' === $file[2])
)
|| null !== parse_url($file, \PHP_URL_SCHEME)
|| parse_url($file, \PHP_URL_SCHEME)
|| str_starts_with($file, 'phar:///') // "parse_url()" doesn't handle absolute phar path, despite being valid
) {
return true;
}

View File

@@ -25,10 +25,12 @@ interface FileLocatorInterface
* @param string|null $currentPath The current path
* @param bool $first Whether to return the first occurrence or an array of filenames
*
* @return string|array The full path to the file or an array of file paths
* @return string|string[] The full path to the file or an array of file paths
*
* @psalm-return ($first is true ? string : string[])
*
* @throws \InvalidArgumentException If $name is empty
* @throws FileLocatorFileNotFoundException If a file is not found
*/
public function locate(string $name, string $currentPath = null, bool $first = true);
public function locate(string $name, ?string $currentPath = null, bool $first = true);
}

View File

@@ -28,7 +28,7 @@ class DelegatingLoader extends Loader
$this->resolver = $resolver;
}
public function load(mixed $resource, string $type = null): mixed
public function load(mixed $resource, ?string $type = null): mixed
{
if (false === $loader = $this->resolver->resolve($resource, $type)) {
throw new LoaderLoadException($resource, null, 0, null, $type);
@@ -37,7 +37,7 @@ class DelegatingLoader extends Loader
return $loader->load($resource, $type);
}
public function supports(mixed $resource, string $type = null): bool
public function supports(mixed $resource, ?string $type = null): bool
{
return false !== $this->resolver->resolve($resource, $type);
}

View File

@@ -31,7 +31,7 @@ abstract class FileLoader extends Loader
private ?string $currentDir = null;
public function __construct(FileLocatorInterface $locator, string $env = null)
public function __construct(FileLocatorInterface $locator, ?string $env = null)
{
$this->locator = $locator;
parent::__construct($env);
@@ -70,7 +70,7 @@ abstract class FileLoader extends Loader
* @throws FileLoaderImportCircularReferenceException
* @throws FileLocatorFileNotFoundException
*/
public function import(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null, string|array $exclude = null)
public function import(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null, string|array|null $exclude = null)
{
if (\is_string($resource) && \strlen($resource) !== ($i = strcspn($resource, '*?{[')) && !str_contains($resource, "\n")) {
$excluded = [];
@@ -101,7 +101,7 @@ abstract class FileLoader extends Loader
/**
* @internal
*/
protected function glob(string $pattern, bool $recursive, array|GlobResource &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable
protected function glob(string $pattern, bool $recursive, array|GlobResource|null &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable
{
if (\strlen($pattern) === $i = strcspn($pattern, '*?{[')) {
$prefix = $pattern;
@@ -133,7 +133,7 @@ abstract class FileLoader extends Loader
yield from $resource;
}
private function doImport(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null): mixed
private function doImport(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null): mixed
{
try {
$loader = $this->resolve($resource, $type);

View File

@@ -18,12 +18,12 @@ namespace Symfony\Component\Config\Loader;
*/
class GlobFileLoader extends FileLoader
{
public function load(mixed $resource, string $type = null): mixed
public function load(mixed $resource, ?string $type = null): mixed
{
return $this->import($resource);
}
public function supports(mixed $resource, string $type = null): bool
public function supports(mixed $resource, ?string $type = null): bool
{
return 'glob' === $type;
}

View File

@@ -23,7 +23,7 @@ abstract class Loader implements LoaderInterface
protected $resolver;
protected $env;
public function __construct(string $env = null)
public function __construct(?string $env = null)
{
$this->env = $env;
}
@@ -46,7 +46,7 @@ abstract class Loader implements LoaderInterface
*
* @return mixed
*/
public function import(mixed $resource, string $type = null)
public function import(mixed $resource, ?string $type = null)
{
return $this->resolve($resource, $type)->load($resource, $type);
}
@@ -56,7 +56,7 @@ abstract class Loader implements LoaderInterface
*
* @throws LoaderLoadException If no loader is found
*/
public function resolve(mixed $resource, string $type = null): LoaderInterface
public function resolve(mixed $resource, ?string $type = null): LoaderInterface
{
if ($this->supports($resource, $type)) {
return $this;

View File

@@ -25,7 +25,7 @@ interface LoaderInterface
*
* @throws \Exception If something went wrong
*/
public function load(mixed $resource, string $type = null);
public function load(mixed $resource, ?string $type = null);
/**
* Returns whether this class supports the given resource.
@@ -34,7 +34,7 @@ interface LoaderInterface
*
* @return bool
*/
public function supports(mixed $resource, string $type = null);
public function supports(mixed $resource, ?string $type = null);
/**
* Gets the loader resolver.

View File

@@ -36,7 +36,7 @@ class LoaderResolver implements LoaderResolverInterface
}
}
public function resolve(mixed $resource, string $type = null): LoaderInterface|false
public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource, $type)) {

View File

@@ -23,5 +23,5 @@ interface LoaderResolverInterface
*
* @param string|null $type The resource type or null if unknown
*/
public function resolve(mixed $resource, string $type = null): LoaderInterface|false;
public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false;
}

View File

@@ -34,7 +34,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
* @param string $resource The fully-qualified class name
* @param bool|null $exists Boolean when the existence check has already been done
*/
public function __construct(string $resource, bool $exists = null)
public function __construct(string $resource, ?bool $exists = null)
{
$this->resource = $resource;
if (null !== $exists) {
@@ -101,23 +101,23 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
return $this->exists[0] xor !$exists[0];
}
/**
* @internal
*/
public function __sleep(): array
public function __serialize(): array
{
if (null === $this->exists) {
$this->isFresh(0);
}
return ['resource', 'exists'];
return [
'resource' => $this->resource,
'exists' => $this->exists,
];
}
/**
* @internal
*/
public function __wakeup(): void
public function __unserialize(array $data): void
{
$this->resource = array_shift($data);
$this->exists = array_shift($data);
if (\is_bool($this->exists)) {
$this->exists = [$this->exists, null];
}
@@ -139,7 +139,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
*
* @internal
*/
public static function throwOnRequiredClass(string $class, \Exception $previous = null): void
public static function throwOnRequiredClass(string $class, ?\Exception $previous = null): void
{
// If the passed class is the resource being checked, we shouldn't throw.
if (null === $previous && self::$autoloadedClass === $class) {
@@ -158,10 +158,10 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
throw $previous;
}
$message = sprintf('Class "%s" not found.', $class);
$message = \sprintf('Class "%s" not found.', $class);
if ($class !== (self::$autoloadedClass ?? $class)) {
$message = substr_replace($message, sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0);
$message = substr_replace($message, \sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0);
}
if (null !== $previous) {

View File

@@ -29,13 +29,13 @@ class DirectoryResource implements SelfCheckingResourceInterface
*
* @throws \InvalidArgumentException
*/
public function __construct(string $resource, string $pattern = null)
public function __construct(string $resource, ?string $pattern = null)
{
$resolvedResource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
$this->pattern = $pattern;
if (false === $resolvedResource || !is_dir($resolvedResource)) {
throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $resource));
throw new \InvalidArgumentException(\sprintf('The directory "%s" does not exist.', $resource));
}
$this->resource = $resolvedResource;

View File

@@ -34,7 +34,7 @@ class FileResource implements SelfCheckingResourceInterface
$resolvedResource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
if (false === $resolvedResource) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $resource));
throw new \InvalidArgumentException(\sprintf('The file "%s" does not exist.', $resource));
}
$this->resource = $resolvedResource;

View File

@@ -53,7 +53,7 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface
$this->globBrace = \defined('GLOB_BRACE') ? \GLOB_BRACE : 0;
if (false === $resolvedPrefix) {
throw new \InvalidArgumentException(sprintf('The path "%s" does not exist.', $prefix));
throw new \InvalidArgumentException(\sprintf('The path "%s" does not exist.', $prefix));
}
$this->prefix = $resolvedPrefix;
@@ -77,21 +77,28 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface
return $this->hash === $hash;
}
/**
* @internal
*/
public function __sleep(): array
public function __serialize(): array
{
$this->hash ??= $this->computeHash();
return ['prefix', 'pattern', 'recursive', 'hash', 'forExclusion', 'excludedPrefixes'];
return [
'prefix' => $this->prefix,
'pattern' => $this->pattern,
'recursive' => $this->recursive,
'hash' => $this->hash,
'forExclusion' => $this->forExclusion,
'excludedPrefixes' => $this->excludedPrefixes,
];
}
/**
* @internal
*/
public function __wakeup(): void
public function __unserialize(array $data): void
{
$this->prefix = array_shift($data);
$this->pattern = array_shift($data);
$this->recursive = array_shift($data);
$this->hash = array_shift($data);
$this->forExclusion = array_shift($data);
$this->excludedPrefixes = array_shift($data);
$this->globBrace = \defined('GLOB_BRACE') ? \GLOB_BRACE : 0;
}
@@ -111,7 +118,7 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface
if (class_exists(Finder::class)) {
$regex = Glob::toRegex($pattern);
if ($this->recursive) {
$regex = substr_replace($regex, '(/|$)', -2, 1);
$regex = substr_replace($regex, str_ends_with($pattern, '/') ? '' : '(/|$)', -2, 1);
}
} else {
$regex = null;

View File

@@ -60,17 +60,19 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
return 'reflection.'.$this->className;
}
/**
* @internal
*/
public function __sleep(): array
public function __serialize(): array
{
if (!isset($this->hash)) {
$this->hash = $this->computeHash();
$this->loadFiles($this->classReflector);
}
return ['files', 'className', 'hash'];
return [
'files' => $this->files,
'className' => $this->className,
'excludedVendors' => $this->excludedVendors,
'hash' => $this->hash,
];
}
private function loadFiles(\ReflectionClass $class): void
@@ -123,7 +125,7 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
yield print_r($attributes, true);
$attributes = [];
yield $class->getDocComment();
yield $class->getDocComment() ?: '';
yield (int) $class->isFinal();
yield (int) $class->isAbstract();
@@ -135,6 +137,14 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
yield print_r($class->getConstants(), true);
}
foreach ($class->getReflectionConstants() as $constant) {
foreach ($constant->getAttributes() as $a) {
$attributes[] = [$a->getName(), (string) $a];
}
yield $constant->name.print_r($attributes, true);
$attributes = [];
}
if (!$class->isInterface()) {
$defaults = $class->getDefaultProperties();
@@ -145,7 +155,7 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
yield print_r($attributes, true);
$attributes = [];
yield $p->getDocComment();
yield $p->getDocComment() ?: '';
yield $p->isDefault() ? '<default>' : '';
yield $p->isPublic() ? 'public' : 'protected';
yield $p->isStatic() ? 'static' : '';

View File

@@ -109,7 +109,7 @@ class ResourceCheckerConfigCache implements ConfigCacheInterface
*
* @throws \RuntimeException When cache file can't be written
*/
public function write(string $content, array $metadata = null)
public function write(string $content, ?array $metadata = null)
{
$mode = 0666;
$umask = umask();
@@ -150,7 +150,7 @@ class ResourceCheckerConfigCache implements ConfigCacheInterface
$signalingException = new \UnexpectedValueException();
$prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback');
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) {
if (__FILE__ === $file) {
if (__FILE__ === $file && !\in_array($type, [\E_DEPRECATED, \E_USER_DEPRECATED], true)) {
throw $signalingException;
}

View File

@@ -42,7 +42,7 @@ class XmlUtils
* @throws InvalidXmlException When parsing of XML with schema or callable produces any errors unrelated to the XML parsing itself
* @throws \RuntimeException When DOM extension is missing
*/
public static function parse(string $content, string|callable $schemaOrCallable = null): \DOMDocument
public static function parse(string $content, string|callable|null $schemaOrCallable = null): \DOMDocument
{
if (!\extension_loaded('dom')) {
throw new \LogicException('Extension DOM is required.');
@@ -84,7 +84,7 @@ class XmlUtils
} else {
libxml_use_internal_errors($internalErrors);
throw new XmlParsingException(sprintf('Invalid XSD file: "%s".', $schemaOrCallable));
throw new XmlParsingException(\sprintf('Invalid XSD file: "%s".', $schemaOrCallable));
}
if (!$valid) {
@@ -112,26 +112,26 @@ class XmlUtils
* @throws XmlParsingException When XML parsing returns any errors
* @throws \RuntimeException When DOM extension is missing
*/
public static function loadFile(string $file, string|callable $schemaOrCallable = null): \DOMDocument
public static function loadFile(string $file, string|callable|null $schemaOrCallable = null): \DOMDocument
{
if (!is_file($file)) {
throw new \InvalidArgumentException(sprintf('Resource "%s" is not a file.', $file));
throw new \InvalidArgumentException(\sprintf('Resource "%s" is not a file.', $file));
}
if (!is_readable($file)) {
throw new \InvalidArgumentException(sprintf('File "%s" is not readable.', $file));
throw new \InvalidArgumentException(\sprintf('File "%s" is not readable.', $file));
}
$content = @file_get_contents($file);
if ('' === trim($content)) {
throw new \InvalidArgumentException(sprintf('File "%s" does not contain valid XML, it is empty.', $file));
throw new \InvalidArgumentException(\sprintf('File "%s" does not contain valid XML, it is empty.', $file));
}
try {
return static::parse($content, $schemaOrCallable);
} catch (InvalidXmlException $e) {
throw new XmlParsingException(sprintf('The XML file "%s" is not valid.', $file), 0, $e->getPrevious());
throw new XmlParsingException(\sprintf('The XML file "%s" is not valid.', $file), 0, $e->getPrevious());
}
}
@@ -245,7 +245,7 @@ class XmlUtils
{
$errors = [];
foreach (libxml_get_errors() as $error) {
$errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
$errors[] = \sprintf('[%s %s] %s (in %s - line %d, column %d)',
\LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
$error->code,
trim($error->message),