Skip to content

Add @implements to SPL iterator stubs#5672

Open
takaram wants to merge 5 commits into
phpstan:2.1.xfrom
takaram:recursive-iterator-iterator
Open

Add @implements to SPL iterator stubs#5672
takaram wants to merge 5 commits into
phpstan:2.1.xfrom
takaram:recursive-iterator-iterator

Conversation

@takaram
Copy link
Copy Markdown
Contributor

@takaram takaram commented May 16, 2026

This PR adds @implement annotations to the stub of three classes:

  • RecursiveIteratorIterator
  • DirectoryIterator
  • RecursiveDirectoryIterator

Closes phpstan/phpstan#8435

@phpstan-bot
Copy link
Copy Markdown
Collaborator

You've opened the pull request against the latest branch 2.2.x. PHPStan 2.2 is not going to be released for months. If your code is relevant on 2.1.x and you want it to be released sooner, please rebase your pull request and change its target to 2.1.x.

@takaram takaram changed the base branch from 2.2.x to 2.1.x May 16, 2026 09:20
@takaram takaram closed this May 16, 2026
@takaram takaram reopened this May 16, 2026
Comment thread stubs/iterable.stub Outdated
Comment on lines +199 to +201
* @template-covariant TKey
* @template-covariant TValue
* @template TIterator of \RecursiveIterator<TKey, TValue>|\IteratorAggregate<TKey, TValue>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it means that RecursiveIteratorIterator has now three template like

RecursiveIteratorIterator<int, int, IteratorAggregate<int, int>>

if so, it will break code where people used the single-template RecursiveIteratorIterator no ?

Also, this won't be compatible with the stub from psalm
https://github.com/vimeo/psalm/blob/ca151242c84d8962b921bf59c509b49362ce0eec/stubs/CoreGenericIterators.phpstub#L902-L903

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, this introduces a breaking change.
I revised my code.
Probably CI errors are not related I guess...

$this->analyse([__DIR__ . '/data/bug-3425.php'], [
[
'Parameter #1 $iterator of class RecursiveIteratorIterator constructor expects T of IteratorAggregate|RecursiveIterator, Generator<int, int, mixed, void> given.',
'Parameter #1 $iterator of class RecursiveIteratorIterator constructor expects TIterator of IteratorAggregate|RecursiveIterator, Generator<int, int, mixed, void> given.',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can avoid this change by not renaming the template from T to TIterator

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Fixed.

`DirectoryIterator::current()` itself always returns `DirectoryIterator`
but `FilesystemIterator`, a child class of `DirectoryIterator`,
gives `string|SplFileIterator` which is not a subtype of
`DirectoryIterator`.

The declared return type of `DirectoryIterator::current()` is actually
`mixed`. So the stub should be `mixed` too in order not to violate LSP.
https://www.php.net/directoryiterator.current
@takaram
Copy link
Copy Markdown
Contributor Author

takaram commented May 27, 2026

Most of the errors are legit.
Value of RecursiveDirectoryIterator has changed from mixed to string|SplFileInfo. Errors with mixed were not reported in level 8.

However I fixed the type of DirectoryIterator. See beeb03a for detail.

@staabm
Copy link
Copy Markdown
Contributor

staabm commented May 27, 2026

please also check issue-bot results. especially I wonder why we get a mixed now instead of SplFileInfo|string

@takaram
Copy link
Copy Markdown
Contributor Author

takaram commented May 27, 2026

@staabm
Thank you for catching!
SplFileInfo|string was from the function map, now getting mixed because of DirectoryIterator stub.
Now the issue should be fixed

Comment thread phpstan-baseline.neon
Comment on lines +123 to +127
-
rawMessage: 'Cannot call method getPathname() on SplFileInfo|string.'
identifier: method.nonObject
count: 1
path: src/Cache/FileCacheStorage.php
Copy link
Copy Markdown
Contributor

@staabm staabm May 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not baseline this error but add a explicit check into FileCacheStorage to make sure we are working on getPathname().

my understanding is, that we get this error now (and did not before), because we work with
string|SplFileInfo after this PR, but had mixed before.

Comment thread stubs/iterable.stub
Comment on lines +312 to +315
/**
* @implements RecursiveIterator<string, SplFileInfo|string>
*/
class RecursiveDirectoryIterator extends FilesystemIterator implements RecursiveIterator
Copy link
Copy Markdown
Contributor

@staabm staabm May 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at the above baseline.neon comment, I realized it might be a nice improvement to infer the RecursiveDirectoryIterator generics based on __construct $flags parameter.

if we could do this, we would not have the baseline entry (this might also be stuff for a future PR)

might be doable for more iterators which work with FilesystemIterator::* constants

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RecursiveDirectoryIterator type

4 participants