Upgrade PHPStan to 2.x and raise analysis level from 6 to 10 #46
Reference in New Issue
Block a user
Delete Branch "chore/phpstan-2-upgrade"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Upgrades static analysis from PHPStan 1.12 (level 6) to PHPStan 2.2.2 at level 10 — the strictest setting — with every finding fixed for real rather than suppressed (3 targeted, justified
phpcs:ignorecomments are the only exceptions, where the WPCS sniff structurally cannot resolve closures/static calls).Dependency changes
phpstan/phpstan^1.10→^2.0(2.2.2),szepeviktor/phpstan-wordpress^1.3→^2.0phpstan.neon(was duplicated in the composer script)SQL-injection hardening (the big win)
All repository queries now pass table names through
wpdb::prepare()'s%iidentifier placeholder instead of string interpolation, so every query string is a compile-time literal and identifiers are escaped by WordPress. This raises the minimum WordPress version from 6.0 to 6.2 (where%iwas introduced).New:
Valboundary-coercion helperLevel 9/10 forbids using
mixeddirectly, and WordPress's APIs (wpdb,WP_REST_Request::get_param(), superglobals,get_option()) all returnmixed.src/Val.phpnarrows those values with explicit runtime checks (is_numeric,is_scalar) instead of blind casts — unexpected shapes degrade to safe defaults instead of leaking garbage. Value objects, endpoints, and controllers route boundary reads through it. Covered by unit tests.Real bugs fixed along the way
get_permalink()can returnfalse— was passed unguarded towp_login_url()in two shortcode pagesstrtotime()can returnfalse— was passed unguarded togmdate()in the payment reportwpdb::prepare()can returnnull— was passed unguarded towpdb::query()inupdateTax()get_users()results are now narrowed toWP_Userbefore mapping?? ''fallbacks removed whereisset()was already checkedVerification
composer lint— PHPStan level 10, no errorscomposer test— 221 tests, 681 assertions, all passingcomposer cs— PHPCS clean🤖 Generated with Claude Code