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

Параметры и именованные аргументы

Чему вы научитесь

Чему вы научитесь:

  • задавать параметрам значения по умолчанию и передавать аргументы по имени;
  • объявлять типы параметров и результата и объяснять, что меняет declare(strict_types=1);
  • предсказывать, изменит ли функция переданную ей переменную и какие переменные она видит;
  • писать функцию, которая вызывает саму себя, и вовремя её останавливать.
Кофейный автомат со щелью для монет $size, кнопкой sugar: 1 и стаканом в лотке со стрелкой return

Как вы уже знаете, функция получает аргументы, выполняет своё тело и возвращает результат через return. В этой теме мы разберём функции подробнее, и через всю тему пройдёт одна картинка — автомат с кофе.

Вы бросаете в автомат монеты и нажимаете кнопки — это аргументы. Автомат готовит напиток и выдаёт его в лоток — это результат return. У некоторых кнопок есть настройка на случай, если их не трогать: если не нажать кнопку сахара, автомат положит одну ложку.

У функции так же: параметру можно заранее задать значение, которое PHP подставит, если аргумента нет. Вот функция, которая описывает заказ:

PHP
<?php

function coffee($size, $sugar = 1, $milk = false)
{
    return $size . ' ml, sugar ' . $sugar . ($milk ? ', milk' : '');
}

echo coffee(200), "\n"; // 200 ml, sugar 1
echo coffee(300, 0), "\n"; // 300 ml, sugar 0
echo coffee(300, 2, true), "\n"; // 300 ml, sugar 2, milk

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

  1. coffee(200) передаёт один аргумент. Он попадает в $size, а $sugar и $milk получают заданные заранее 1 и false.
  2. coffee(300, 0) передаёт два аргумента: 300 попадает в $size, а 0 — в $sugar.
  3. coffee(300, 2, true) заполняет все три параметра, и в заказе появляется молоко.

Такие аргументы называют позиционными: они заполняют параметры по порядку, слева направо. Первый аргумент попадает в первый параметр, второй — во второй.

Значения по умолчанию

Запись $sugar = 1 в объявлении функции задаёт значение по умолчанию: PHP подставит 1, если вызов не передал этот аргумент. Параметр без такой записи, как $size, обязателен.

У таких параметров три правила:

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

Вот что будет, если вызвать coffee совсем без аргументов:

PHP
echo coffee(), "\n"; // ✗
TEXT
Fatal error: Uncaught ArgumentCountError: Too few arguments to function coffee(), 0 passed and at least 1 expected

Это ошибка, а не предупреждение: программа останавливается на этой строке. В сообщении сказано, что передано 0 аргументов, а нужен хотя бы 1 — значение для $size.

Здесь автомат и функция расходятся. Автомат без монеты молча ждёт, а функция без обязательного аргумента останавливает всю программу.

Именованные аргументы

Допустим, нужен кофе с молоком и обычной ложкой сахара. Позиционно придётся повторить сахар: coffee(300, 1, true). Чтобы пропустить середину, в PHP 8 есть именованные аргументы: перед значением пишут имя параметра без $ и двоеточие.

PHP
echo coffee(300, milk: true), "\n"; // 300 ml, sugar 1, milk
echo coffee(milk: true, size: 250), "\n"; // 250 ml, sugar 1, milk

Разберём по шагам:

  1. В первом вызове 300 попадает в $size по позиции, а milk: true — в $milk по имени.
  2. $sugar пропущен, поэтому получает значение по умолчанию 1.
  3. Во втором вызове названы оба аргумента, и их порядок уже не важен: size: 250 попадёт в $size, где бы он ни стоял.

Правила для именованных аргументов:

  • позиционные аргументы идут первыми, именованные — после них;
  • имя параметра пишут без знака $: milk: true;
  • нельзя задать по имени параметр, который уже получил значение от позиционного аргумента: на coffee(300, size: 200) PHP ответит Error: Named parameter $size overwrites previous argument;
  • имя должно совпадать с именем параметра: на coffee(300, mlk: true) PHP ответит Error: Unknown named parameter $mlk.

Именованные аргументы ещё и подписывают значения. Сравните coffee(300, 1, true) и coffee(300, milk: true): во втором вызове сразу видно, что значит true.

На собеседовании спрашивают, что меняют именованные аргументы. Ответ: аргумент находит параметр по имени, а не по позиции, поэтому необязательные параметры можно пропускать. У этого есть цена: имя параметра становится частью договора функции, и после переименования $milk вызовы с milk: true сломаются.

return завершает вызов

return не только отдаёт значение, но и сразу завершает вызов. Если return стоит внутри if и условие истинно, строки функции ниже уже не выполнятся.

Как вы уже знаете, функция без return тоже завершается, когда доходит до закрывающей скобки, и возвращает null.

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

Позиционный аргумент поставили после именованного:

PHP
echo coffee(milk: true, 300), "\n"; // ✗
TEXT
Fatal error: Cannot use positional argument after named argument

PHP проверяет порядок аргументов ещё до запуска, так же как синтаксис. Поэтому файл не выполняется вовсе: не напечатаются даже строки выше этой. Исправление — сначала позиционные аргументы, потом именованные: coffee(300, milk: true).

Главное

  • Параметр со значением по умолчанию можно не передавать; такие параметры ставят после обязательных.
  • Без обязательного аргумента вызов останавливает программу ошибкой ArgumentCountError.
  • Именованный аргумент milk: true находит параметр по имени, поэтому необязательные параметры перед ним можно пропустить.
  • Позиционные аргументы идут первыми, а return сразу завершает вызов.