Releases: phpstan/phpstan
Release list
2.2.8
Bugfixes 🐛
- Narrow the right side of
??=with falseyisset()instead of!== null(#6145), #15021, thanks @VincentLanglet and @staabm! ArrayType::isCallable(): askStringType::isSuperTypeOf()about the item type instead of onlyisString()(#6166), #13114- Conjoin alternative-form entries in
SpecifiedTypes::unionWith()instead of keeping only the left one (#6173), #15039 - Do not narrow the falsey branch of a nested isset() at its intermediate offset (#6175), #15005, thanks @SanderMuller!
- Store PhpStorm stub paths in the reflection cache relative to the stubs root (#6179), #15023
- Turbo extension: Resolve comment token ids at runtime in the native parser (#6180), #15037, #15043
- Rebuild
GatheringNodeCallbacklayers inVirtualAssignNodeCallbackinstead of wrapping them (#6172), #15038
Performance 🏎️
- Faster handling of enums with lots of cases (#6160), thanks @staabm!
- Memoize the isGenerator() yield scan on the AST node (#6161)
- Answer
UnionTypecomparisons from an identity-keyedFiniteTypeSetinstead of scanning every member (#6116), #15008, #14978, thanks @staabm and @SanderMuller!
Function signature fixes 🤖
- Make
ReflectionObject,RecursiveFilterIterator,ParentIterator,RecursiveCachingIteratorandRecursiveRegexIteratorgeneric in stubs (#6165), #15032
Internals 🔍
- Resolve isset/empty/?? chains from handler-built descriptors (#6144)
- Split processAssignVar into prepareTarget and applyWrite, compose the ??= read (#6144)
- Walk the dynamic variable name once, drop the vestigial clone walks (#6144)
- Add parameter closure type extensions for array_map, array_filter, array_walk, array_find (#6147)
- Resolve the native flavour of closure parameters through parameter closure type extensions (#6147)
- Derive ArrayAccess and __set simulation throw points directly instead of walking synthetic calls (#6148)
- Extract the intrinsic closure-parameter blocks into
ParametersAcceptorSelector::applyIntrinsicArgOverrides()(#6149) - Derive expression-statement exit points from the never type (#6150)
- Reference the original chain in ExistingArrayDimFetch, delete DeepNodeCloner (#6151)
- Let the compositional-key shortcut clear virtual-node keys on the invalidated side (#6154)
- Do not extend Expr in the isset/empty/coalesce rule-facing virtual nodes (#6155)
- Add ShellExecHandler and IssetExprHandler (#6156)
- Run the impossible-check and nullsafe rules on post-processing virtual nodes (#6157)
- Process call arguments in a single pass with type-driven acceptor selection (#6158)
- Improve
#[InstanceofDeprecated]message of EnumCaseObjectType (#6159), thanks @staabm! - Check yield operand voidness through getKeepVoidType() (#6161)
- Drop redundant
@internalon hasAcceptorTemplateOrLateResolvableParameterType (#6161) - Pass the iteratee type into enterForeach() and enterForeachKey() (#6162)
- Resolve intertwined by-ref slot types from the just-assigned root type (#6162)
- Filter FiberScope state in the falsey direction and carry both filter lists (#6164)
- Check destructured
@varitems against the native offset type (#6164) - Defer match arm comparison errors only for match(true)-style subjects (#6164)
- Scope deferred constant-condition errors and markers per file (#6164)
- Add deferred SpecifiedTypes machinery evaluated at the application point (#6163), #14908, #14966
- Defer boolean-decomposition holder math to the application point (#6163)
- Add regression test for #14908 (#6163)
- Do not derive holder antecedents from truthy narrowing weaker than the truth (#6163)
- Specify expression types in place on an unpublished working copy (#6168)
- Use a complete version constraint in FiniteTypeSetTest's RequiresPhp attribute (#6177), thanks @SanderMuller!
- Harden the turbo-token-numbering job against zizmor findings (#6180), #15037, #15043
- Harden phar.yml per zizmor across all jobs (#6180), #15037, #15043
2.2.7
Bugfixes 🐛
- Preserve maybe-certainty only for
Variablewhen narrowing the base of?->,??,isset()andempty()(#6109), #15002, thanks @staabm and @VincentLanglet! - Do not key the container cache on the turbo extension state (#6121)
- Fill the missing gaps in expr processing (phpstan/phpstan-src@eea2788)
- Resolve a relative include against the trait file in a trait context (#6127), thanks @zonuexe!
- Do not let type narrowing define a certainly-undefined variable (#6130), #2032
- Merge all callable acceptors' parameters into
NativeParameterReflectionwhen a closure is passed to a union of callables (#6128), #15003, thanks @staabm and @VincentLanglet! - Treat a property with a default value as always set in isset resolution (#6131), #10786
- Read already-processed expression types from ExpressionResults in NodeScopeResolver (#6139), #13253
- Resolve
__DIR__and__FILE__against the trait file in a trait context (#6126), #15015, thanks @zonuexe!
Performance 🏎️
- Reuse the scope factory of the other flavour (#6114)
- Remember chain levels that shortcircuit to themselves (phpstan/phpstan-src@ab11f34), #14991
- Prevent unnecessary re-creation of union types (#6117), thanks @staabm!
- Remember an expression's printed form as the printer produces it (#6118), #14991
- Prevent unnecessary re-creation of benevolent union types (#6119), thanks @staabm!
- Resume expression-asking fibers with ExpressionResults (phpstan/phpstan-src@9725942)
- Create merge conditionals from the differing holders only (#6141)
Internals 🔍
- ExprHandlerRegistry does not need to be AutowiredService (phpstan/phpstan-src@36392ba)
- Repeat a shadowed class's interfaces on its stub shell (#6113)
- Run the benchmark on PHP 7.4 in addition to PHP 8.5 (#6121)
- Check
bench/datafiles with RequiredPhpVersionCommentTest (#6122), thanks @staabm! - Introduce ExpressionResultFactory (phpstan/phpstan-src@8f5111f)
- ExpressionResult - add beforeScope (phpstan/phpstan-src@a7094b5)
- ExpressionResult - add Expr (phpstan/phpstan-src@abcce56)
- Eliminate the OriginalPropertyTypeExpr virtual node (#6129)
- Eliminate the GetOffsetValueTypeExpr virtual node (#6129)
- Eliminate the GetIterableKeyTypeExpr virtual node (#6129)
- Eliminate the GetIterableValueTypeExpr virtual node (#6129)
- Deduplicate constant-condition vs impossible-check reports via collectors instead of asking the type specifier inline (#6132)
- Replace
SpecifiedTypes::normalize()with symbolic alternative-form entries (#6133) - Resolve early-terminating calls to an explicit never type in the call handlers (#6134)
- Read operand types from ExpressionResults in Throw/BooleanAnd/Coalesce handlers (#6135)
- Read operand types from ExpressionResults in Ternary/ArrayDimFetch/PropertyFetch handlers (#6136)
- Read operand types from ExpressionResults in BinaryOp/BooleanOr/MethodCall/Match handlers (#6137)
- Read expression types from ExpressionResults in NodeScopeResolver and handlers (#6138)
- Fill the foreach key-loop native types with the native flavour (#6141)
- Run engine-feeding node-callback gatherers synchronously at the emission position (#6142)
- Track containsNullsafe on ExpressionResult and propagate it through fetch/call chains (#6143)
1.12.34
- Revert "Tell coding agent PHPStan 2.x is available" (phpstan/phpstan-src@643c2a3), #14614
- Message from the future (phpstan/phpstan-src@c2fbb22)
2.2.6
This release fixes 33 issues! 🎉
Major new features 🚀
- PHPStan Turbo (https://github.com/phpstan/turbo-ext/)
- Optional native PHP extension (PHP 8.3+) written in C++ that makes running PHPStan 10-30 % faster (depending on project specifics)
- Users installing PHPStan through Composer with
phpstan/phpstanget it automatically. Composer package ships prebuilt binaries for the most common platforms — Linux (glibc and musl, x86_64 and arm64), macOS, and Windows (x86_64) - Users running standalone
phpstan.pharcan install the extension withpie install phpstan/turbo - The fact that it's enabled can be verified with
vendor/bin/phpstan diagnoseor runninganalyse -vvv - There's room to improve performance with this technique in the future, but we're shipping it now because it brings real benefits already.
Bleeding edge 🔪
- Report finite-typed values in a constant array haystack that can never be the in_array()/array_search()/array_keys() needle (#6054), #14960
- Report
?? null/??= nullon an always-set left side as an unnecessary null coalesce (#5865), #4337, #12179, #9966, thanks @VincentLanglet and @staabm! - Type
DOMDocumentload/save/validate string arguments asnon-empty-stringon PHP 8 (#6075), #14979, thanks @VincentLanglet and @staabm!
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 🔧
- Implement
@pure-unless-callable-is-impure(#3482), #11101, #11100, thanks @zonuexe! - Report invalid
$flagsconstants forpreg_replace_callback()andpreg_replace_callback_array()(#6019), #11437, #14910, thanks @staabm and @VincentLanglet! - Validate callback signatures for curl_setopt callback options like CURLOPT_PREREQFUNCTION (#6050), #14956, thanks @staabm and @VincentLanglet!
Bugfixes 🐛
- Do not narrow the left side of
??to non-null when the coalesce context still permits a falsey value (#6000), #13488, thanks @VincentLanglet and @staabm! - Add
UnaryOperatorTypeSpecifyingExtensionforBcMath\Numberso unary+/-inferBcMath\Number(#5994), #13965, thanks @VincentLanglet and @staabm! - Narrow
explode()result for limit 0, 1, and -1 (#5993), thanks @paulbalandan! - Accept
decimal-int-stringarguments for%dprintf placeholders in strict mode (#5997), #13609, thanks @VincentLanglet and @staabm! - Resolve the base of
$prop[] = ...to its readable type instead of its writable type (#5996), #14054, thanks @VincentLanglet and @staabm! - Invalidate tracked superglobal narrowings after impure function, method, static and constructor calls (#6007), #12799, thanks @VincentLanglet and @staabm!
- Invalidate volatile expressions on eval/include (#6009), thanks @VincentLanglet!
- Do not treat offset writes on ArrayAccess properties as reassignments of readonly properties (#5995), #13856, thanks @VincentLanglet and @staabm!
- Forget negative
function_exists()/class_exists()narrowings when global state may change (#5998), #13608, #12094, thanks @VincentLanglet and @staabm! - Reanalyse trait-consuming files after a body-only trait change even when the trait shares its file with another symbol (#6033), #14943
- Negating the smallest integer results in a float (#6028), #14946, #14947, thanks @zonuexe!
- Fix 'path ... does not exist' false-positive for expr containing DIRECTORY_SEPARATOR (#6035), #14944, thanks @staabm!
- Track file dependencies for global constant fetches (#6023), thanks @SanderMuller!
- Track define()'d constants as exported nodes (#6036), thanks @SanderMuller!
- Fix filter_var throw-on-failure detection (#6042), thanks @simPod!
- Make Type objects behave as the immutable values they are (#6037)
- Account for subclasses in get_parent_class() of a $this/static value (#6048), #14951, thanks @zonuexe!
- Treat all in-scope variables as used when a closure or constructor body contains
include/require/eval(#6056), #14962, thanks @staabm and @VincentLanglet! - Treat all in-scope variables as used when an unused-parameter body accesses a variable variable (
$$name) (#6058), #13960, thanks @staabm and @VincentLanglet! - Resolve static/self/parent relative to
@param-closure-thisbound class (#6061), #11010, thanks @calebdw! - Do not report abstract interface methods provided by a non-abstract built-in parent class in
MissingMethodImplementationRule(#6059), #14964, thanks @VincentLanglet! - Preserve maybe in BitwiseFlagHelper for bitwise-or with dynamic operands (#6080), thanks @vrana!
- Treat trait-declared properties as initialized when promoted by an inherited constructor (#6085), #14983, thanks @VincentLanglet and @staabm!
- Keep the result cache when composer.lock changes but no package version did (#6086), #14984, thanks @SanderMuller!
- Fix "
ob_get_*() === falsewill always evaluate to false" false positive (#6097), #14985, thanks @staabm! - Invalidate the whole result cache when a changed package registers a container class (#6088), #14986, thanks @SanderMuller!
Performance 🏎️
- Cache ObjectType instead of re-creating it over and over (#6006), thanks @staabm!
- Single-flight cold directory scans in OptimizedDirectorySourceLocatorFactory (#5846), thanks @SanderMuller!
- Disable zend.assertions as suggested by PHP-Parser (#6021), thanks @staabm!
- Faster DuplicateClassDeclarationRule (#6038), thanks @staabm!
- Faster DuplicateFunctionDeclarationRule (#6039), thanks @staabm!
- Memoize
ExprHandlerdispatch inMutatingScope::resolveType()(#6040), thanks @staabm! - Replace
NodeFinderwith direct recursion inshouldInvalidateExpression()(#6041), thanks @staabm! - Return early from
ClassReflection::getMethod()cache (#6043), thanks @staabm! - Index PSR autoloader locators by symbol instead of sweeping them per lookup (#6037)
- Short-circuit no-op remove() comparisons by identity before equals() (#6037)
- Cache reflections built from the PhpStorm stubs (phpstan/phpstan-src@ae5fd31)
- Do not park fibers on expressions that can never receive a before-scope (#6064)
- Extend the compositional-key shortcut to more invalidation scans (#6064)
- Prevent unnecessary method calls on Type (#6076), thanks @staabm!
- Prevent reflection when Property Hooks not supported (#6082), thanks @staabm!
- Iterate through nullsafe expression chains (#6084), thanks @realFlowControl!
- Iterate in
collectInterfaces()(#6092), thanks @staabm! - Iterate in
getBooleanExpressionDepth()(#6091), thanks @staabm! - Prevent duplicate
filterByTruthyValue()work inNodeScopeResolver(#6103), thanks @staabm! - Run indentation detection, node cloning and node replaci...
2.2.5
Improvements 🔧
- Update nikic/PHP-Parser to 5.8.0 (phpstan/phpstan-src@afc2669)
- Narrow
explode()when the delimiter is a known substring (#5959), #14651, thanks @paulbalandan!
Bugfixes 🐛
- Allow null values in native
preg_replace_callbackcallback array type forPREG_UNMATCHED_AS_NULL(#5987), #14904, thanks @staabm!
Performance 🏎️
- Restore process-wide statics from the main container after stub validation (#5984)
- Drop the container reference in LazyClassReflectionExtensionRegistryProvider after building the registry (#5985)
- Replace PhpClassReflectionExtension::evictPrivateSymbols() with a shared LRU over the member caches (#5986)
- Make the member cache LRU limit configurable as cache.memberCacheKeysMax (#5986)
- LRU-cap resolved local type aliases in UsefulTypeAliasResolver (#5989)
- Make the cap configurable via cache.resolvedLocalTypeAliasesCountMax (#5989)
- Raise CachedParser source-byte cap to 4 MB, add eviction floor, make it configurable (phpstan/phpstan-src@354e926)
- Give CachedParser $cachedSourceBytesMax a default value (phpstan/phpstan-src@fa1003a)
- Flatten deep BooleanOr chains in resolveType() to avoid O(n^2) scope narrowing (#5992), #14477, thanks @SanderMuller!
- Cache per-guard
isSuperTypeOf()results increateConditionalExpressions()instead of recomputing them per target (#6001), #14920 - Skip constant-array guards when creating conditional expressions for subtype-absorbed targets (#6002), #14921
- Compute
ConstantArrayTypesealed-shapeisSuperTypeOf()reasons lazily viaIsSuperTypeOfResultclosures (#6003), #14918 - Memoize the
ExprHandlerlookup byExprclass inspecifyTypesInCondition()andprocessExprNode()(#5999), #14919
Function signature fixes 🤖
- Add PHP 8.5
partitionedcookie attribute tosession_get_cookie_params()and the cookie option shapes (#6004), #14922, thanks @VincentLanglet and @staabm!
Internals 🔍
- Ignore PHP versions where a snippet newly stopped parsing in issue-bot comparisons (phpstan/phpstan-src@8d545f1)
2.2.4
PHPStan addresses the RAMpocalypse! It now consumes a lot less memory. See for yourself by running analyse -v.
E.g. running PHPStan on itself went from 2.8 GB to 2.1 GB total consumed memory across worker processes.
Bugfixes 🐛
- Skip boolean conditional holders whose target was dropped as a no-op antecedent narrowing (#5958), #14891, thanks @VincentLanglet!
- Distrust a TemplateType member's eager Yes in IntersectionType::isAcceptedBy only when that member accepts with Yes (#5962), #14893, thanks @staabm!
- Forget the tracked
ob_get_level()after impure calls that may open or close output buffers (#5964), #14895, thanks @staabm and @VincentLanglet!
Performance 🏎️
- PackageDependencyResolver: memoize resolvePackage per file (#5961), thanks @SanderMuller!
- Evict parser and PHPDoc name-scope caches by LRU instead of FIFO (#5965)
- Remove custom isSuperTypeOf reasons from ObjectType (#5968), #14896
- Restore value sharing in name scope maps hydrated from the file cache (#5969)
- Cap CachedParser by total cached source size (#5969)
- Keep a single memoization layer for located reflections (#5974)
- Stream the result cache to disk instead of building it in memory (phpstan/phpstan-src@ee9fe9e)
Internals 🔍
2.2.3
This release fixes 52 issues! 🎉
Bleeding edge 🔪
- Report
newon an expression whose type is notstring|objectvianew.nonObject(#5866), #4922, thanks @VincentLanglet and @staabm! - RequireFileExistsRule: Fix Differing behaviors when requiring or including relatively vs using
__DIR__(#5879), thanks @staabm!
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 🔧
- Result cache: Invalidate only package-dependent files when a Composer package changes (#5933), thanks @SanderMuller!
- Prevent ENV var tokens from being leaked by commited DI containers (#5820), thanks @staabm!
- Explain unresolvable and impossible types with reasons (#5827)
- Support type predicates on callable and Closure types (#5837), #14800, #11139
- Implement
AccessoryDecimalIntegerStringType::tryRemove()and preserve accessories when re-unioning'0'(#5816), #14785, thanks @staabm and @VincentLanglet! - Enumerate constant strings from bounded regex quantifications (
a?,a{n},a{n,m}) (#5860), #14820, thanks @staabm! - Preserve variable certainty when narrowing the base of a nullsafe operator (#5870), #7291, thanks @VincentLanglet and @staabm!
- Support
::classmagic constant in array shape keys and const types (#5891), thanks @janedbal! - Infer
non-falsy-string&non-decimal-int-stringfor the magicnameproperty on theUnitEnum/BackedEnuminterfaces (#5894), #14839, thanks @staabm and @VincentLanglet! - Narrow
ob_get_contents()/ob_get_clean()/ob_get_flush()/ob_get_length()to non-falsewhile output buffering is active (#5909), #10348, thanks @staabm and @VincentLanglet! - Support treatPhpDocTypesAsCertain for null-safe methods/properties (#5924), thanks @rvanvelzen!
- Do not let a TemplateType member force Yes acceptance of an intersection (#5926), #13190, thanks @rvanvelzen!
- Report always-true
in_array(..., true)when every finite needle value is guaranteed in the haystack (#5944), #14873, thanks @staabm and @VincentLanglet!
Bugfixes 🐛
- Narrow the
matchsubject when its assigned result is later narrowed (#5808), #14772, #10843 - Do not create
never-narrowing conditional expression holders inBooleanAnd/BooleanOrdecomposition (#5809), #14774 - Gather all conjuncts of a compound condition side into
BooleanAnd/BooleanOrconditional holders (#5810), #14780 - Do not split a swapped negated-conjunction holder side into per-expression holders (#5810), #14780
- Infer
non-empty-listforpreg_match_all()matches when the match succeeded (#5812), #14781, thanks @staabm and @VincentLanglet! - Do not split a compound-boolean holder side whose asserted truth value is a disjunction (#5817), #14787
- Narrow regex subject to
decimal-int-stringwhen every alternation branch is a decimal integer (#5814), #14784, thanks @staabm! - Narrow
ctype_digit()argument tonumeric-stringinstead ofdecimal-int-string(#5822), #14792 - Revert #5793 (#5825), thanks @staabm!
- Preserve keyed array prefix as unsealed tail when adding a general array with
+(#5832), #14799 - Skip conditional expression guard when guard type is a subtype of the other branch's value (#5848), #14807
- Narrow switch case branch from the case condition's plain scope instead of its truthy scope (#5852), #14814
- Treat a regex alternation as maybe-empty when any branch is maybe-empty in
isMaybeEmptyNode(#5851), #14809, thanks @staabm and @VincentLanglet! - Combine alternation branch literals with their preceding prefix in regex group types (#5851), #14809, thanks @staabm and @VincentLanglet!
- Decompose union offset types in
ConstantArrayType::flipArray()andfillKeysArray()to preserve per-key value precision (#5719), #14656, thanks @VincentLanglet and @staabm! - Report exceptions thrown from
ResultCacheMetaExtensionduring result cache restore as internal errors (#5853), #14805, thanks @staabm and @VincentLanglet! - Include
nullin return type ofClosure::bindTo()andClosure::bind()dynamic return type extensions (#5675), #5009, thanks @VincentLanglet and @staabm! - Treat
decimal-int-stringas a numeric string inlooseCompare()instead of assuming inequality with non-decimal strings (#5824), #14793, thanks @VincentLanglet and @staabm! - Consider
is_file($path)before checkingrequire $path(#5867), thanks @staabm! - Use genuine falsey narrowing (not the inverted truthy narrowing) for the consequent of
BooleanAndfalse-context conditional holders (#5878), #14828 - Narrow array element type after a keyless
foreachwhose body guards each element with an early exit (#5877), #5755 - Remember call expression as truthy/falsey alongside
@phpstan-assert-if-trueargument narrowing (#5885), #14829, thanks @staabm! - Remember method/static call expression as truthy/falsey alongside
@phpstan-assert-if-trueargument narrowing (#5880), thanks @staabm and @VincentLanglet! - Keep subtype-absorbed variables as conditional-expression targets when merging branches (#5876), #7948, #4905, thanks @VincentLanglet and @staabm!
- Enter right-side-assign context for
??=so closures capturing the assigned variable by reference see its assigned type (#5900), #13810, thanks @staabm! - Propagate
hasYieldfromyieldin ternary branches (#5904), #5681, thanks @staabm and @VincentLanglet! - Normalize constant-string member access (
$obj->{'n'}) to bareword form when printing expression keys (#5916), #14847, thanks @staabm and @VincentLanglet! - Do not report invariant template type mismatch when both type arguments are the same template parameter narrowed by control flow (#5921), #13190, thanks @rvanvelzen!
- Prevent "Unresolvable type" errors when mapping constant arrays (#5936), #14844, thanks @staabm and @VincentLanglet!
- Preserve template bound for enum-case, integer-range and constant-bool subtypes in
TemplateTypeFactory::create()(#5905), #10083, thanks @staabm and @VincentLanglet! - Re-add complement of a dropped self-condition to boolean-decomposition holder types (#5943), #14874, thanks @VincentLanglet and @staabm!
- Skip degenerate no-op antecedents when building boolean conditional expression holders (#5951), #14878, thanks @VincentLanglet and @staabm!
- Resolve class-string expressions to object types when detecting unused private methods, constants and static properties (#5953), #14880, thanks @staabm and @VincentLanglet!
- Treat plain
class-stringas a definite subtype ofclass-string<object>inGenericClassStringType::isSuperTypeOf()(#5956), #14887 - Invalidate outer-scope expressions mutated by closures, arrow functions and callables passed as arguments (#5957), #14888
Performance 🏎️
- Stripe size-sorted files across parallel jobs (#5844), thanks @SanderMuller!
- Keep input order of files withi...
2.2.2
Improvements 🔧
- Narrow
preg_match/preg_match_allsubject string type when match is truthy (#5777), #14710, thanks @staabm and @VincentLanglet! - Resolve per-element callback return types in array_map for closure and arrow function callbacks (#5716), #14649, #11656, thanks @VincentLanglet and @staabm!
- Support union types in str_repeat() (#5784), thanks @staabm!
- Report impossible class_exists/interface_exists/trait_exists/enum_exists (#5754), #14683, thanks @janedbal!
- Narrow variadic parameter array key integer type to
int<0, max>(#5791), #14744, thanks @staabm and @VincentLanglet! - Build an (unsealed) array shape in ArrayType::intersectKeyArray() when the other operand has known sealedness (#5792), #14747
- Resolve
WithoutImpurePointspurity transitively through calls to other effect-free callables (#5798), #14759 - ctype_digit() narrows to decimal-int-string (#5311), thanks @staabm!
- Infer
decimal-int-string/non-decimal-int-stringfor regex capturing groups matching (non-)digits (#5793), #14750, thanks @staabm, @VincentLanglet and @mvorisek! - Infer
decimal-int-stringwhen castingint/int<a, b>tostring(#5794), #14753, thanks @staabm and @VincentLanglet!
Bugfixes 🐛
- Create cross-kind conditional expression holders in
BooleanAnd/BooleanOrtype specifier with truthy fallback forisset()(#5760), #10644, #11918, #3385, #6202, #14455, thanks @VincentLanglet and @staabm! - Fix file path of trait errors reported directly in the trait (#5780), #14718, thanks @janedbal!
- PHPStan should not crash on startup when projects' composer.json is invalid (#5779), #14724, thanks @staabm!
- Narrow array key type when removing
HasOffsetTypeviaArrayType::tryRemove(#5756), #9461, thanks @VincentLanglet and @staabm! - Narrow value type instead of unsetting key in
ConstantArrayType::tryRemoveforHasOffsetValueType(#5776), #14711, thanks @VincentLanglet and @staabm! - Allow reinitialization of a readonly property in __clone since PHP8.3 (#5731), #11495, thanks @grizzm0!
- Omit key type from unsealed ConstantArrayType description when the unsealed extra type is
array-key(phpstan/phpstan-src@49074ec), #14732 - Revert "Return
list<mixed>fromPDOStatement::fetchAll()(#5643)" (#5795), thanks @staabm! - Treat declarations with a non-void
@throwsas not effect-free in theCallTo*StatementWithoutImpurePointsRulefamily (#5802), #14767
Function signature fixes 🤖
- Correct xdebug filename/trace function return types in functionMap to include
false/null(#5788), #14736
Internals 🔍
- Cleanup
instanceof ConstantStringType(#5783), thanks @staabm! - Cleanup
instanceof ConstantScalarType(#5785), thanks @staabm! - Simplify use of
getConstantScalarTypes()togetConstantScalarValues()(#5786), thanks @staabm! - PHPBench: use custom report format (#5789), thanks @staabm!
- Add missing
return(phpstan/phpstan-src@1643f14) - Add regression test (#5797), #14758, thanks @staabm!
2.2.1
Improvements 🔧
- Do not require specifying unsealed extra value type after
...on level 6+ (phpstan/phpstan-src@6ae7aa2)
Bugfixes 🐛
- Do not unpack unsealed array when expanding arguments in FunctionCallParametersCheck (phpstan/phpstan-src@7da57c9), #14715
- Fix constants allowed in parameters for multi-variant functions (phpstan/phpstan-src@4a57953), #14719
Function signature fixes 🤖
- Allow
FILTER_VALIDATE_BOOLas a valid constant forfilter_varandfilter_input(#5778), thanks @aprat84! - Add RoundingMode enum cases as valid constants of
round()(phpstan/phpstan-src@53fe519), #14716 - Fix Collator::setAttribute() allowed constants (phpstan/phpstan-src@f1a3110), #14720
2.2.0
Dive into details about this release on PHPStan's blog: PHPStan 2.2: Unsealed Array Shapes, Safer Array Keys, and More!. It explains all the changes and the motivation behind them.
Major new features 🚀
- Unsealed array shapes (#5501), #13565, #8438, #11494, #12110, #14032
- New types:
decimal-int-stringandnon-decimal-int-string(#5279) - New config parameter:
reportUnsafeArrayStringKeyCasting - Check constants in parameters (#5256), #12850
- New error identifiers:
- Detect named arguments whose parameters are renamed in subtypes (phpstan/phpstan-src@4c1a2b9), #7434, #5279
- New error identifier
argument.parameterRenamedInSubtype
- New error identifier
Bleeding edge 🔪
- Sealed array shapes are truly sealed
- Array shape like
array{a: int, b: string}does not allow for extra keys and does not accept general arrays
- Array shape like
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 🔧
- Allow custom rules to emit collector data for CollectedDataNode with CollectedDataEmitter (#5261)
- Reduced false positives about constant conditions in traits (#5309), #13023, #7599, #13474, #13687, #12798, #11949, #12267, #9515, #4570, #4121, #8060, #10353
Bugfixes 🐛
- Narrow division to int when modulo is known to be zero (#5757), #9724, thanks @VincentLanglet and @staabm!
- Do not normalize union types in tryRemove to preserve finite type combinations (#5744), #10128, #11453, thanks @VincentLanglet and @staabm!
- Prevent infinite recursion in
AttributeReflectionFactorywhen an attribute references itself on its constructor (#5773), #14707