Функция принимает информацию в виде списка аргументов — выражений через запятую. Аргументы вычисляются слева направо перед действительным вызовом функции. Такое вычисление называют энергичным.
PHP поддерживает передачу аргументов по значению (по умолчанию), передачу аргументов по ссылке, и значения по умолчанию. Списки аргументов переменной длины и именованные аргументы также поддерживаются.
Пример #1 Передача массивов в функции
<?php
function takes_array($input)
{
echo "$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>
Начиная с PHP 8.0.0 списку аргументов функции разрешается включать конечную запятую, которую парсер проигнорирует. Это полезно, когда список аргументов длинный или содержит длинные имена переменных, что в целях удобства подталкивает к вертикальному перечислению аргументов.
Пример #2 Список аргументов функции с конечной запятой
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // Конечная запятая не допускалась до PHP 8.0.0
) {
// ...
}
?>
По умолчанию аргументы функции передаются по значению (поэтому если значение аргумента внутри функции изменится, значение не изменится за пределами функции). Аргументы передают по ссылке, чтобы разрешить функции изменять значения аргументов.
В описании функции перед именем параметра указывают амперсанд &, когда требуется передача аргумента по ссылке:
Пример #3 Передача аргументов по ссылке
<?php
function add_some_extra(&$string)
{
$string .= 'и кое-что ещё.';
}
$str = 'Это строка, ';
add_some_extra($str);
echo $str; // Выведет «Это строка, и кое-что ещё.»
?>
Передача в виде аргумента значения в параметр, который ждёт ссылку, — ошибка.
Функция умеет определять для параметров значения по умолчанию, в этом помогает синтаксис, который похож на синтаксис присваивания значения переменной. Функция присвоит параметру значение по умолчанию, только если в параметр не передали аргумент; обратите внимание, что функция не присваивает параметру значение по умолчанию при передаче в параметр аргумента со значением null
.
Пример #4 Значения по умолчанию для параметров в функциях
<?php
function makecoffee($type = "капучино")
{
return "Готовим чашку $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("эспрессо");
?>
Результат выполнения приведённого примера:
Готовим чашку капучино. Готовим чашку . Готовим чашку эспрессо.
Значениями по умолчанию для параметров разрешается указывать скалярные значения, массивы (array), специальный тип null
и начиная с PHP 8.1.0 объекты, которые создают синтаксисом new ClassName().
Пример #5 Нескалярные типы как значения по умолчанию
<?php
function makecoffee($types = array("капучино"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker)
? "вручную"
: $coffeeMaker
;
return "Готовлю чашку " . join(", ", $types) . " $device. \n";
}
echo makecoffee();
echo makecoffee(array("капучино", "лавацца"), "в чайнике");
?>
Результат выполнения приведённого примера:
Готовлю чашку капучино вручную. Готовлю чашку капучино, лавацца в чайнике.
Пример #6 Объекты как значения по умолчанию, с PHP 8.1.0
<?php
class DefaultCoffeeMaker
{
public function brew()
{
return "Приготовление кофе.\n";
}
}
class FancyCoffeeMaker
{
public function brew()
{
return "Приготовление прекрасного кофе только для вас.\n";
}
}
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
{
return $coffeeMaker->brew();
}
echo makecoffee();
echo makecoffee(new FancyCoffeeMaker);
?>
Результат выполнения приведённого примера:
Приготовление кофе. Приготовление прекрасного кофе только для вас.
Значение по умолчанию должно быть константным выражением, а не, например, переменной, вызовом функции или метода класса.
Обратите внимание, что необязательные аргументы требуется указывать после обязательных аргументов, иначе необязательные аргументы не получится опустить при вызове. Рассмотрим следующий пример:
Пример #7 Неправильное определение значений по умолчанию для параметров функции
<?php
function makeyogurt($container = "миску", $flavour)
{
return "Делаем $container с $flavour йогуртом.\n";
}
echo makeyogurt("малиновым"); // Значение «малиновым» получит параметр $container, а не $flavour
?>
Результат выполнения приведённого примера:
Fatal error: Uncaught ArgumentCountError: Too few arguments to function makeyogurt(), 1 passed in example.php on line 42
Теперь сравним приведённый пример со следующим примером:
Пример #8 Правильное определение значений по умолчанию для параметров функции
<?php
function makeyogurt($flavour, $container = "миску")
{
return "Делаем $container с $flavour йогуртом.\n";
}
echo makeyogurt("малиновым"); // Значение «малиновым» получит параметр $flavour
?>
Результат выполнения приведённого примера:
Делаем миску с малиновым йогуртом.
Начиная с PHP 8.0.0 для пропуска нескольких необязательных параметров передают именованные аргументы.
Пример #9 Правильное определение значений по умолчанию для параметров функции
<?php
function makeyogurt($container = "миску", $flavour = "малиновым", $style = "греческим")
{
return "Делаем $container с $flavour$style йогуртом.\n";
}
echo makeyogurt(style: "натуральным");
?>
Результат выполнения приведённого примера:
Делаем миску с малиновым натуральным йогуртом.
С PHP 8.0.0 объявление обязательных аргументов после необязательных устарело. Обычно из таких ситуаций выходят за счёт отказа от значения по умолчанию, поскольку функция никогда не присвоит параметру, в который передали аргумент, значение по умолчанию. Исключение из этого правила — аргументы вида Type $param = null
, где null
по умолчанию делает тип неявно обнуляемым. Такое определение остаётся допустимым, хотя рекомендуется указывать явный обнуляемый тип.
Пример #10 Объявление необязательных аргументов после обязательных аргументов
<?php
function foo($a = [], $b) {} // Функция не присвоит значение по умолчанию; устарело с PHP 8.0.0
function foo($a, $b) {} // Функционально эквивалентны, без уведомления об устаревании
function bar(A $a = null, $b) {} // Всё ещё разрешается; переменная $a обязательна, но допускает значение null
function bar(?A $a, $b) {} // Рекомендуется
?>
Замечание: Начиная с PHP 7.1.0 пропуск параметра, для которого не задали значение по умолчанию, выбрасывает исключение ArgumentCountError; в предыдущих версиях это выдавало предупреждение.
Замечание: Для параметров, которые ждут, что аргумент передадут по ссылке, разрешается устанавливать значения по умолчанию.
PHP поддерживает в пользовательских функциях списки аргументов переменной длины, параметры для которых определяют оператором из трёх точек ...
, который называется spread-оператором.
Списку параметров разрешается содержать оператор ...
, чтобы показать, что функция принимает переменное количество аргументов. Переменная получит аргументы как массив:
Пример #11 Оператор ...
для доступа к аргументам
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
Результат выполнения приведённого примера:
10
Spread-оператор ...
указывают также при вызове функции, чтобы распаковать в список аргументов массив (array), или распаковать переменную или литерал, которые принадлежат типу Traversable:
Пример #12 Передача аргументов через spread-оператор ...
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
Результат выполнения приведённого примера:
3 3
Разрешается указывать стандартные позиционные параметры, а за ними параметр с оператором ...
, тогда оператор ...
сгенерирует и добавит в массив только конечные аргументы, позиции которых не совпали с позиционными аргументами.
Разрешается также добавлять перед оператором ...
объявление типа. Тогда аргументы, которые захватил оператор ...
, должны соответствовать типу параметра.
Пример #13 Аргументы с подсказкой типа
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// Это не сработает, поскольку null — не объект класса DateInterval
echo total_intervals('d', null);
?>
Результат выполнения приведённого примера:
3 days Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
В финале добавим, что разрешается также передавать аргументы переменной длины по ссылке, для этого перед оператором ...
указывают амперсанд (&
).
В PHP 8.0.0 как расширение позиционных параметров появились именованные аргументы. Именованные аргументы передают в функцию на основе имени, а не позиции параметра. Назначение аргумента документирует само себя, аргументы перестают зависеть от порядка, в котором их передают, и разрешается произвольно пропускать значения по умолчанию.
Именованные аргументы передают по имени параметра, за которым идёт двоеточие и значение аргумента. Разрешается указывать зарезервированные ключевые слова как имена параметров. Имя параметра должно быть идентификатором, нельзя указывать динамические имена параметров.
Пример #14 Синтаксис именованного аргумента
<?php
myFunction(paramName: $value);
array_foobar(array: $value);
// НЕ поддерживается
function_name($variableStoringParamName: $value);
?>
Пример #15 Позиционные аргументы по сравнению с именованными аргументами
<?php
// Передача позиционных аргументов:
array_fill(0, 100, 50);
// Передача именованных аргументов:
array_fill(start_index: 0, count: 100, value: 50);
?>
Порядок передачи именованных аргументов неважен.
Пример #16 Тот же пример, но с другим порядком аргументов
<?php
array_fill(value: 50, count: 100, start_index: 0);
?>
Разрешается комбинировать именованные аргументы с позиционными. Тогда именованные аргументы должны идти после позиционных. Разрешается также передавать только часть необязательных аргументов функции, независимо от порядка аргументов.
Пример #17 Объединение именованных аргументов с позиционными аргументами
<?php
htmlspecialchars($string, double_encode: false);
// То же самое
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>
Передача одного и того же аргумента больше одного раза выбросит исключение Error.
Пример #18 Ошибка, которая возникает при передаче одного и того же параметра больше одного раза
<?php
function foo($param) {}
foo(param: 1, param: 2);
// Error: Named parameter $param overwrites previous argument
foo(1, param: 2);
// Error: Named parameter $param overwrites previous argument
?>
Начиная с PHP 8.1.0 разрешается передавать именованные аргументы после распаковки аргументов. Именованный аргумент не должен переопределять распакованный аргумент.
Пример #19 Пример передачи именованных аргументов после распаковки
<?php
function foo($a, $b, $c = 3, $d = 4) {
return $a + $b + $c + $d;
}
var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46
var_dump(foo(...[1, 2], b: 20)); // Fatal error: Named parameter $b overwrites previous argument
?>