Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8b4783e
Resolve PHP version checks in return-type, throw-type and type-specif…
staabm Sep 22, 2026
c006f1f
Resolve PHP version checks in round() and str_split() throw type exte…
phpstan-bot Sep 22, 2026
56816b0
Discover scope-aware extensions in the build rule instead of listing …
phpstan-bot Sep 22, 2026
037ddad
List the scope-aware extension interfaces in the build rule explicitly
phpstan-bot Sep 22, 2026
add8984
Branch on the version check with a plain if() instead of PhpVersions:…
phpstan-bot Sep 22, 2026
5ee6d34
Move the printf format parser change to its own pull request
phpstan-bot Sep 22, 2026
6dd96dd
Keep PrintfFormatParser reading the PHP version from the call site
phpstan-bot Sep 22, 2026
f6b2836
Resolve PHP version checks in the get_class(), array_chunk() and unse…
phpstan-bot Sep 22, 2026
b74fdd4
Fix the expected lines in NoInjectedPhpVersionInScopeAwareExtensionRu…
phpstan-bot Sep 22, 2026
892a037
fix build
staabm Sep 22, 2026
365835c
Keep the PHP version check inside RegexArrayShapeMatcher::containsUnm…
phpstan-bot Sep 22, 2026
e9d2c95
Do not infer null from version_compare() with a valid constant operator
phpstan-bot Sep 22, 2026
80619fa
Detect DateTime::modify() failure from its return value, not from the…
phpstan-bot Sep 22, 2026
6d24a23
Strip modifiers the host PCRE may not know before compiling the pattern
phpstan-bot Sep 22, 2026
b2db476
Test return-type extensions against a configured PHP version range
phpstan-bot Sep 22, 2026
a69e753
fix baseline
staabm Sep 22, 2026
3565169
Update scope-php-version-range-return-type-extensions.php
staabm Sep 22, 2026
ddc2b6f
Move the src/Type/Php extension changes to their own pull request
phpstan-bot Sep 23, 2026
0d8d599
Leave the Regex* classes out of this pull request
phpstan-bot Sep 23, 2026
c778a5d
Test that FilterVarRule follows PHP_VERSION_ID narrowing
phpstan-bot Sep 23, 2026
8cd6733
restore phpversions
staabm Sep 23, 2026
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
Prev Previous commit
Next Next commit
Test return-type extensions against a configured PHP version range
The nsrt file only covers narrowing through PHP_VERSION_ID, which makes the
analysed version certain. Pin the uncertain case too: with phpVersion
min 70400 / max 80500 every version check inside the converted extensions is
Maybe, and the inferred type has to stay wide enough for both ends.

Covers the four expressions that widen at a range - substr(), str_split(''),
mb_substitute_character() with null and with 0 - and the version_compare()
regression, which fails here without the previous fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
  • Loading branch information
2 people authored and staabm committed Sep 22, 2026
commit b2db47673fd3385551d73cdcf31ca3610e67e253
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace PHPStan\Analyser;

use PHPStan\Testing\TypeInferenceTestCase;
use PHPUnit\Framework\Attributes\DataProvider;

class ScopePhpVersionRangeReturnTypeExtensionsTest extends TypeInferenceTestCase
{

public static function dataFileAsserts(): iterable
{
yield from self::gatherAssertTypes(__DIR__ . '/data/scope-php-version-range-return-type-extensions.php');
}

/**
* @param mixed ...$args
*/
#[DataProvider('dataFileAsserts')]
public function testFileAsserts(
string $assertType,
string $file,
...$args,
): void
{
$this->assertFileAsserts($assertType, $file, ...$args);
}

public static function getAdditionalConfigFiles(): array
{
return [
__DIR__ . '/scopePhpVersionRange.neon',
];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace ScopePhpVersionRangeReturnTypeExtensions;

use function PHPStan\Testing\assertType;

// The analysed PHP version is configured as the range 7.4 - 8.5, so every version check
// inside these extensions is uncertain. An uncertain check must not produce a type that is
// narrower than the truth on either end of the range.

function bothVersionsPossible(string $s): void
{
assertType("''|false", substr('abc', 10));
assertType("array{}|array{''}", str_split(''));
assertType('bool', mb_substitute_character(null));
assertType('bool', mb_substitute_character(0));
}

function validOperatorNeverReturnsNull(string $a, string $b): void
{
// version_compare() only returns null for an invalid operator, so a constant valid one
// rules null out no matter which version of the range is analysed.
assertType('bool', version_compare($a, $b, '<'));
assertType('bool', version_compare($a, $b, 'ge'));

assertType('(bool|null)', version_compare($a, $b, 'nope'));
assertType('(bool|null)', version_compare($a, $b, $s));
}
4 changes: 4 additions & 0 deletions tests/PHPStan/Analyser/scopePhpVersionRange.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
parameters:
phpVersion:
min: 70400
max: 80500
Loading