Skip to content

Add a PHPStan path-coverage check: every PHP-containing dir must be explicitly included or excluded #10

@ballidev

Description

@ballidev

Problem

PHP files in directories that PHPStan never analyses silently escape ALL static-analysis rules. A real example: in a downstream project a $_ENV['X'] ?? '' silent-default smell lived in config/services.php and was never caught — even though ForbidNullCoalescingEmptyStringRule was enabled — because php-qa-ci's PHPStan runner only analyses src and tests, not config. The rule was active; the directory was simply never visited. This is a whole class of blind spot: any dir with .php files that isn't in the analysed set gets zero enforcement, invisibly.

Why this canNOT be a normal PHPStan (AST) rule

A PHPStan rule only fires on nodes inside files PHPStan actually visits. An un-analysed directory is never visited, so a rule placed there can never fire — chicken-and-egg. The enforcement must therefore be a standalone check/tool that runs as part of the php-qa-ci pipeline and inspects the project structure vs the analysis configuration, not the parsed AST.

Proposed solution

Add a php-qa-ci pipeline check (e.g. a tool runnable via qa -t stanPathCoverage, name open to maintainers) that:

  1. Enumerates every directory in the project that contains at least one .php file (excluding vendor/, build/cache output, and generated code by default).
  2. Reads the project's declared PHPStan analysis configuration — the analysed paths plus an explicit exclude list.
  3. FAILS the pipeline if any PHP-containing directory is neither explicitly included in the analysed paths nor explicitly excluded — forcing a conscious include/exclude decision for every such directory.

Intended default policy (overridable per project): vendor/ → exclude; src/, tests/, config/ → include. The key property is that adding a new top-level PHP dir (or a config/ that was silently unanalysed) trips the check until someone explicitly classifies it.

Acceptance criteria

  • A new check integrated into the php-qa-ci pipeline (and into the relevant meta-groups, e.g. allStatic).
  • Project-level configuration to declare include/exclude classifications (with sensible defaults).
  • The check fails with a clear, actionable message naming each unclassified PHP directory.
  • Tests covering: a fully-classified project (passes); a project with an unclassified PHP dir like config/ (fails); explicitly-excluded dirs (passes).
  • Docs describing configuration and rationale.

Context / origin

Surfaced during downstream work (checkout "plan 00097" — Zoho dual-account credentials) when a $_ENV[...] ?? '' smell in a vendor config/services.php slipped past an enabled ForbidNullCoalescingEmptyStringRule purely because config/ was outside the analysed paths. The fix for that one instance was applied directly; this issue is the "defence before fix" ratchet to prevent the entire class recurring across all php-qa-ci consumers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions