Static Analysis
Phexium uses static analysis tools to maintain code quality and enforce modern PHP practices.
PHPStan
PHPStan proves type correctness without running the code.
Configuration
PHPStan is configured in phpstan.neon: level 9, analysing src/ and app/.
Level 9, deliberately
Level 9 means every explicitly declared mixed value must be narrowed before use. Level 10 would extend this to implicit mixed — chiefly every value read from an untyped array. Typing those requires PHPDoc array shapes (array{title: string}), and PHPDoc blocks are forbidden by framework convention: types live in native declarations only. Level 9 is therefore the ceiling, by design, not by debt.
For the same reason, two rules that can only be satisfied with annotations are disabled in phpstan.neon:
missingType.iterableValue— array value types (array<Book>) require PHPDocmissingType.generics— generics (@template) require PHPDoc
One scoped exemption exists: the application config files (app/*/config/*) wire the applications from $_ENV and PSR-11 get() calls, which both return mixed. This composition-root code is fully exercised at boot by the acceptance suites.
Fixing errors without PHPDoc
Never fix a PHPStan error by adding a docblock. The native toolbox, in order of preference:
- Native type declarations — parameters, returns, properties
- Narrowing —
instanceof,is_string(),is_array()guards at the boundary where a type is erased (container, cache, session, request attributes) - Typed closure parameters —
$books->mapToArray(fn (Book $book): array => ...)proves collection element types without generics - Small typed objects — replacing an array contract with a value object or DTO removes the need for array shapes
- Baseline: never — errors are fixed or explicitly justified in
phpstan.neon, not accumulated
Rector
Rector automates code refactoring and modernization.
Configuration
Rector is configured in rector.php:
return RectorConfig::configure()
->withPaths([__DIR__.'/app', __DIR__.'/src', __DIR__.'/tests'])
->withPhpSets(php84: true)
->withPreparedSets(
deadCode: true,
codeQuality: true,
typeDeclarations: true,
earlyReturn: true,
);
Common Transformations
Constructor Property Promotion:
// Before
class Book {
private string $title;
public function __construct(string $title) {
$this->title = $title;
}
}
// After
class Book {
public function __construct(private string $title) {}
}
Early Return:
// Before
if ($condition) {
return $this->process();
}
return null;
// After
if (!$condition) {
return null;
}
return $this->process();
Safe Usage
- Always review changes before committing
- Run tests after applying transformations
- Use version control to revert unwanted changes
SonarQube
SonarQube provides comprehensive static analysis including code smells, bugs, and vulnerabilities. Configuration is in sonar-project.properties.