Skip to content

phpstan.neon default paths silently miss custom code kept outside web/modules/custom #41

Description

@UltraBob

Summary

The phpstan.neon the add-on installs (from the Drupal GitLab CI template) limits analysis to:

paths:
    - web/modules/custom
    - web/themes/custom
    - web/sites

Projects that keep their custom modules somewhere other than web/modules/custom get zero PHPStan coverage of that code, silently. There's no error — PHPStan runs green because it simply never looks at the files.

Real-world example

On a project using a web/modules/common/ directory for custom modules, web/modules/custom/ contained only a .gitkeep. PHPStan reported success on every run while never analysing a single line of the project's actual custom code. The gap was only noticed by accident when comparing IDE diagnostics (intelephense/phpcs) against PHPStan output on the same file.

This is easy to miss because:

  • web/modules/custom is the template default, so it's rarely revisited.
  • An empty or near-empty custom dir still makes PHPStan exit 0.
  • ddev checks shows PHPStan passing, which reads as "analysed and clean," not "analysed nothing."

Suggested change

Default to analysing all of web/modules and carve out contrib, so custom code is covered regardless of a project's directory convention:

paths:
    - web/modules
    - web/themes/custom
    - web/sites
excludePaths:
    analyseAndScan:
        - web/modules/contrib/*
        # ...existing web/sites excludes...

Notes on the specifics:

  • analyseAndScan (not analyse) for contrib: mglaman/phpstan-drupal resolves contrib classes on demand via Drupal's autoloader, so PHPStan still understands calls into contrib without scanning the whole contrib tree (faster, and avoids parse errors in third-party code).
  • The /* is deliberate: PHPStan matches excludePaths with fnmatch where * crosses /, so web/modules/contrib/* excludes the subtree recursively.

Adoption caveat worth documenting

Broadening coverage will surface a batch of previously-unseen findings on existing projects. The add-on could pair this with guidance to run ddev phpstan --generate-baseline on first adoption so old debt is captured and only new regressions fail.

Possible approaches for the add-on

  1. Change the installed default to the web/modules + contrib-exclusion form above.
  2. Or detect custom-code locations at install time (scan for web/modules/*/ dirs containing .info.yml outside contrib) and write matching paths.
  3. At minimum, document the limitation and the one-line fix so users know to check whether their custom code is actually in scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions