Перейти к содержимому
Теория · Функции · урок 4 из 11

declare(strict_types=1)

В режиме приведения PHP помогает: строка '5' сама становится числом 5. Но иногда такая помощь прячет ошибку. Если число пришло строкой, его, скорее всего, прочитали из формы или из файла и забыли преобразовать, а программа молча работает дальше.

Вернёмся к автомату. В прошлом уроке у него стоял услужливый служащий, который менял бумажку '5' на монету 5. Строка declare(strict_types=1); отпускает служащего: прорезь принимает только монету нужной формы.

Такая строка — директива: указание PHP, как читать этот файл. Директива strict_types=1 включает строгий режим: PHP не приводит аргументы и требует точного типа.

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

Давайте разберём программу по шагам:

  1. declare(strict_types=1); включает строгий режим для этого файла. Директиву ставят первой инструкцией, сразу после <?php.
  2. area(1.5) передаёт float, и тип совпадает с объявленным.
  3. area(3) передаёт int, и вызов всё равно работает: целое число в параметр float — единственная поблажка строгого режима.
  4. Результат 9.0 — дробное число без дробной части, поэтому echo печатает его как 9.

Что отвергает строгий режим

Строку с числом строгий режим уже не пропускает:

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

В строгом режиме параметр int принимает аргументы так:

  • '4' — TypeError, хотя в строке записано число;
  • 2.0 — TypeError, хотя дробной части нет;
  • true — TypeError;
  • 4 — проходит: тип совпадает.

Строгий режим действует и на встроенные функции: в таком файле strlen(123) тоже бросает TypeError.

Здесь картинка с автоматом упрощает. Строгий автомат всё-таки пропускает целую монету 3 в прорезь для дробных, int в float. В обратную сторону поблажки нет: 2.0 в параметр int не пройдёт.

Где действует директива

Программы побольше состоят из нескольких файлов, и директива действует только в том файле, где написана. Главное правило: важно, где стоит вызов, а не где объявлена функция.

  • Функция объявлена в файле без директивы, а вызов стоит в файле с ней: аргументы проверяются строго.
  • Функция объявлена в файле с директивой, а вызов стоит в файле без неё: PHP приводит аргументы, как обычно.
  • Результат функции проверяется по режиму того файла, где функция объявлена.
  • Директива не переходит в другие файлы: в каждом файле её пишут заново.

Этот вопрос часто задают на собеседовании: в каком файле должна стоять директива, чтобы вызов проверялся строго? Ответ — в файле, где написан вызов.

Зачем включать строгий режим

Новые проекты обычно ставят директиву в начало каждого файла. Причины:

  • ошибка видна там, где появилась: строка вместо числа останавливает вызов, а не превращается молча в число;
  • редакторы и программы-анализаторы кода опираются на точные типы и находят ошибки ещё до запуска;
  • код читается однозначно: какой тип объявлен, такой и придёт.

В остальных примерах курса директивы нет — так видно, как PHP приводит типы. В своих проектах включайте её.

Частая ошибка

Директиву поставили не первой инструкцией:

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 проверяет это до запуска, поэтому файл не выполняется вовсе — не напечатается даже start. Исправление — поставить директиву сразу после <?php, перед любым другим кодом.

Главное

  • declare(strict_types=1); первой инструкцией файла включает строгий режим: аргументы не приводятся.
  • В строгом режиме '4' и 2.0 для параметра int дают TypeError, а int для параметра float проходит.
  • Строгость вызова решает файл, где написан вызов, а не файл, где объявлена функция.