← All results

ArrayIterator's template is inferred from its constructor argument

Group: PHPDoc generics · Category: phpdoc · File: generics_array_iterator_constructor_inference.php

new ArrayIterator([1, 2, 3]) is ArrayIterator<int, int> with no annotation at the call site. current() and key() return null at an invalid position, so the receivers are nullable: the probe is the element type, not the null. generics_iterator_to_array consumes a declared iterator instead, so the two rows separate the inference from the function signature. Source: carthage-software/mago#2476 (1.57.0). References: - mago#2476

Analyzer results

AnalyzerVersionResultDiagnostics
phan 6.0.11Phan 6.0.11 php-ast version 1.1.3 PHP version used to run Phan: 8.5.11 Fail

No diagnostics reported.

Expectation diff
Line 35: Expected 1 error(s)
Line 43: Expected 1 error(s)
phpstan 2.3.5PHPStan - PHP Static Analysis Tool 2.3.5 Pass reported Lv.5+
generics_array_iterator_constructor_inference.php:35: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects string|null, int given. [reported-from-level=5]
generics_array_iterator_constructor_inference.php:43: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, string given. [reported-from-level=5]
With strict-rules
generics_array_iterator_constructor_inference.php:35: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects string|null, int given.
generics_array_iterator_constructor_inference.php:43: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, string given.
psalm 6.20.9Psalm 6.20.9@f67170ac3c3b931f5088681e21d6c8babc601c08
next: 7.0.4
Pass
generics_array_iterator_constructor_inference.php:35: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects null|string, but 1|2|3|null provided [InvalidScalarArgument]
generics_array_iterator_constructor_inference.php:43: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, but 'a'|'b'|null provided [InvalidScalarArgument]
mago 1.59.0mago 1.59.0 Pass
generics_array_iterator_constructor_inference.php:35: Possible argument type mismatch for argument #1 of `Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString`: expected `null|string`, but possibly received `int|null`. [possibly-invalid-argument]
generics_array_iterator_constructor_inference.php:43: Possible argument type mismatch for argument #1 of `Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt`: expected `int|null`, but possibly received `null|string`. [possibly-invalid-argument]
mir 0.91.0mir 0.91.0 Pass
generics_array_iterator_constructor_inference.php:35: InvalidArgument: Argument $value of takesNullableString() expects 'string|null', got 'int' [MIR0201]
generics_array_iterator_constructor_inference.php:43: InvalidArgument: Argument $value of takesNullableInt() expects 'int|null', got 'string' [MIR0201]
phpantom 0.11.1phpantom_lsp 0.11.1 Pass
generics_array_iterator_constructor_inference.php:35: Argument 1 ($value) expects ?string, got int [type_mismatch_argument]
generics_array_iterator_constructor_inference.php:43: Argument 1 ($value) expects ?int, got string [type_mismatch_argument]
intelephense 1.18.5intelephense 1.18.5 Fail
generics_array_iterator_constructor_inference.php:34: Expected type 'null|int'. Found 'mixed'. [P1006]
generics_array_iterator_constructor_inference.php:35: Expected type 'null|string'. Found 'mixed'. [P1006]
generics_array_iterator_constructor_inference.php:36: Expected type 'null|int'. Found 'string|int|null'. [P1006]
generics_array_iterator_constructor_inference.php:42: Expected type 'null|string'. Found 'mixed'. [P1006]
generics_array_iterator_constructor_inference.php:43: Expected type 'null|int'. Found 'mixed'. [P1006]
Expectation diff
Line 34: Expected valid value to be accepted, got ["Expected type 'null|int'. Found 'mixed'. [P1006]"]
Line 36: Expected valid value to be accepted, got ["Expected type 'null|int'. Found 'string|int|null'. [P1006]"]
Line 42: Expected valid value to be accepted, got ["Expected type 'null|string'. Found 'mixed'. [P1006]"]
phpactor 2026.10.07.0Phpactor 2026.10.07.0 Fail

No diagnostics reported.

Expectation diff
Line 35: Expected 1 error(s)
Line 43: Expected 1 error(s)
phpy 1.0.19490phpy 1.0.19490 Fail

No diagnostics reported.

Expectation diff
Line 35: Expected 1 error(s)
Line 43: Expected 1 error(s)
qodana 262.11879.104PhpStorm 262.11879.104 Fail

No diagnostics reported.

Expectation diff
Line 35: Expected 1 error(s)
Line 43: Expected 1 error(s)
noverify 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 Fail

No diagnostics reported.

Expectation diff
Line 35: Expected 1 error(s)
Line 43: Expected 1 error(s)
steins 0.1.8steins 0.1.8 (2026-09-21 revision 76306a9) Fail

No diagnostics reported.

Expectation diff
Line 35: Expected 1 error(s)
Line 43: Expected 1 error(s)
phpstan-strict 2.3.5PHPStan - PHP Static Analysis Tool 2.3.5 Pass
generics_array_iterator_constructor_inference.php:35: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects string|null, int given.
generics_array_iterator_constructor_inference.php:43: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, string given.
psalm-next 7.0.4Psalm 7.0.4@fa5b1f6e665cb743838ffd865b8fc96207f9409f Pass
generics_array_iterator_constructor_inference.php:35: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects null|string, but 1|2|3|null provided [InvalidScalarArgument]
generics_array_iterator_constructor_inference.php:43: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, but 'a'|'b'|null provided [InvalidScalarArgument]

Source

<?php

declare(strict_types=1);

namespace Conformance\Tests\GenericsArrayIteratorConstructorInference;

/**
 * `ArrayIterator`'s template is inferred from its constructor argument.
 *
 * `new ArrayIterator([1, 2, 3])` is `ArrayIterator<int, int>` with no
 * annotation at the call site. `current()` and `key()` return null at an
 * invalid position, so the receivers are nullable: the probe is the element
 * type, not the null.
 * `generics_iterator_to_array` consumes a declared iterator instead, so the
 * two rows separate the inference from the function signature.
 *
 * Source: carthage-software/mago#2476 (1.57.0).
 *
 * References:
 * - https://github.com/carthage-software/mago/pull/2476
 */

function takesNullableInt(?int $value): void
{
}

function takesNullableString(?string $value): void
{
}

function fromIntList(): void
{
    $iterator = new \ArrayIterator([1, 2, 3]);
    takesNullableInt($iterator->current()); // V
    takesNullableString($iterator->current()); // E: current() is int|null
    takesNullableInt($iterator->key()); // V: list keys are int
}

function fromStringList(): void
{
    $iterator = new \ArrayIterator(['a', 'b']);
    takesNullableString($iterator->current()); // V
    takesNullableInt($iterator->current()); // E: current() is string|null
}