Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ parameters:
count: 5
path: src/Analyser/TypeSpecifier.php

-
rawMessage: 'Cannot call method getPathname() on SplFileInfo|string.'
identifier: method.nonObject
count: 1
path: src/Cache/FileCacheStorage.php
Comment on lines +123 to +127
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.


-
rawMessage: 'Template type TNodeType is declared as covariant, but occurs in contravariant position in parameter node of method PHPStan\Collectors\Collector::processNode().'
identifier: generics.variance
Expand Down
54 changes: 41 additions & 13 deletions stubs/iterable.stub
Original file line number Diff line number Diff line change
Expand Up @@ -159,22 +159,19 @@ class ArrayIterator implements SeekableIterator, ArrayAccess, Countable
}

/**
* @template T of \RecursiveIterator|\IteratorAggregate
* @mixin T
* @template TValue = mixed
* @implements SeekableIterator<string, TValue>
*/
class RecursiveIteratorIterator
class DirectoryIterator extends SplFileInfo implements SeekableIterator
{
/**
* @param T $iterator
*/
public function __construct(
$iterator,
int $mode = RecursiveIteratorIterator::LEAVES_ONLY,
int $flags = 0
)
{

}
}

/**
* @extends DirectoryIterator<SplFileInfo|string>
*/
class FilesystemIterator extends DirectoryIterator
{

}

Expand Down Expand Up @@ -207,6 +204,29 @@ class IteratorIterator implements OuterIterator {
public function __construct(Traversable $iterator) {}
}

/**
* @template T of \RecursiveIterator|\IteratorAggregate
*
* @implements OuterIterator<key-of<T>, value-of<T>>
*
* @mixin T
*/
class RecursiveIteratorIterator implements OuterIterator
{
/**
* @param T $iterator
*/
public function __construct(
$iterator,
int $mode = RecursiveIteratorIterator::LEAVES_ONLY,
int $flags = 0
)
{

}

}

/**
* @template-covariant TKey
* @template-covariant TValue
Expand Down Expand Up @@ -289,6 +309,14 @@ class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator
public function uksort($cmp_function) { }
}

/**
* @implements RecursiveIterator<string, SplFileInfo|string>
*/
class RecursiveDirectoryIterator extends FilesystemIterator implements RecursiveIterator
Comment on lines +312 to +315
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

{

}

/**
* @template TKey
* @template TValue
Expand Down
36 changes: 36 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-8435.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace Bug8435;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use function PHPStan\Testing\assertType;

class HelloWorld
{
public function sayHello1(string $path): void
{
$iterator = new RecursiveDirectoryIterator($path);
foreach ($iterator as $fileinfo) {
assertType('SplFileInfo|string', $fileinfo);
}
}

public function sayHello2(string $path): void
{
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
foreach ($iterator as $fileinfo) {
assertType('SplFileInfo|string', $fileinfo);
}
}

/**
* @param RecursiveIteratorIterator<RecursiveDirectoryIterator> $iterator
*/
public function test(RecursiveIteratorIterator $iterator): void
{
foreach ($iterator as $fileinfo) {
assertType('SplFileInfo|string', $fileinfo);
}
}
}
Loading