Skip to content
Theory · Functions · lesson 4 of 11

declare(strict_types=1)

In coercive mode PHP helps: the string '5' becomes the number 5 by itself. But sometimes that help hides a bug. If a number arrived as a string, it was most likely read from a form or a file and nobody converted it, while the program quietly goes on.

Back to the machine. In the last lesson it had an obliging attendant who changed the note '5' into a 5 coin. The line declare(strict_types=1); sends the attendant home: the slot takes only a coin of the right shape.

Such a line is a directive: an instruction to PHP on how to read this file. The directive strict_types=1 turns on strict mode: PHP does not convert arguments and demands the exact type.

PHP
<?php

declare(strict_types=1);

function area(float $side): float
{
    return $side * $side;
}

echo area(1.5), "\n"; // 2.25
echo area(3), "\n"; // 9

Let's go through the program step by step:

  1. declare(strict_types=1); turns on strict mode for this file. The directive goes first, right after <?php.
  2. area(1.5) passes a float, and the type matches the declared one.
  3. area(3) passes an int, and the call still works: a whole number for a float parameter is the one allowance of strict mode.
  4. The result 9.0 is a fraction with no fractional part, so echo prints it as 9.

What strict mode refuses

A string holding a number no longer gets through in strict mode:

PHP
echo area('3'), "\n"; // ✗
TEXT
Fatal error: Uncaught TypeError: area(): Argument #1 ($side) must be of type float, string given

Here is what happens to arguments for an int parameter in strict mode:

  • '4': a TypeError, although the string holds a number;
  • 2.0: a TypeError, although there is no fractional part;
  • true: a TypeError;
  • 4: passes, because the type matches.

Strict mode applies to built-in functions too: in such a file strlen(123) also throws a TypeError.

Here the machine picture simplifies things. The strict machine still lets a whole 3 coin into the slot for fractions, an int into a float. There is no allowance the other way round: 2.0 will not get into an int parameter.

Where the directive applies

Bigger programs are made of several files, and the directive applies only in the file where it is written. The main rule: what matters is where the call stands, not where the function is declared.

  • The function is declared in a file without the directive, and the call stands in a file with it: the arguments are checked strictly.
  • The function is declared in a file with the directive, and the call stands in a file without it: PHP converts the arguments as usual.
  • A function's result is checked by the mode of the file where the function is declared.
  • The directive does not carry over to other files: each file has to state it again.

Interviewers often ask this: in which file must the directive stand for a call to be checked strictly? The answer: in the file where the call is written.

Why turn on strict mode

Most modern projects put the directive at the top of every file. The reasons:

  • an error shows up where it appears: a string instead of a number stops the call instead of quietly turning into a number;
  • editors and code analyzers rely on exact types and find bugs before the program runs;
  • the code reads one way only: whatever type is declared is the type that arrives.

The rest of the course's examples have no directive, so you can see how PHP converts types. Turn it on in your own projects.

Common mistake

The directive was not put first:

PHP
<?php

echo 'start', "\n";
declare(strict_types=1); // ✗
TEXT
Fatal error: strict_types declaration must be the very first statement in the script

PHP checks this before the run, so the file does not run at all, and not even start prints. The fix is to put the directive right after <?php, before any other code.

Key points

  • declare(strict_types=1); as the first statement of a file turns on strict mode: arguments are not converted.
  • In strict mode, '4' and 2.0 for an int parameter give a TypeError, while an int for a float parameter passes.
  • Whether a call is strict is decided by the file where the call is written, not the file where the function is declared.