Skip to content

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.

task phpstan:analyse

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 PHPDoc
  • missingType.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
  • Narrowinginstanceof, 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.

task rector

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

  1. Always review changes before committing
  2. Run tests after applying transformations
  3. 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.

task tests:all          # Generate coverage reports
sonar-scanner           # Run analysis