From 4cdc61c2a9199268bf33e25945d650e457c5b9c2 Mon Sep 17 00:00:00 2001 From: Arshid Date: Thu, 28 Aug 2025 09:25:02 +0530 Subject: [PATCH 1/7] Add ArrayKeyExistsNullToEmptyStringRector to fix deprecated null key --- config/set/php85.php | 2 + ...ayKeyExistsNullToEmptyStringRectorTest.php | 28 +++++++ .../Fixture/key_null.php.inc | 11 +++ .../Fixture/key_null_var.php.inc | 11 +++ .../config/configured_rule.php | 13 +++ .../ArrayKeyExistsNullToEmptyStringRector.php | 84 +++++++++++++++++++ src/ValueObject/PhpVersionFeature.php | 6 ++ 7 files changed, 155 insertions(+) create mode 100644 rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/ArrayKeyExistsNullToEmptyStringRectorTest.php create mode 100644 rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null.php.inc create mode 100644 rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc create mode 100644 rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/config/configured_rule.php create mode 100644 rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php diff --git a/config/set/php85.php b/config/set/php85.php index afb09306273..074c18b2af9 100644 --- a/config/set/php85.php +++ b/config/set/php85.php @@ -10,6 +10,7 @@ use Rector\Php85\Rector\ArrayDimFetch\ArrayFirstLastRector; use Rector\Php85\Rector\ClassMethod\NullDebugInfoReturnRector; use Rector\Php85\Rector\Const_\DeprecatedAnnotationToDeprecatedAttributeRector; +use Rector\Php85\Rector\FuncCall\ArrayKeyExistsNullToEmptyStringRector; use Rector\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector; use Rector\Php85\Rector\Switch_\ColonAfterSwitchCaseRector; use Rector\Removing\Rector\FuncCall\RemoveFuncCallArgRector; @@ -32,6 +33,7 @@ NullDebugInfoReturnRector::class, DeprecatedAnnotationToDeprecatedAttributeRector::class, ColonAfterSwitchCaseRector::class, + ArrayKeyExistsNullToEmptyStringRector::class, ] ); diff --git a/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/ArrayKeyExistsNullToEmptyStringRectorTest.php b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/ArrayKeyExistsNullToEmptyStringRectorTest.php new file mode 100644 index 00000000000..99ac55e8f0b --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/ArrayKeyExistsNullToEmptyStringRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null.php.inc b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null.php.inc new file mode 100644 index 00000000000..f20b508d01a --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null.php.inc @@ -0,0 +1,11 @@ + +----- + diff --git a/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc new file mode 100644 index 00000000000..c98ce73ab69 --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc @@ -0,0 +1,11 @@ + +----- + diff --git a/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/config/configured_rule.php b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/config/configured_rule.php new file mode 100644 index 00000000000..d3207f07fa0 --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/config/configured_rule.php @@ -0,0 +1,13 @@ +rule(ArrayKeyExistsNullToEmptyStringRector::class); + + $rectorConfig->phpVersion(PhpVersion::PHP_85); +}; diff --git a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php new file mode 100644 index 00000000000..319cf2a92fb --- /dev/null +++ b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php @@ -0,0 +1,84 @@ +isName($node->name, 'array_key_exists')) { + return null; + } + + $args = $node->getArgs(); + + if (count($args) < 2) { + return null; + } + + $keyExpr = $args[0]->value; + + if ($keyExpr instanceof Coalesce) { + return null; + } + + + if ($keyExpr instanceof String_ && $keyExpr->value === '') { + return null; + } + + if ($this->nodeNameResolver->isName($keyExpr, 'null')) { + $args[0]->value = new String_(''); + return $node; + } + + if (! $keyExpr instanceof Coalesce && ! ($keyExpr instanceof String_ && $keyExpr->value === '')) { + $args[0]->value = new Coalesce($keyExpr, new String_('')); + return $node; + } + + return $node; + } + + public function provideMinPhpVersion(): int + { + return PhpVersionFeature::DEPRECATE_NULL_ARG_IN_ARRAY_KEY_EXISTS_FUNCTION; + } +} diff --git a/src/ValueObject/PhpVersionFeature.php b/src/ValueObject/PhpVersionFeature.php index a37b164c45b..3a0505ef5f6 100644 --- a/src/ValueObject/PhpVersionFeature.php +++ b/src/ValueObject/PhpVersionFeature.php @@ -792,4 +792,10 @@ final class PhpVersionFeature * @var int */ public const COLON_AFTER_SWITCH_CASE = PhpVersion::PHP_85; + + /** + * @see https://wiki.php.net/rfc/deprecations_php_8_5#https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_using_values_null_as_an_array_offset_and_when_calling_array_key_exists + * @var int + */ + public const DEPRECATE_NULL_ARG_IN_ARRAY_KEY_EXISTS_FUNCTION = PhpVersion::PHP_85; } From bff8d54717c83af842dcf36f1fe5fe4ab6869851 Mon Sep 17 00:00:00 2001 From: Arshid Date: Thu, 28 Aug 2025 09:38:47 +0530 Subject: [PATCH 2/7] Add ArrayKeyExistsNullToEmptyStringRector to fix deprecated null key --- .../ArrayKeyExistsNullToEmptyStringRector.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php index 319cf2a92fb..d4636476d95 100644 --- a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php +++ b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php @@ -15,6 +15,10 @@ use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; +/** + * @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_using_values_null_as_an_array_offset_and_when_calling_array_key_exists + * @see \Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\RemoveFinfoBufferContextArgRectorTest + */ final class ArrayKeyExistsNullToEmptyStringRector extends AbstractRector implements MinPhpVersionInterface { public function getRuleDefinition(): RuleDefinition @@ -43,7 +47,12 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node { - if ($node instanceof FuncCall && ! $this->isName($node->name, 'array_key_exists')) { + + if (! $node instanceof FuncCall) { + return null; + } + + if (! $this->isName($node->name, 'array_key_exists')) { return null; } From 830c585340b2efb12d2c16c3943de97cb6dd7baa Mon Sep 17 00:00:00 2001 From: Arshid Date: Thu, 28 Aug 2025 09:45:38 +0530 Subject: [PATCH 3/7] Add ArrayKeyExistsNullToEmptyStringRector to fix deprecated null key --- .../Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php index d4636476d95..460e966bf5e 100644 --- a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php +++ b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php @@ -78,7 +78,7 @@ public function refactor(Node $node): ?Node return $node; } - if (! $keyExpr instanceof Coalesce && ! ($keyExpr instanceof String_ && $keyExpr->value === '')) { + if (! $keyExpr instanceof Coalesce) { $args[0]->value = new Coalesce($keyExpr, new String_('')); return $node; } From 03d8b66bc15ba7461662082919b73b0a8bcc84af Mon Sep 17 00:00:00 2001 From: Arshid Date: Thu, 28 Aug 2025 09:48:41 +0530 Subject: [PATCH 4/7] Add ArrayKeyExistsNullToEmptyStringRector to fix deprecated null key --- .../Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php index 460e966bf5e..a4918ada164 100644 --- a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php +++ b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php @@ -73,7 +73,7 @@ public function refactor(Node $node): ?Node return null; } - if ($this->nodeNameResolver->isName($keyExpr, 'null')) { + if ($this->isName($keyExpr, 'null')) { $args[0]->value = new String_(''); return $node; } From ac7b70fc33a0ecac1f7aa7747f804cd801232645 Mon Sep 17 00:00:00 2001 From: Arshid Date: Thu, 28 Aug 2025 11:07:46 +0530 Subject: [PATCH 5/7] Add ArrayKeyExistsNullToEmptyStringRector to fix deprecated null key --- .../Fixture/key_null_var.php.inc | 2 +- .../ArrayKeyExistsNullToEmptyStringRector.php | 196 ++++++++++++++++-- 2 files changed, 174 insertions(+), 24 deletions(-) diff --git a/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc index c98ce73ab69..68582d1037c 100644 --- a/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc +++ b/rules-tests/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector/Fixture/key_null_var.php.inc @@ -6,6 +6,6 @@ array_key_exists($k, $array); ----- diff --git a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php index a4918ada164..05320b567ca 100644 --- a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php +++ b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php @@ -4,23 +4,57 @@ namespace Rector\Php85\Rector\FuncCall; + + + use PhpParser\Node; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\BinaryOp\Coalesce; +use PhpParser\Node\Arg; +use PhpParser\Node\Expr; +use PhpParser\Node\Expr\Cast\String_ as CastString_; use PhpParser\Node\Expr\FuncCall; +use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\Ternary; +use PhpParser\Node\Identifier; +use PhpParser\Node\Scalar\InterpolatedString; use PhpParser\Node\Scalar\String_; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\FunctionReflection; +use PHPStan\Reflection\Native\ExtendedNativeParameterReflection; +use PHPStan\Reflection\Native\NativeFunctionReflection; +use PHPStan\Reflection\ParametersAcceptor; +use PHPStan\Type\ErrorType; +use PHPStan\Type\MixedType; +use PHPStan\Type\NullType; +use PHPStan\Type\Type; +use PHPStan\Type\UnionType; +use Rector\NodeAnalyzer\ArgsAnalyzer; +use Rector\NodeAnalyzer\PropertyFetchAnalyzer; +use Rector\NodeTypeResolver\Node\AttributeKey; +use Rector\NodeTypeResolver\PHPStan\ParametersAcceptorSelectorVariantsWrapper; +use Rector\PhpParser\Node\Value\ValueResolver; use Rector\Rector\AbstractRector; +use Rector\Reflection\ReflectionResolver; use Rector\ValueObject\PhpVersionFeature; use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; + /** * @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_using_values_null_as_an_array_offset_and_when_calling_array_key_exists * @see \Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\RemoveFinfoBufferContextArgRectorTest */ final class ArrayKeyExistsNullToEmptyStringRector extends AbstractRector implements MinPhpVersionInterface { + public function __construct( + private readonly ReflectionResolver $reflectionResolver, + private readonly ArgsAnalyzer $argsAnalyzer, + private readonly PropertyFetchAnalyzer $propertyFetchAnalyzer, + private readonly ValueResolver $valueResolver + ) { + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -32,7 +66,7 @@ public function getRuleDefinition(): RuleDefinition CODE_SAMPLE , <<<'CODE_SAMPLE' - array_key_exists($key ?? '', $array); + array_key_exists((string)$key, $array); CODE_SAMPLE ), ] @@ -46,48 +80,164 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node { - - - if (! $node instanceof FuncCall) { + if ($node->isFirstClassCallable()) { return null; } - if (! $this->isName($node->name, 'array_key_exists')) { + if (! $this->isName($node, 'array_key_exists')) { return null; } - $args = $node->getArgs(); - - if (count($args) < 2) { + $scope = $node->getAttribute(AttributeKey::SCOPE); + if (! $scope instanceof Scope) { return null; } - $keyExpr = $args[0]->value; + $args = $node->getArgs(); - if ($keyExpr instanceof Coalesce) { - return null; - } - + $classReflection = $scope->getClassReflection(); + $isTrait = $classReflection instanceof ClassReflection && $classReflection->isTrait(); - if ($keyExpr instanceof String_ && $keyExpr->value === '') { + $functionReflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($node); + if (! $functionReflection instanceof FunctionReflection) { return null; } - if ($this->isName($keyExpr, 'null')) { - $args[0]->value = new String_(''); - return $node; - } + $parametersAcceptor = ParametersAcceptorSelectorVariantsWrapper::select($functionReflection, $node, $scope); + $isChanged = false; - if (! $keyExpr instanceof Coalesce) { - $args[0]->value = new Coalesce($keyExpr, new String_('')); + $result = $this->processNullToStrictStringOnNodePosition( + $node, + $args, + 0, + $isTrait, + $scope, + $parametersAcceptor + ); + if ($result instanceof Node) { + $node = $result; + $isChanged = true; + } + + if ($isChanged) { return $node; } - return $node; + return null; } public function provideMinPhpVersion(): int { return PhpVersionFeature::DEPRECATE_NULL_ARG_IN_ARRAY_KEY_EXISTS_FUNCTION; } + /** + * @param Arg[] $args + * @param int|string $position + */ + private function processNullToStrictStringOnNodePosition(FuncCall $funcCall, array $args, $position, bool $isTrait, Scope $scope, ParametersAcceptor $parametersAcceptor) : ?FuncCall + { + if (!isset($args[$position])) { + return null; + } + $argValue = $args[$position]->value; + if ($this->valueResolver->isNull($argValue)) { + $args[$position]->value = new String_(''); + $funcCall->args = $args; + return $funcCall; + } + if ($this->shouldSkipValue($argValue, $scope, $isTrait)) { + return null; + } + $parameter = $parametersAcceptor->getParameters()[$position] ?? null; + if ($parameter instanceof ExtendedNativeParameterReflection && $parameter->getType() instanceof UnionType) { + $parameterType = $parameter->getType(); + if (!$this->isValidUnionType($parameterType)) { + return null; + } + } + if ($argValue instanceof Ternary && !$this->shouldSkipValue($argValue->else, $scope, $isTrait)) { + if ($this->valueResolver->isNull($argValue->else)) { + $argValue->else = new String_(''); + } else { + $argValue->else = new CastString_($argValue->else); + } + $args[$position]->value = $argValue; + $funcCall->args = $args; + return $funcCall; + } + $args[$position]->value = new CastString_($argValue); + $funcCall->args = $args; + return $funcCall; + } + private function shouldSkipValue(Expr $expr, Scope $scope, bool $isTrait) : bool + { + $type = $this->nodeTypeResolver->getType($expr); + if ($type->isString()->yes()) { + return \true; + } + $nativeType = $this->nodeTypeResolver->getNativeType($expr); + if ($nativeType->isString()->yes()) { + return \true; + } + if ($this->shouldSkipType($type)) { + return \true; + } + if ($expr instanceof InterpolatedString) { + return \true; + } + if ($this->isAnErrorType($expr, $nativeType, $scope)) { + return \true; + } + return $this->shouldSkipTrait($expr, $type, $isTrait); + } + private function isValidUnionType(Type $type) : bool + { + if (!$type instanceof UnionType) { + return \false; + } + foreach ($type->getTypes() as $childType) { + if ($childType->isString()->yes()) { + continue; + } + if ($childType->isInteger()->yes()) { + continue; + } + if ($childType->isNull()->yes()) { + continue; + } + return \false; + } + return \true; + } + private function shouldSkipType(Type $type) : bool + { + return !$type instanceof MixedType && !$type->isNull()->yes() && !$this->isValidUnionType($type); + } + private function shouldSkipTrait(Expr $expr, Type $type, bool $isTrait) : bool + { + if (!$type instanceof MixedType) { + return \false; + } + if (!$isTrait) { + return \false; + } + if ($type->isExplicitMixed()) { + return \false; + } + if (!$expr instanceof MethodCall) { + return $this->propertyFetchAnalyzer->isLocalPropertyFetch($expr); + } + return \true; + } + private function isAnErrorType(Expr $expr, Type $type, Scope $scope) : bool + { + if ($type instanceof ErrorType) { + return \true; + } + $parentScope = $scope->getParentScope(); + if ($parentScope instanceof Scope) { + return $parentScope->getType($expr) instanceof ErrorType; + } + return $type instanceof MixedType && !$type->isExplicitMixed() && $type->getSubtractedType() instanceof NullType; + } } From 8a3ad927b88fd2320091788879ef8c0028915882 Mon Sep 17 00:00:00 2001 From: Arshid Date: Thu, 28 Aug 2025 11:11:42 +0530 Subject: [PATCH 6/7] Add ArrayKeyExistsNullToEmptyStringRector to fix deprecated null key --- .../ArrayKeyExistsNullToEmptyStringRector.php | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php index 05320b567ca..b7ec7bc18d6 100644 --- a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php +++ b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php @@ -4,9 +4,6 @@ namespace Rector\Php85\Rector\FuncCall; - - - use PhpParser\Node; use PhpParser\Node\Arg; use PhpParser\Node\Expr; @@ -14,14 +11,12 @@ use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\Ternary; -use PhpParser\Node\Identifier; use PhpParser\Node\Scalar\InterpolatedString; use PhpParser\Node\Scalar\String_; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\Native\ExtendedNativeParameterReflection; -use PHPStan\Reflection\Native\NativeFunctionReflection; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Type\ErrorType; use PHPStan\Type\MixedType; @@ -40,7 +35,6 @@ use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; - /** * @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_using_values_null_as_an_array_offset_and_when_calling_array_key_exists * @see \Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\RemoveFinfoBufferContextArgRectorTest @@ -118,11 +112,11 @@ public function refactor(Node $node): ?Node $node = $result; $isChanged = true; } - + if ($isChanged) { return $node; } - + return null; } @@ -130,13 +124,20 @@ public function provideMinPhpVersion(): int { return PhpVersionFeature::DEPRECATE_NULL_ARG_IN_ARRAY_KEY_EXISTS_FUNCTION; } + /** * @param Arg[] $args * @param int|string $position */ - private function processNullToStrictStringOnNodePosition(FuncCall $funcCall, array $args, $position, bool $isTrait, Scope $scope, ParametersAcceptor $parametersAcceptor) : ?FuncCall - { - if (!isset($args[$position])) { + private function processNullToStrictStringOnNodePosition( + FuncCall $funcCall, + array $args, + $position, + bool $isTrait, + Scope $scope, + ParametersAcceptor $parametersAcceptor + ): ?FuncCall { + if (! isset($args[$position])) { return null; } $argValue = $args[$position]->value; @@ -144,18 +145,18 @@ private function processNullToStrictStringOnNodePosition(FuncCall $funcCall, arr $args[$position]->value = new String_(''); $funcCall->args = $args; return $funcCall; - } + } if ($this->shouldSkipValue($argValue, $scope, $isTrait)) { return null; - } + } $parameter = $parametersAcceptor->getParameters()[$position] ?? null; if ($parameter instanceof ExtendedNativeParameterReflection && $parameter->getType() instanceof UnionType) { $parameterType = $parameter->getType(); - if (!$this->isValidUnionType($parameterType)) { + if (! $this->isValidUnionType($parameterType)) { return null; } } - if ($argValue instanceof Ternary && !$this->shouldSkipValue($argValue->else, $scope, $isTrait)) { + if ($argValue instanceof Ternary && ! $this->shouldSkipValue($argValue->else, $scope, $isTrait)) { if ($this->valueResolver->isNull($argValue->else)) { $argValue->else = new String_(''); } else { @@ -169,7 +170,8 @@ private function processNullToStrictStringOnNodePosition(FuncCall $funcCall, arr $funcCall->args = $args; return $funcCall; } - private function shouldSkipValue(Expr $expr, Scope $scope, bool $isTrait) : bool + + private function shouldSkipValue(Expr $expr, Scope $scope, bool $isTrait): bool { $type = $this->nodeTypeResolver->getType($expr); if ($type->isString()->yes()) { @@ -190,9 +192,10 @@ private function shouldSkipValue(Expr $expr, Scope $scope, bool $isTrait) : bool } return $this->shouldSkipTrait($expr, $type, $isTrait); } - private function isValidUnionType(Type $type) : bool + + private function isValidUnionType(Type $type): bool { - if (!$type instanceof UnionType) { + if (! $type instanceof UnionType) { return \false; } foreach ($type->getTypes() as $childType) { @@ -209,27 +212,31 @@ private function isValidUnionType(Type $type) : bool } return \true; } - private function shouldSkipType(Type $type) : bool + + private function shouldSkipType(Type $type): bool { - return !$type instanceof MixedType && !$type->isNull()->yes() && !$this->isValidUnionType($type); + return ! $type instanceof MixedType && ! $type->isNull() + ->yes() && ! $this->isValidUnionType($type); } - private function shouldSkipTrait(Expr $expr, Type $type, bool $isTrait) : bool + + private function shouldSkipTrait(Expr $expr, Type $type, bool $isTrait): bool { - if (!$type instanceof MixedType) { + if (! $type instanceof MixedType) { return \false; } - if (!$isTrait) { + if (! $isTrait) { return \false; } if ($type->isExplicitMixed()) { return \false; } - if (!$expr instanceof MethodCall) { + if (! $expr instanceof MethodCall) { return $this->propertyFetchAnalyzer->isLocalPropertyFetch($expr); } return \true; } - private function isAnErrorType(Expr $expr, Type $type, Scope $scope) : bool + + private function isAnErrorType(Expr $expr, Type $type, Scope $scope): bool { if ($type instanceof ErrorType) { return \true; @@ -238,6 +245,6 @@ private function isAnErrorType(Expr $expr, Type $type, Scope $scope) : bool if ($parentScope instanceof Scope) { return $parentScope->getType($expr) instanceof ErrorType; } - return $type instanceof MixedType && !$type->isExplicitMixed() && $type->getSubtractedType() instanceof NullType; + return $type instanceof MixedType && ! $type->isExplicitMixed() && $type->getSubtractedType() instanceof NullType; } } From afcd6e1070c05031308b4ff1c845fddb96a1f8aa Mon Sep 17 00:00:00 2001 From: Arshid Date: Thu, 28 Aug 2025 11:17:42 +0530 Subject: [PATCH 7/7] Add ArrayKeyExistsNullToEmptyStringRector to fix deprecated null key --- .../FuncCall/ArrayKeyExistsNullToEmptyStringRector.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php index b7ec7bc18d6..0f7a8faf29e 100644 --- a/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php +++ b/rules/Php85/Rector/FuncCall/ArrayKeyExistsNullToEmptyStringRector.php @@ -23,7 +23,6 @@ use PHPStan\Type\NullType; use PHPStan\Type\Type; use PHPStan\Type\UnionType; -use Rector\NodeAnalyzer\ArgsAnalyzer; use Rector\NodeAnalyzer\PropertyFetchAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\PHPStan\ParametersAcceptorSelectorVariantsWrapper; @@ -43,7 +42,6 @@ final class ArrayKeyExistsNullToEmptyStringRector extends AbstractRector impleme { public function __construct( private readonly ReflectionResolver $reflectionResolver, - private readonly ArgsAnalyzer $argsAnalyzer, private readonly PropertyFetchAnalyzer $propertyFetchAnalyzer, private readonly ValueResolver $valueResolver ) { @@ -74,6 +72,10 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node { + if(!$node instanceof FuncCall){ + return null; + } + if ($node->isFirstClassCallable()) { return null; }