shipmonk/phpstan-rules
ShipMonk PHPStan strict rules adds about 40 opinionated, super-strict checks beyond native PHPStan, targeting gaps like unsafe comparisons, casts, and array keys. Install via Composer, include rules.neon, and disable or reconfigure any rule per project.
Strengths:
readonly properties, match for enums, forbidding unsafe casts). This aligns with Laravel’s evolving PHP 8.x+ features (e.g., enums, attributes, generics).enforceReadonlyPublicProperty for immutable DTOs, forbidCast for type safety).stubFiles for BackedEnumGenerics), reducing duplication and tooling overhead.iterator_to_array, checked exceptions in closures for queues/jobs).Gaps:
enforceReadonlyPublicProperty) are PHP 8.2+ only, requiring version gates or polyfills.composer require --dev, with minimal config changes (e.g., adding includes to phpstan.neon). Pin to ^4.4.1 to pick up the callable-resolution fixes.classSuffixNaming requires mapping superclasses to suffixes). TPMs can start with defaults and refine.phpstan/extension-installer or custom scripts.forbidCheckedExceptionInCallable: 4.4.1 resolves the static-call caller type from expressions (#368). This removes a class of incorrect reports on static dispatch and should materially reduce noise in code that uses Laravel facades, static helpers, and container ::make()/::resolve() patterns. Prior mitigations via allowedCheckedExceptionCallables may now be removable.requirePreviousExceptionPass: 4.4.1 accepts an exception passed to a nested call (#369). Wrapping/rethrowing patterns such as throw new X(..., previous: $e) nested inside another call no longer produce false positives, which was a common friction point in Laravel exception-handling and job-retry code.enforceEnumMatch may still flag legitimate patterns (e.g., dynamic closures in Laravel’s tap() or when()). forbidCast may still break legacy code using (array) on null; mitigate with blacklist exceptions.enforceEnumMatch for PHPStan 1.10.x quirks). TPMs must monitor updates and adjust configs.BackedEnumGenerics) require manual stub file management.forbidArithmeticOperationOnNonNumber) may cause friction. TPMs should phase them in (e.g., warn-only mode first).enforceNativeReturnTypehint for legacy methods vs. forbidCast for new code)?phpstan.neon) vs. per-repo overrides?ignoreErrors).allowedCheckedExceptionCallables and requirePreviousExceptionPass suppressions can be deleted now that 4.4.1 fixes the underlying resolution? Audit the allowlists for dead entries before they mask real issues.--memory-limit and --parallel.HasFactory traits or Nova resources)?--error-format=json and custom scripts.forbidCheckedExceptionInCallable and requirePreviousExceptionPass reports; an unchanged count suggests the suppressions were masking something else.phpstan-baseline.php for legacy code).readonly, match) that Laravel 9+ encourages. 4.4.1’s static-call resolution fix improves behaviour specifically on facade- and container-style static dispatch.Illuminate\Support\Collection methods). TPMs must manually whitelist or configure exceptions.forbidCheckedExceptionInCallable help catch issues in test doubles or mocks.enforceNativeReturnTypehint).forbidCheckedExceptionInYieldingMethod reduce runtime errors in queues/jobs.phpstan analyse --generate-baseline).forbidCast, enforceReadonlyPublicProperty) and enable them incrementally.parameters:
shipmonkRules:
forbidCast:
blacklist!: ['(array)'] # Allow (array) on Collections
forbidCheckedExceptionInCallable:
allowedCheckedExceptionCallables:
'Illuminate\Queue\CallQueuedHandler::handle': 0 # Allow in jobs
vendor, storage/framework/views)..github/workflows/phpstan.yml:
- name: PHPStan
run: phpstan analyse --level=max --error-format=github
--fix for auto-fixable rules (e.g., enforceNativeReturnTypehint).(array) casts").enforceEnumMatch for enum handling).enforceReadonlyPublicProperty require PHP 8.2+. Use feature flags or polyfills for older versions.1.10.x) to avoid rule conflicts (e.g., enforceEnumMatch for PHPStan 1.10.0–1.10.34 quirks). Validate 4.4.1 against your pinned PHPStan version before rollout — the #368 fix changes caller-type resolution and can shift results on existing baselines.BackedEnumGenerics).laravel/framework, spatie/laravel-package-tools).enforceNativeReturnTypehint, enforceIteratorToArrayPreserveKeys).forbidCast, forbidArithmeticOperationOnNonNumber.enforceReadonlyPublicProperty, enforceClosureParamNativeTypehint.forbidCheckedExceptionInCallable, enforceEnumMatch — now the preferred entry point for these two given the 4.4.1 precision fixes.ignoreErrors for known issues:
ignoreErrors:
- '#Method .* has no PHPDoc or return typehint#' # For old controllers
storage/logs) or use --exclude-paths.phpstan --cache-results.enforceEnumMatch for PHPStan 1.11+). TPMs should:
forbidCheckedExceptionInCallable and nested-exception workarounds for requirePreviousExceptionPass are now partly obsolete. Assign ownership for pruning them; stale suppressions silently erode the value of the rule set.phpstan.neon, and decide suppression vs. refactor. Without a named owner, allowlists accrete.ignoreErrors scoped to path and message rather than disabling the rule globally.--parallel, --memory-limit, and path exclusions; measure before adding all ~40 rules to large monorepos.^4.4.1) and a shared config package so teams inherit the same rule set; per-repo overrides should be additive and reviewed.How can I help you explore Laravel packages today?