re #96 raise PHPStan to level 7, zero baseline#113
Merged
Conversation
added 2 commits
May 28, 2026 10:16
Raise phpstan.neon.dist level 6 -> 7 and fix all 183 new findings at root cause across ~20 packages (parallel per-package sub-agents + central verification). No baseline; PHPStan [OK] at level 7. Full suite green (only the pre-existing ext-mongodb-absent MongoSessionHandlerTest errors). Representative root-cause fixes (no silencing casts/ignores): - json_encode/preg_*/file_* and other "string|false" returns guarded or given JSON_THROW_ON_ERROR; generator methods returning ?Generator -> Generator. - argument.type from mixed flows fixed by propagating generics, precise param/return types, or genuine instanceof / is_* narrowing at boundaries. - PhpToken::tokenize() / FilesystemIterator results normalised to list / guarded with instanceof SplFileInfo; class-string<T> @param added before ReflectionClass. - Persistence DatabaseSettings now validates non-empty host / positive port to satisfy Cycle's non-empty-string/int<1,max> connection-config constructors. - Real bug: DefaultErrorHandler dispatched on handler name vs media type + a missing plain() responder; IpRule netmask via integer bit-shift. - Structure end()/array_key_last narrowing, intdiv for capacity, __get no longer writes null into TKey/TValue-typed properties. Documented exceptions (config ignoreErrors, not inline) for the php-ds-derived shared-trait design: CollectionTrait is used by both array-backed collections and delegate-backed adapters (Set/Stack/Queue narrow $internal to an object but must keep the trait's `$internal = []` default), so the trait's array-backed storage/append/capacity hook reads as invalid when analysed in the adapter context. These are intentional-design artefacts, not reachable bugs.
The level-7 narrowing assumed findOne() returns an array, but it returns a BSONDocument object by default, so read() always returned '' and broke the write/read round-trip on CI (where ext-mongodb is loaded). Pass a typeMap so findOne genuinely returns an array, keeping the is_array narrowing valid.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Raises
phpstan.neon.distfrom level 6 → 7 and fixes all 183 new findings at root cause across ~20 packages — no baseline, PHPStan[OK]at level 7. Parallelized via per-package sub-agents with central verification (full stan + test + rector + cs).Representative fixes (no silencing casts/ignores)
string|falsereturns (json_encode,preg_*,file_*,finfo_*, session funcs) guarded or givenJSON_THROW_ON_ERROR;?Generator→Generator.argument.typefrommixedflows fixed by propagating generics, precise param/return types, or genuineinstanceof/is_*narrowing at boundaries.PhpToken::tokenize()/FilesystemIteratorresults normalised tolist/ guarded withinstanceof SplFileInfo;class-string<T>params beforeReflectionClass.DatabaseSettingsvalidates non-empty host / positive port to satisfy Cycle'snon-empty-string/int<1,max>connection-config constructors.DefaultErrorHandlerdispatched on handler name vs media type + a missingplain()responder;IpRulenetmask via integer bit-shift.end()/array_key_lastnarrowing,intdivfor capacity,__getno longer writesnullintoTKey/TValue-typed properties.Documented exceptions (config
ignoreErrors, with rationale)CollectionTraitis shared by array-backed collections (Map/Vector/Deque) and delegate-backed adapters (Set→Map, Stack→Vector, Queue→Deque). The adapters narrow$internalto a delegate object but PHP's trait rules force them to keep the trait's$internal = []default, and PHPStan analyses the trait's array-backed storage per using-class. These are intentional shared-trait-design artefacts, not reachable bugs.Test plan
composer stan(level 7, no baseline) —[OK] No errorscomposer cs(cache-free) — cleanvendor/bin/rector process --dry-run(full) — cleancomposer test— 5555 tests; only pre-existing localMongoSessionHandlerTestenv errors (CI loads ext-mongodb)