On this page
Strict Types
PHP 8 introduced and enhanced several features related to strict typing, also known as “strict mode.” This feature enforces stricter type checks during function calls. Here’s an overview of how it works:
1. Strict Types Declaration
- PHP allows you to enable strict typing on a per-file basis by declaring strict_types=1 at the beginning of the file. When strict types are enabled, PHP will enforce strict type checking for function calls and return types.
Copy code
<?php
declare(strict_types=1);
function add(int $a, int $b): int {
return $a + $b;
}
echo add(1, 2); // 3
echo add(1.5, 2.5); // TypeError: Argument 1 passed to add() must be of the type int, float given
2. Behavior of Strict Mode
- With
strict_types=1: PHP requires the exact data type specified in the function signature. If you pass a float where an integer is expected, aTypeErrorwill be thrown. - Without
strict_types=1(Default): PHP will attempt to coerce the type, converting a float to an integer, for example.
// Without strict_types=1
function add(int $a, int $b): int {
return $a + $b;
}
echo add(1.5, 2.5); // 3
3. Return Type Declarations
- PHP 8 allows you to specify the return type of a function. In strict mode, the returned value must match the declared return type exactly.
function multiply(float $a, float $b): float {
return $a * $b;
}
echo multiply(2.5, 4.2); // 10.5
4. TypeError Exceptions
- If a function is called with arguments that do not match the declared types, or if a function returns a value that does not match the declared return type, a TypeError exception will be thrown.
5. Nullable Types
- PHP 8 supports nullable types, which allow
nullto be passed to a function or returned from it, even if the type is otherwise strict.
function getName(?string $name): ?string {
return $name;
}
echo getName(null); // null
6. Union Types
- PHP 8 introduced union types, allowing a parameter or return type to accept more than one type.
function processInput(int|string $input): int|string {
if (is_int($input)) {
return $input * 2;
} else {
return strtoupper($input);
}
}
echo processInput(5); // 10
echo processInput("hello"); // HELLO
Strict Types Across Files
declare(strict_types=1) applies only to the file where it is declared. If FileA.php calls a function defined in FileB.php, strictness depends on the calling file:
// FileA.php — strict
declare(strict_types=1);
require 'FileB.php';
add(1.5, 2.5); // TypeError
// FileB.php — no strict declaration
function add(int $a, int $b): int { return $a + $b; }
Enable strict types in every project file for consistent behavior.
Scalar Type Declarations
PHP 7+ supports scalar hints on parameters and returns:
declare(strict_types=1);
function formatPrice(float $amount): string {
return number_format($amount, 2);
}
Intersection Types (PHP 8.1+)
declare(strict_types=1);
function process(Countable&Iterator $collection): void {
echo count($collection);
}
Readonly Properties (PHP 8.2+)
Combine strict typing with immutable objects:
declare(strict_types=1);
class User {
public function __construct(
public readonly int $id,
public readonly string $email,
) {}
}
Best Practices
- Add
declare(strict_types=1);as the first statement after<?phpin every new file. - Use union and nullable types instead of loose checks like
is_numeric(). - Let
TypeErrorsurface bugs early rather than silently coercing"123abc"to123.
Common Pitfalls
- Enabling strict types in only some files leads to inconsistent coercion behavior.
- Forgetting that JSON-decoded numbers arrive as
intorfloat, but form data arrives asstring. - Using weak comparison (
==) alongside strict types — prefer===everywhere.