# strict_types and Strict Typing in PHP Production

> strict_types in PHP: how declare(strict_types=1) changes type handling, where code breaks, and how to enable strict typing safely.

## What declare(strict\_types=1) Actually Does

The declare(strict\_types=1) directive must be the first executable line in a file, right after the opening \<?php tag. It does not enable typing as such — parameter and return types can be declared without it too. It changes only one thing: how PHP behaves when a passed value does not match the declared type.

Without strict\_types, PHP tries to coerce the value automatically: the string "42" becomes the int 42, the number 1 becomes the bool true. With strict\_types=1, any type mismatch, except the safe widening of int to float, throws a TypeError immediately at the point the function is called, not somewhere inside it after a few lines of logic.

## Weak Typing: an Example of Implicit Conversion

The function below declares an int parameter, but without strict\_types PHP will accept both a string and a floating-point number, silently cutting off the fractional part.

```
function applyDiscount(int $percent): float {
    return 100 - $percent;
}

echo applyDiscount("15abc"); // works as applyDiscount(15), no error
```

The string "15abc" is not a number, but PHP in weak mode cuts off the part that looks like a number and runs the function. The bug shows up not here but wherever the result turns out unexpectedly wrong — you end up hunting for it through the logs, as covered in the article [on reading PHP logs](https://www.zevshost.net/en/kb/php-logi-oshibok-razbor/).

## With strict\_types=1: the Same Error Is Caught Immediately

The same code with the directive added at the top of the file behaves differently — instead of a silent conversion, it fails explicitly.

```
declare(strict_types=1);

function applyDiscount(int $percent): float {
    return 100 - $percent;
}

echo applyDiscount("15abc");
// TypeError: applyDiscount(): Argument #1 ($percent) must be of type int, string given
```

The error appears right at the call site, with an exact line number, instead of after several steps of business logic. This matters especially for code written for PHP 8.3 and 8.4 — the new features of these versions are covered in the article [on PHP 8.3 and 8.4](https://www.zevshost.net/en/kb/php-84-novye-vozmozhnosti/), and they assume strict typing by default.

## Property, Parameter, and Return Types: Examples

| Construct | Example | What strict\_types Checks |
| --- | --- | --- |
| Parameter type | function f(int $x) | argument type at the call site |
| Return type | function f(): string | value type after return |
| Class property type | private float $price | type when assigning to the field |
| Nullable type | function f(?int $x) | allows int or null, not a string |

Nullable types and union types like int\|string work just as strictly with strict\_types: any value outside the declared list throws a TypeError.

## Where Strict Typing Breaks Existing Code

- Data from $\_GET and $\_POST always arrives as strings — cast it explicitly with (int) before passing it into a typed function.
- Values from PDO are also strings by default, even for numeric columns — without an explicit cast, strict\_types throws a TypeError.
- Old libraries without declared parameter types keep working as before; strict\_types does not affect them.
- JSON after json\_decode returns numbers as int or float depending on the content — check the type before passing it further.
- Tests written assuming automatic type coercion start failing and need explicit casts in the mocks.

## Summary: Checklist for Adopting strict\_types

- declare(strict\_types=1) is the first line after \<?php in every file of the project.
- All input data from $\_GET, $\_POST, and PDO is cast to the right type explicitly, instead of relying on automatic coercion.
- Parameters and return values of public methods have declared types, including nullable and union types.
- New TypeError occurrences are tracked through error\_log, not through display\_errors in production.
- The change is rolled out gradually, module by module, with tests run after every file.

---

Source: https://www.zevshost.net/en/kb/php-strict-types-tipizaciya/
