Lesson 11 / 25
The Type System and Static Analysis
Use union, intersection, nullable and special types, and catch bugs with PHPStan or Psalm.
Types that document and protect
PHP's type system has grown considerably. Nullable types (?string), union types (int|string, PHP 8.0), intersection types (Countable&Traversable, 8.1) and DNF types combining both ((A&B)|null, 8.2) describe precise contracts. Special types: mixed (anything), void, never (always throws or exits), static (the called class, useful in fluent factories), iterable, and standalone null, true and false (8.2). PHP 8.3 added typed class constants. Still, runtime types cannot express everything, such as the shape of an array or generics like "a collection of Orders". Static analysers fill the gap: PHPStan and Psalm read your code without running it, understand docblock types such as array<string, Order>, list<int> and Collection<Order>, and report type errors, undefined methods, unreachable code and possible null dereferences. Start at a low strictness level and raise it over time, use a baseline file for legacy code, and run analysis in CI on every pull request.
Precise types plus docblock generics for static analysis
Runtime types where PHP supports them; docblocks where it does not.
<?php
declare(strict_types=1);
final class OrderRepository
{
/** @var array<string, Order> */
private array $orders = [];
public function find(string $id): ?Order
{
return $this->orders[$id] ?? null;
}
/** @return list<Order> */
public function byStatus(OrderStatus $status): array
{
return array_values(array_filter($this->orders, fn (Order $o): bool => $o->status === $status));
}
public function idOf(Order|string $orderOrId): string // union type
{
return $orderOrId instanceof Order ? $orderOrId->id : $orderOrId;
}
public function fail(string $reason): never // always throws
{
throw new RuntimeException($reason);
}
}
// vendor/bin/phpstan analyse src --level=8
// PHPStan would flag: $repo->find('x')->total (possible null dereference)A building inspector before move-in
Runtime type checks are like discovering a missing step when you fall on the stairs. Static analysis is the inspector who walks through before anyone moves in and marks every missing step on the plan.
Quick check: What does PHPStan or Psalm add on top of PHP's runtime type declarations?
- A faster interpreter
- Static checking of code, including docblock types such as array shapes and generics, without running it
- A web server
- Automatic database migrations
Answer
Static checking of code, including docblock types such as array shapes and generics, without running it — Static analysers find type errors and bugs before the code runs.