Type System
A type system is a formal set of rules that assigns a type to every expression in a program and uses those types to determine which operations are valid, how values are stored, and what errors can be detected before or during execution. Type systems span a spectrum from loose and implicit to strict and expressive.
Key dimensions of a type system:
- Static vs dynamic: static type checking happens before execution, as in C, Java, Rust, Haskell; dynamic type checking happens at runtime, as with Python, Ruby. A statically typed language catches type errors at compile time; a dynamically typed one catches them only when the erroneous operation is executed.
- Strong vs weak: a strongly typed language refuses implicit coercion between incompatible types, as in Python, Rust; a weakly typed one performs automatic conversions, as in classic C, early PHP. Strength is orthogonal to static vs dynamic.
- Nominal vs structural: nominal typing requires explicit declaration of type relationships,
class Foo implements Bar; structural typing, as in Go interfaces,TypeScriptconsiders two types compatible if they share the same shape, regardless of declaration. - Sound vs unsound: a sound type system guarantees that well-typed programs never produce type errors at runtime. PHP’s type system, even with strict_types, is unsound:
mixedparameters, union types, and coercion paths leave runtime type errors possible.
PHP’s type system has evolved significantly:
- Pre-PHP 5: no type declarations; all typing is dynamic and implicit.
- PHP 5: class and interface type on parameters;
arrayandcallablehints added in 5.1/5.4. - PHP 7.0: scalar type declarations,
int,float,string,bool, return type declarations,declare(strict_types=1). - PHP 7.1: nullable types
?Type,voidreturn type,iterablepseudo-type. - PHP 7.2:
objecttype. - PHP 8.0: union types
int|string,mixed,staticreturn type,#[Attribute]for typed metadata,matchwith strict comparison. - PHP 8.1: intersection types
Countable&Iterator,neverreturn type,readonlyproperties. - PHP 8.2:
true,false,nullas standalone types, DNF types(A&B)|C, readonly classes. - PHP 8.3+: typed class constants,
\Overrideattribute.
Static analysers add a richer layer of type inference and generics @template on top of PHP’s native declarations, providing near-sound type checking as a development tool without changing runtime behaviour.
<?php
declare(strict_types=1);
// Union type (PHP 8.0): parameter accepts int or string
function formatId(int|string $id): string {
return (string) $id;
}
// Intersection type (PHP 8.1): must implement both interfaces
function processCollection(Countable&Iterator $col): void {
foreach ($col as $item) { /* ... */ }
}
// Readonly property (PHP 8.1): immutable after construction
class Point {
public function __construct(
public readonly float $x,
public readonly float $y,
) {}
}
// DNF type (PHP 8.2): (A&B)|null
interface Serializable {}
interface Loggable {}
function handle((Serializable&Loggable)|null $obj): void {
if ($obj === null) return;
// $obj is guaranteed to implement both interfaces here
}
// generic annotation (static analysis only, no runtime effect)
/** @template T of \DateTimeInterface */
class TimestampedCollection {
/** @var list<T> */
private array $items = [];
/** @param T $item */
public function add(mixed $item): void { $this->items[] = $item; }
}
?>
See Also
Related
- strict_types
- Union Type
- Intersection Type
- Nullable
- Generics
- Readonly
- Template Metaprogramming (TMP)
- Static Code Analysis (SCA)
- Algebraic Data Type
- Existential Type
- Generalized Algebraic Data Type (GADT)
- Higher-Kinded Type
- Linear Type
- Phantom Type
- Refinement Type
- Row Polymorphism
- Semantic Analysis
- Array Shape
- Effect System
- Nominal Type
- Structural Typing
- Type Class
- Type Narrowing
- Type Widening