Download Latest Version 2.1.55 source code.tar.gz (4.0 MB)
Email in envelope

Get an email when there's a new version of PHPStan

Home / 2.1.55
Name Modified Size InfoDownloads / Week
Parent folder
phpstan.phar 2026-05-18 26.6 MB
phpstan.phar.asc 2026-05-18 833 Bytes
2.1.55 source code.tar.gz 2026-05-18 4.0 MB
2.1.55 source code.zip 2026-05-18 3.9 MB
README.md 2026-05-18 15.7 kB
Totals: 5 Items   34.5 MB 3

This release fixes 55 issues! 🎉

Bleeding edge 🔪

  • Report invalid DateInterval constructor arguments at analysis time (#5587), [#14442], thanks @staabm and @VincentLanglet!
  • Report impure method overriding pure parent method in MethodSignatureRule (#5584), [#14563], thanks @VincentLanglet and @staabm!
  • Validate define() and const values against explicit types in dynamicConstantNames (#5648), [#14600], thanks @staabm and @VincentLanglet!

If you want to see the shape of things to come and adopt bleeding edge features early, you can include this config file in your project's phpstan.neon:

includes:

    - vendor/phpstan/phpstan/conf/bleedingEdge.neon

Of course, there are no backwards compatibility guarantees when you include this file. The behaviour and reported errors can change in minor versions with this file included. Learn more

Improvements 🔧

  • Don't report "no value type specified in iterable type array&callable" (#5565), thanks @staabm!
  • Resolve method reflection for dynamic static calls ($var::method()) to enable purity and side-effect checking (#5572), [#14557], [#5020], thanks @VincentLanglet and @staabm!
  • Track more expressions (#5596), [#12517], [#6486], [#9155], thanks @VincentLanglet!
  • Detect private promoted properties whose only reads are self-writes via new self() (#5599), [#14573]
  • Report wrong types being passed to array&callable type (#5573), [#14549], thanks @VincentLanglet and @staabm!
  • Infer numeric-string for DateInterval::format('%a') when interval comes from diff() (#5674), [#1452], thanks @VincentLanglet and @staabm!

Bugfixes 🐛

  • Recurse into parent expression in IssetCheck and MutatingScope::issetCheck when property has propagated error (#5569), [#14555]
  • Fix oversized-array self-rejection in optimizeConstantArrays (https://github.com/phpstan/phpstan-src/commit/974334628877101f92571ac2d84f289667621e24)
  • Update jetbrains/phpstorm-stubs (#5576), [#14559], thanks @bitwise-operators!
  • Track $arr[$key] existence across array_search/array_find_key via conditional expression holders (#5552), [#14537], thanks @staabm and @VincentLanglet!
  • Do not narrow array to empty when array_find_key() returns null (#5693), [#14630]
  • Fix implode losing non-empty-string when ConstantArrayType has all-optional keys (#5578), [#14558], thanks @VincentLanglet and @staabm!
  • Narrow DateInterval->days after DateTimeInterface->diff() (#5588), [#14428], thanks @staabm!
  • Treat * as assignment suppression in sscanf/fscanf placeholder counting (#5586), [#10260], thanks @staabm and @VincentLanglet!
  • Do not prefix anything in resources/ when building phpstan.phar (https://github.com/phpstan/phpstan-src/commit/5c2804832e7e259bf3333bd06e6a4c7fcd65bb00)
  • Walk ancestors for stub method PHPDoc on built-in classes without their own stub entries (#5695), [#14632], thanks @staabm!
  • Isolate alternation branches in RegexGroupParser::walkGroupAst() to prevent non-empty/non-falsy state bleeding (#5602), [#14575], thanks @staabm and @VincentLanglet!
  • Widen empty ConstantArrayType to array when resolving dynamic constant types (#5606), [#8526], thanks @VincentLanglet and @staabm!
  • Fix counting *scanf() format string placeholders (#5594), [#14567], thanks @hakre!
  • Do not report maybe in RandomIntParametersRule when either argument is an unbounded IntegerRangeType (#5622), [#14468], thanks @staabm and @VincentLanglet!
  • Assign proper types for $argc and $argv in global statements (#5623), [#12392], thanks @staabm and @VincentLanglet!
  • Do not propagate isAlwaysTerminating from immediately-invoked callable arguments to the outer call (#5604), [#14582], thanks @VincentLanglet!
  • Resolve ConditionalType when subject-target relationship is deterministic despite containing template types (#5631), [#11894], [#8048], thanks @VincentLanglet and @staabm!
  • Return null from ArgumentsNormalizer::reorderArgs() when positional args after named args create holes beyond parameter count (#5637), [#14596], thanks @staabm and @VincentLanglet!
  • Collect all remaining callable parameter types for variadic closure parameters instead of using only the matching index (#5634), [#9240], thanks @VincentLanglet and @staabm!
  • Switch HasMethodType/HasPropertyType from ObjectTypeTrait to MaybeObjectTypeTrait (#5605), [#8217], thanks @VincentLanglet and @staabm!
  • Augment BooleanAnd falsey and BooleanOr truthy type narrowing when left and right conditions narrow different expression keys (#5595), [#14566], [#13061], [#7259], thanks @VincentLanglet!
  • callable-array intersection type is a constant array (#5647)
  • Fix infinite recursion in specifyTypesForCountFuncCall with mixed TypeSpecifierContext (#5653), [#14605]
  • Do not report non-falsy-string == 0 as always false in AccessoryNonFalsyStringType::looseCompare() (#5654), [#14606], thanks @VincentLanglet and @staabm!
  • Prevent creation of IntersectionType with just HasOffsetValueType accessories (https://github.com/phpstan/phpstan-src/commit/fa4e7d2f6a33d124dee19df561876662e20e71f0), [#14604]
  • Prevent issue with accessory-only IntersectionType (https://github.com/phpstan/phpstan-src/commit/f2af15b571c3546734f75162699d240bd3e72306)
  • Re-check scalar types after integer range expansion in TypeCombinator::union (#5660), [#14610], thanks @staabm and @VincentLanglet!
  • Respect @throws void on getIterator() when determining foreach Traversable throw points (#5666), [#6833], thanks @staabm and @VincentLanglet!
  • Check inner union types before delegating to isSubTypeOf for LateResolvableType in UnionType::isSuperTypeOf() (#5645), [#10942], thanks @staabm and @VincentLanglet!
  • Use pre-args scope for value types in array_push/array_unshift (#5579), [#13510], thanks @predictor2718!
  • Use before-scope for evaluating array_splice argument types (#5682), [#13510], thanks @VincentLanglet and @staabm!
  • Fix: property.notFound in chained isset() with checkDynamicProperties (#5562), [#13539], thanks @predictor2718!
  • Invalidate property types after dynamic method calls (#5679), [#3831], thanks @VincentLanglet and @staabm!
  • Skip class name case check for type hints using explicit use ... as aliases (#5671), [#14617], thanks @VincentLanglet and @staabm!
  • Skip non-discriminating guards in createConditionalExpressions even when target is not tracked in the other scope (#5676), [#14595], thanks @staabm and @VincentLanglet!
  • Preserve TemplateType in IntersectionType::shuffleArray() when intersection is already a list (#5694), [#14631]
  • Fix another shuffle() variant (#5696), thanks @staabm!

Performance 🏎️

  • Lazily initialize AggregateSourceLocator to speedup bootstrapping (#5577), thanks @staabm!
  • PhpFileCleaner: Use strcspn instead of regex for fast-skip in clean() (#5600), thanks @staabm!
  • Cap cumulative unroll factor when nesting unrolled constant-array foreach (#5614), [#14590]
  • DateFunctionReturnTypeHelper: prevent unnecessary TypeCombinator::union() (#5629), thanks @staabm!
  • Memoize ArrayType::isList() (#5680), thanks @staabm!

Function signature fixes 🤖

  • Fix [#14499]: Mark Lua::__construct $lua_script_file parameter as optional (#5571), [#14499], thanks @predictor2718!
  • More concrete return type for opcache_get_configuration (#5424), thanks @devnix!
  • Conditional return type for SQLite3Result::fetchArray() (#3080), thanks @devnix!
  • Some metadata fixes for SPL classes (#5574), thanks @bitwise-operators!
  • Mark class_exists, interface_exists, trait_exists, and enum_exists as having no side effects in function metadata (#5607), [#8579], thanks @VincentLanglet and @staabm!
  • Add multi-variant overloads for PDOStatement::fetchAll() in function signature map (#5630), [#5509], thanks @VincentLanglet and @staabm!
  • Return list<mixed> from PDOStatement::fetchAll() (#5643), [#11889], thanks @staabm and @VincentLanglet!

Internals 🔍

  • Add bench for PhpDocInheritanceResolver speedup from [#4829] (https://github.com/phpstan/phpstan-src/commit/d34f7cc756dbb7c3ab40525aa452fc32485f4da8)
  • Added regression test (#5585), [#9004], thanks @staabm!
  • Remove dead code from FileExcluder (#5598), thanks @staabm!
  • Compiler - update Box + dependencies (#5601)
  • Simplify compiler/box/composer.json (https://github.com/phpstan/phpstan-src/commit/37e8fe0310a5dfb1767c7d144ec439345ab8cdb9)
  • Extract Type::makeListMaybe() for sort functions that drop list-ness (#5611)
  • Extract Type::mapValueType(callable) for "same keys, transformed values" (#5611)
  • Extract Type::changeKeyCaseArray(?int) for array_change_key_case (#5611)
  • Extract Type::filterArrayRemovingFalsey() for array_filter no-callback path (#5611)
  • Extract Type::mapKeyType(callable) and use it alongside mapValueType in NodeScopeResolver (#5611)
  • Add Type::makeAllArrayKeysOptional() for preg_replace* array fast path (#5611)
  • Extract Type::toBitwiseNotType() for ~$x (#5612)
  • Extract Type::toGetClassResultType() for get_class($x) (#5612)
  • Extract Type::toClassConstantType() for $x::class (#5612)
  • Extract Type::toObjectTypeForInstanceofCheck() for instanceof RHS (#5612)
  • Extract Type::toObjectTypeForIsACheck() for is_a($x, $class, $allowString) (#5612)
  • Inline one-line wrappers around polymorphic Type methods (#5613)
  • Test result-cache restore does not trigger reflection (#5617), thanks @staabm!
  • Test result-cache restore does not trigger reflection in all 1st party extensions (#5618), thanks @staabm!
  • Remove dead code in StrContainingTypeSpecifyingExtension (#5626), thanks @staabm!
  • Merge NSRT and rule test fixtures for bug-14582 into a single file (#5604), [#14582], thanks @VincentLanglet!
  • Introduce MutatingScope::getCallableParameterType (#5635), thanks @VincentLanglet!
  • Introduce MaybeStringTypeTrait (#5642), thanks @VincentLanglet!
  • Added regression test (#5652), [#14569], thanks @staabm!
  • IntersectionType::toPhpDocNode - check empty types (https://github.com/phpstan/phpstan-src/commit/bfa881cac303328075f6621772baa9842cb0f827)
  • Introduce Process interface and ProcessBase for parallel workers (#5663)
  • Extract WorkerRunner from WorkerCommand (#5663)
  • Add pcntl_fork() parallel worker path (#5663)
  • Introduce ProcessPromise interface for the PHPStan Pro worker (#5663)
  • Extract FixerWorkerRunner from FixerWorkerCommand (#5663)
  • Add pcntl_fork() PHPStan Pro worker path (#5663)
  • Print parallel worker mechanism via DiagnoseExtension (#5663)
  • Experiment: fork parallel workers via pcntl_fork() (https://github.com/phpstan/phpstan-src/pull/5663)
  • Mostly broken because of PHAR file pointer shared between process forks
  • Opt-in behaviour with env var PHPSTAN_PARALLEL_FORK=1
  • Looking for an idea for a fix from the community
  • Add regression test for circular class constant PHPDoc type references (#5685), [#9172], thanks @VincentLanglet and @staabm!
Source: README.md, updated 2026-05-18