Аргументы функции

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

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', // Эта завершающая запятая допустима только начиная с 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
'Приготовление кофе.';
}
}
class
FancyCoffeeMaker {
public function
brew() {
return
'Приготовление прекрасного кофе специально для вас.';
}
}
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 по умолчанию делает тип неявно обнуляемым. Такое использование остаётся допустимым, хотя рекомендуется использовать явный тип nullable.

Пример #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 поддерживает списки аргументов переменной длины для функций, определяемых пользователем с помощью добавления многоточия (...).

Список аргументов может содержать многоточие (...), чтобы показать, что функция принимает переменное количество аргументов. Аргументы в этом случае будут переданы в виде массива:

Пример #11 Использование ... для доступа к аргументам

<?php
function sum(...$numbers) {
$acc = 0;
foreach (
$numbers as $n) {
$acc += $n;
}
return
$acc;
}

echo
sum(1, 2, 3, 4);
?>

Результат выполнения данного примера:

10

Многоточие (...) можно использовать при вызове функции, чтобы распаковать массив (array) или Traversable переменную в список аргументов:

Пример #12 Использование ... для передачи аргументов

<?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)); // Фатальная ошибка. Именованный аргумент $b переопределяет предыдущий аргумент
?>