diff --git a/composer.json b/composer.json index 7b0b606..f5a94ef 100644 --- a/composer.json +++ b/composer.json @@ -34,10 +34,13 @@ "mockery/mockery": "^1.6", "php-parallel-lint/php-parallel-lint": "^1.4", "phpcompatibility/phpcompatibility-wp": "^2", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.2", "phpunit/phpunit": "^9.6", "rector/rector": "^2.4", "roave/security-advisories": "dev-latest", "squizlabs/php_codesniffer": "^3", + "szepeviktor/phpstan-wordpress": "^2.0", "wp-coding-standards/wpcs": "^3", "yoast/phpunit-polyfills": "^4" }, @@ -58,7 +61,8 @@ "composer/installers": true, "dealerdirect/phpcodesniffer-composer-installer": true, "ergebnis/composer-normalize": true, - "infection/extension-installer": true + "infection/extension-installer": true, + "phpstan/extension-installer": true }, "sort-packages": true }, @@ -72,6 +76,7 @@ "@php ./vendor/bin/parallel-lint . --exclude vendor --exclude node_modules", "bin/xml-lint" ], + "phpstan": "phpstan analyse", "rector": "@php ./vendor/bin/rector process --dry-run", "rector:fix": "@php ./vendor/bin/rector process", "test": [ @@ -100,6 +105,7 @@ "infection": "Run mutation testing with Infection.", "integration": "Deprecated alias for test:integration, kept until CI moves to the new script names.", "lint": "Check PHP files for syntax errors and XML config files against their schemas.", + "phpstan": "Run static analysis with PHPStan.", "rector": "Preview automated refactorings with Rector (dry run).", "rector:fix": "Apply automated refactorings with Rector.", "test": "Run the quick checks: lint, coding standards, and unit tests.", diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..c0ae816 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,18 @@ +# PHPStan configuration. +# +# The WordPress stubs and rules are loaded automatically from +# szepeviktor/phpstan-wordpress via phpstan/extension-installer. +# +# views/ and config/ are deliberately not analysed: those files are pulled in +# via include/require and rely on variables injected into their scope at +# runtime (template data, plugin constants), which PHPStan cannot see. +# +# Level 8 is the ceiling for this codebase: level 9 adds checkExplicitMixed, +# which fights the untyped boundary of config-driven WordPress code — the +# BrightNucleus Config accessors return mixed by design. Revisit if the +# config ever gains a typed accessor layer. +parameters: + level: 8 + paths: + - plugin-slug.php + - src