From a34f6046a6a08c5731f583b0df1107e3bf40502c Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 20 Jan 2026 14:58:18 +0100 Subject: [PATCH 1/7] SplObjectStorage iterates over objects --- tests/PHPStan/Analyser/nsrt/bug-13985.php | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-13985.php diff --git a/tests/PHPStan/Analyser/nsrt/bug-13985.php b/tests/PHPStan/Analyser/nsrt/bug-13985.php new file mode 100644 index 0000000000..0224007d36 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-13985.php @@ -0,0 +1,32 @@ + $value) { + assertType('int', $key); + assertType('object', $value); + } + } +} + +class X {} + +/** + * @param SplObjectStorage $splObjectStorage + * @return void + */ +function genericExample(SplObjectStorage $splObjectStorage): void +{ + foreach ($splObjectStorage as $key => $value) { + assertType('int', $key); + assertType('Bug13985\X', $value); + } + assertType('int', $splObjectStorage->getInfo()); + +} From 4c9cd1f8212f463aec7006c18eb9340a525fe298 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 20 Jan 2026 15:08:50 +0100 Subject: [PATCH 2/7] Revert "Cache ClassReflections" reverts https://github.com/phpstan/phpstan-src/commit/4a143bdda18c535d66ea5afbcea885c7cce63abd --- src/Type/ObjectType.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 3e755bab60..ca75971914 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -1746,10 +1746,10 @@ public function getClassReflection(): ?ClassReflection $classReflection = $reflectionProvider->getClass($this->className); if ($classReflection->isGeneric()) { - return $this->classReflection = $classReflection->withTypes(array_values($classReflection->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes())); + return $classReflection->withTypes(array_values($classReflection->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes())); } - return $this->classReflection = $classReflection; + return $classReflection; } public function getAncestorWithClassName(string $className): ?self From 51123c5a0e282818df9054e0c49f7081c9f45e14 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 20 Jan 2026 15:16:46 +0100 Subject: [PATCH 3/7] Update ObjectType.php --- src/Type/ObjectType.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index ca75971914..3e2960a67c 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -1746,10 +1746,11 @@ public function getClassReflection(): ?ClassReflection $classReflection = $reflectionProvider->getClass($this->className); if ($classReflection->isGeneric()) { + // withTypes creates a new object, don't cache it in $this->classReflection return $classReflection->withTypes(array_values($classReflection->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes())); } - return $classReflection; + return $this->classReflection = $classReflection; } public function getAncestorWithClassName(string $className): ?self From 4e5db05b575d3464e9bd88744ca9507458ca24d2 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 20 Jan 2026 15:16:54 +0100 Subject: [PATCH 4/7] Update ObjectType.php --- src/Type/ObjectType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 3e2960a67c..0e7626426d 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -1746,7 +1746,7 @@ public function getClassReflection(): ?ClassReflection $classReflection = $reflectionProvider->getClass($this->className); if ($classReflection->isGeneric()) { - // withTypes creates a new object, don't cache it in $this->classReflection + // withTypes() creates a new object, don't cache it in $this->classReflection return $classReflection->withTypes(array_values($classReflection->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes())); } From 5e8512f88f0cb9dc91fbd88a299b1adb6dbd1ab2 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 20 Jan 2026 19:13:46 +0100 Subject: [PATCH 5/7] Update ObjectType.php --- src/Type/ObjectType.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 0e7626426d..b69fd0e5d1 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -1746,7 +1746,6 @@ public function getClassReflection(): ?ClassReflection $classReflection = $reflectionProvider->getClass($this->className); if ($classReflection->isGeneric()) { - // withTypes() creates a new object, don't cache it in $this->classReflection return $classReflection->withTypes(array_values($classReflection->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes())); } From e710e76cae237088e6ab2c008ce903f6a5873f64 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 2 Feb 2026 17:00:26 +0100 Subject: [PATCH 6/7] Create bug-4789.php --- tests/PHPStan/Analyser/nsrt/bug-4789.php | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-4789.php diff --git a/tests/PHPStan/Analyser/nsrt/bug-4789.php b/tests/PHPStan/Analyser/nsrt/bug-4789.php new file mode 100644 index 0000000000..ae4aa20bb6 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-4789.php @@ -0,0 +1,11 @@ + Date: Mon, 2 Feb 2026 17:08:33 +0100 Subject: [PATCH 7/7] Update bug-4789.php --- tests/PHPStan/Analyser/nsrt/bug-4789.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/bug-4789.php b/tests/PHPStan/Analyser/nsrt/bug-4789.php index ae4aa20bb6..4f47b1859d 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-4789.php +++ b/tests/PHPStan/Analyser/nsrt/bug-4789.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug4789;