mirror of
https://github.com/php/doc-ru.git
synced 2026-03-23 23:32:16 +01:00
1871 lines
66 KiB
XML
1871 lines
66 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- EN-Revision: dd87866772c31671146ff778140dc0955c55005c Maintainer: sergey Status: ready -->
|
||
<!-- Reviewed: no -->
|
||
<chapter xml:id="language.functions" xmlns="http://docbook.org/ns/docbook">
|
||
<title>Функции</title>
|
||
|
||
<sect1 xml:id="functions.user-defined">
|
||
<title>Пользовательские функции</title>
|
||
|
||
<para>
|
||
Функции определяют ключевым словом <literal>function</literal>,
|
||
за которым через пробел идёт название функции и круглые скобки.
|
||
Круглые скобки оставляют пустыми или определяют в скобках список параметров; параметры разделяют символом <literal>,</literal>.
|
||
За круглыми скобками идёт пара фигурных скобок — тело функции. Приведём пример определения функции:
|
||
</para>
|
||
<example>
|
||
<title>Объявление новой функции с названием <literal>foo</literal></title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
|
||
{
|
||
echo "Пример функции.\n";
|
||
return $retval;
|
||
}
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
<note>
|
||
<para>
|
||
С PHP 8.0.0 список параметров допускает завершающую запятую:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo($arg_1, $arg_2,) {}
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
</note>
|
||
|
||
<simpara>
|
||
В теле функции записывают корректный PHP-код,
|
||
даже другие функции и определения <link linkend="language.oop5.basic.class">классов</link>.
|
||
</simpara>
|
||
<para>
|
||
Имена функций следуют тем же правилам, что и другие метки в PHP.
|
||
Корректное имя функции начинается с буквы или знака подчёркивания,
|
||
за которым идёт любое количество букв, цифр или знаков
|
||
подчёркивания. В виде регулярного выражения имя выражается так:
|
||
<code>^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$</code>.
|
||
</para>
|
||
&tip.userlandnaming;
|
||
<simpara>
|
||
Требования объявлять функции раньше появления ссылки на функции — нет,
|
||
<emphasis>за исключением</emphasis> условного определения функции,
|
||
как показывают два следующих примера.
|
||
</simpara>
|
||
<para>
|
||
Определение функции описывают <emphasis>до</emphasis> вызова функции,
|
||
когда функцию определяют по условию, как в двух следующих примерах.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Условные функции</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$makefoo = true;
|
||
|
||
/* Нельзя вызвать функцию foo() в этом месте,
|
||
поскольку функцию ещё не определили, но обращение
|
||
к функции bar() доступно */
|
||
|
||
bar();
|
||
|
||
if ($makefoo) {
|
||
function foo()
|
||
{
|
||
echo "Я не существую, пока выполнение программы не дойдёт до меня.\n";
|
||
}
|
||
}
|
||
|
||
/* Теперь безопасно вызываем функцию foo(),
|
||
поскольку выражение переменной $makefoo язык интерпретировал как true */
|
||
|
||
if ($makefoo) {
|
||
foo();
|
||
}
|
||
|
||
function bar()
|
||
{
|
||
echo "Я существую сразу после запуска программы.\n";
|
||
}
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Вложенные функции</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo()
|
||
{
|
||
function bar()
|
||
{
|
||
echo "Я не существую пока не вызовут функцию foo().\n";
|
||
}
|
||
}
|
||
|
||
/* Пока нельзя обратиться к функции bar(),
|
||
поскольку функцию ещё не определили */
|
||
|
||
foo();
|
||
|
||
/* Теперь функция bar() доступна для вызова,
|
||
обработка функции foo() сделала её доступной */
|
||
|
||
bar();
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
У функций и классов PHP глобальная область видимости —
|
||
их разрешается вызывать за пределами функции, даже если их определили
|
||
внутри, и наоборот.
|
||
</para>
|
||
<simpara>
|
||
PHP не поддерживает перегрузку функций, также невозможно
|
||
переопределить или удалить функции, которые объявили раньше.
|
||
</simpara>
|
||
<note>
|
||
<simpara>
|
||
Имена функций не зависят от регистра символов в кодировке ASCII
|
||
от <literal>A</literal> до <literal>Z</literal>, хотя хорошим тоном
|
||
будет вызов функций в том виде, в каком функцию указали в объявлении.
|
||
</simpara>
|
||
</note>
|
||
<simpara>
|
||
Функции PHP поддерживают как <link linkend="functions.variable-arg-list">
|
||
списки аргументов переменной длины</link>, так и
|
||
<link linkend="functions.arguments.default">значения аргументов по умолчанию</link>.
|
||
Подробнее об этом рассказывают описания функций
|
||
<function>func_num_args</function>,
|
||
<function>func_get_arg</function>
|
||
и <function>func_get_args</function>.
|
||
</simpara>
|
||
|
||
<para>
|
||
В PHP функции разрешается вызывать рекурсивно.
|
||
<example>
|
||
<title>Рекурсивные функции</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function recursion($a)
|
||
{
|
||
if ($a < 20) {
|
||
echo "$a\n";
|
||
recursion($a + 1);
|
||
}
|
||
}
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
<note>
|
||
<simpara>
|
||
Рекурсивный вызов функций и методов с глубиной более 100-200 уровней
|
||
рекурсии может вызвать переполнение стека и привести к аварийному
|
||
завершению скрипта. В частности, бесконечную рекурсию PHP считает
|
||
программной ошибкой.
|
||
</simpara>
|
||
</note>
|
||
</para>
|
||
|
||
</sect1>
|
||
|
||
<sect1 xml:id="functions.arguments">
|
||
<title>Параметры и аргументы функции</title>
|
||
|
||
<simpara>
|
||
Параметры объявляются в сигнатуре функции. Информацию в параметры функции передают в списке аргументов.
|
||
Список аргументов состоит из выражений, которые разделяют запятыми. Выражения
|
||
в списке аргументов вычисляются слева направо, а результат вычислений присваивается параметрам
|
||
перед действительным вызовом функции. Такое вычисление называется <emphasis>упреждающим</emphasis>.
|
||
</simpara>
|
||
|
||
<!-- Note: this paragraph feels like it should be moved to the syntax part? -->
|
||
<para>
|
||
PHP поддерживает передачу аргументов по значению, это поведение по умолчанию,
|
||
и <link linkend="functions.arguments.by-reference">по ссылке</link>,
|
||
и <link linkend="functions.arguments.default">значения по умолчанию</link>.
|
||
<link linkend="functions.variable-arg-list">Списки аргументов
|
||
переменной длины</link> и <link linkend="functions.named-arguments">именованные
|
||
аргументы</link> тоже поддерживаются.
|
||
</para>
|
||
<note>
|
||
<para>
|
||
С PHP 7.3.0 список аргументов при вызове функций допускает
|
||
завершающую запятую:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$v = foo(
|
||
$arg_1,
|
||
$arg_2,
|
||
);
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
</note>
|
||
|
||
<para>
|
||
Начиная с PHP 8.0.0 список параметров функции допускает завершающую
|
||
запятую, которую парсер проигнорирует. Это полезно, когда список параметров
|
||
длинный или содержит длинные названия переменных, что в целях удобства подталкивает
|
||
к вертикальному перечислению параметров.
|
||
</para>
|
||
<example>
|
||
<title>Список параметров функции с запятой в конце</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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 указывать запятую в конце списка не разрешали
|
||
) {
|
||
// ...
|
||
}
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<sect2 xml:id="functions.arguments.by-reference">
|
||
<title>Передача аргументов по ссылке</title>
|
||
|
||
<simpara>
|
||
По умолчанию аргументы передаются в функцию по значению. Поэтому
|
||
если значение аргумента внутри функции изменится, значение
|
||
переменной, в которой передали аргумент, не изменится за пределами функции.
|
||
Аргументы передают по ссылке, чтобы разрешить функции изменять значения аргументов.
|
||
</simpara>
|
||
<para>
|
||
В описании функции перед именем параметра указывают амперсанд &,
|
||
когда требуется передача аргумента по ссылке:
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Передача аргументов по ссылке</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function add_some_extra(&$string)
|
||
{
|
||
$string .= 'и кое-что ещё.';
|
||
}
|
||
|
||
$str = 'Это строка, ';
|
||
add_some_extra($str);
|
||
echo $str; // Конструкция выведет «Это строка, и кое-что ещё.»
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Передача в аргументе константного выражения в параметр, который ожидает значение по ссылке, вызовет ошибку.
|
||
</para>
|
||
</sect2>
|
||
<sect2 xml:id="functions.arguments.default">
|
||
<title>Значения по умолчанию для параметров</title>
|
||
|
||
<para>
|
||
Функция умеет определять для параметров значения по умолчанию,
|
||
в этом помогает синтаксис, который похож на синтаксис присваивания значения переменной.
|
||
Функция присвоит параметру значение по умолчанию, только если
|
||
в параметр не передали аргумент;
|
||
обратите внимание, функция <emphasis>не</emphasis> присваивает
|
||
параметру значение по умолчанию при передаче в параметр аргумента со значением &null;.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Значения по умолчанию для параметров функций</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function makecoffee($type = "капучино")
|
||
{
|
||
return "Готовим чашку $type.\n";
|
||
}
|
||
|
||
echo makecoffee();
|
||
echo makecoffee(null);
|
||
echo makecoffee("эспрессо");
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Готовим чашку капучино.
|
||
Готовим чашку .
|
||
Готовим чашку эспрессо.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Значениями по умолчанию для параметров разрешается указывать скалярные значения,
|
||
массивы (<type>array</type>), специальный тип &null; и начиная с PHP 8.1.0 объекты,
|
||
которые создают синтаксисом <link linkend="language.oop5.basic.new">new ClassName()</link>.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Нескалярные типы как значения по умолчанию</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function makecoffee($types = array("капучино"), $coffeeMaker = NULL)
|
||
{
|
||
$device = is_null($coffeeMaker)
|
||
? "вручную"
|
||
: $coffeeMaker
|
||
;
|
||
|
||
return "Готовлю чашку " . join(", ", $types) . " $device. \n";
|
||
}
|
||
|
||
echo makecoffee();
|
||
echo makecoffee(array("капучино", "лавацца"), "в чайнике");
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Готовлю чашку капучино вручную.
|
||
Готовлю чашку капучино, лавацца в чайнике.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Объекты как значения по умолчанию, с PHP 8.1.0
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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);
|
||
]]>
|
||
</programlisting>
|
||
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Приготовление кофе.
|
||
Приготовление прекрасного кофе только для вас.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<simpara>
|
||
Объект как значение по умолчанию разрешается определять только константным выражением,
|
||
а не переменной, вызовом функции или метода класса.
|
||
</simpara>
|
||
<para>
|
||
Обратите внимание, необязательные параметры потребуется указать
|
||
после обязательных, иначе необязательные параметры
|
||
не получится пропустить при вызове, поскольку функция рассматривает необязательные параметры,
|
||
которые указали перед обязательными, как обязательные.
|
||
Рассмотрим следующий пример:
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Неправильное определение значений по умолчанию
|
||
для параметров функции
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function makeyogurt($container = "миску", $flavour)
|
||
{
|
||
return "Делаем $container с $flavour йогуртом.\n";
|
||
}
|
||
|
||
echo makeyogurt("малиновым"); // Значение «малиновым» получит параметр $container, а не параметр $flavour
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Fatal error: Uncaught ArgumentCountError: Too few arguments
|
||
to function makeyogurt(), 1 passed in example.php on line 42
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Теперь сравним приведённый пример со следующим примером:
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Правильное определение значений по умолчанию
|
||
для параметров функции
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function makeyogurt($flavour, $container = "миску")
|
||
{
|
||
return "Делаем $container с $flavour йогуртом.\n";
|
||
}
|
||
|
||
echo makeyogurt("малиновым"); // Значение «малиновым» получит параметр $flavour
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Делаем миску с малиновым йогуртом.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Начиная с PHP 8.0.0 для пропуска необязательных параметров
|
||
передают <link linkend="functions.named-arguments">именованные аргументы</link>.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Правильное определение значений по умолчанию
|
||
для параметров функции
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function makeyogurt($container = "миску", $flavour = "малиновым", $style = "греческим")
|
||
{
|
||
return "Делаем $container с $flavour $style йогуртом.\n";
|
||
}
|
||
|
||
echo makeyogurt(style: "натуральным");
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Делаем миску с малиновым натуральным йогуртом.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Начиная с PHP 8.0.0 объявление обязательных параметров после необязательных
|
||
<emphasis>устарело</emphasis>.
|
||
Часто из таких ситуаций выходят путём отказа от значения по умолчанию,
|
||
поскольку функция никогда не присвоит параметру, в который передали аргумент,
|
||
значение по умолчанию.
|
||
Исключение из этого правила — параметры вида <code>Type $param = null</code>,
|
||
где значение &null; по умолчанию делает тип неявно обнуляемым.
|
||
Такое определение устарело с PHP 8.4.0
|
||
и теперь <link linkend="language.types.declarations.nullable">обнуляемый тип</link>
|
||
потребуется указать явно.
|
||
<example>
|
||
<title>
|
||
Объявление необязательных параметров после обязательных
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo($a = [], $b) {} // Функция никогда не присвоит значение по умолчанию;
|
||
// определение значения по умолчанию для параметра, который идёт
|
||
// перед обязательным, устарело с PHP 8.0.0
|
||
function foo($a, $b) {} // Определение функционально эквивалентно, но не выдаёт уведомление об устаревании
|
||
|
||
function bar(A $a = null, $b) {} // С PHP 8.1.0 параметр $a неявно обязателен, поскольку идёт перед обязательным,
|
||
// но неявно обнуляем, поскольку для параметра определили значение по умолчанию null.
|
||
// Объявления значения по умолчанию null
|
||
// без указания обнуляемого типа устарело с PHP 8.4.0
|
||
function bar(?A $a, $b) {} // Определение, которое рекомендуют
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
Начиная с PHP 7.1.0 пропуск аргумента для параметра, для которого не задали
|
||
значение по умолчанию, выбрасывает исключение
|
||
<classname>ArgumentCountError</classname>;
|
||
в предыдущих версиях выдавалось предупреждение.
|
||
</simpara>
|
||
</note>
|
||
<note>
|
||
<simpara>
|
||
Параметрам, которые ожидают аргумент по ссылке,
|
||
разрешается устанавливать значения по умолчанию.
|
||
</simpara>
|
||
</note>
|
||
</sect2>
|
||
|
||
<sect2 xml:id="functions.variable-arg-list">
|
||
<title>Списки аргументов переменной длины</title>
|
||
|
||
<simpara>
|
||
В пользовательских функциях PHP поддерживает списки аргументов
|
||
переменной длины, параметры для которых определяют оператором из трёх точек
|
||
<literal>...</literal>, который называется spread-оператором.
|
||
</simpara>
|
||
|
||
<para>
|
||
Списку параметров разрешается содержать оператор
|
||
<literal>...</literal>, чтобы показать, что функция принимает переменное
|
||
количество аргументов. Переменная получит аргументы как массив:
|
||
|
||
<example>
|
||
<title>
|
||
Оператор <literal>...</literal> для доступа к аргументам
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function sum(...$numbers) {
|
||
$acc = 0;
|
||
|
||
foreach ($numbers as $n) {
|
||
$acc += $n;
|
||
}
|
||
|
||
return $acc;
|
||
}
|
||
|
||
echo sum(1, 2, 3, 4);
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
10
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
|
||
<para>
|
||
Spread-оператор <literal>...</literal> указывают также при вызове функции,
|
||
чтобы распаковать в список аргументов массив (<type>array</type>),
|
||
или распаковать переменную или литерал, которые принадлежат типу
|
||
<classname>Traversable</classname>:
|
||
|
||
<example>
|
||
<title>
|
||
Передача аргументов со spread-оператором <literal>...</literal>
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function add($a, $b) {
|
||
return $a + $b;
|
||
}
|
||
|
||
echo add(...[1, 2])."\n";
|
||
|
||
$a = [1, 2];
|
||
echo add(...$a);
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
3
|
||
3
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
|
||
<para>
|
||
Стандартные позиционные параметры разрешается указывать перед токеном <literal>...</literal>,
|
||
тогда оператор <literal>...</literal> сгенерирует и добавит в массив только конечные аргументы,
|
||
которые не соответствуют позиционным.
|
||
</para>
|
||
|
||
<para>
|
||
Перед оператором <literal>...</literal> разрешается также добавлять
|
||
<link linkend="language.types.declarations">объявление типа</link>.
|
||
Тогда функция проверит, что аргументы, которые захватил оператор <literal>...</literal>,
|
||
соответствуют типу параметра, или выбросит ошибку.
|
||
|
||
<example>
|
||
<title>Объявление типа для параметра, который ожидает аргументы переменной длины</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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);
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
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
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
|
||
<para>
|
||
В финале добавим, что аргументы переменной длины разрешается также передавать
|
||
<link linkend="functions.arguments.by-reference">по ссылке</link>,
|
||
для этого перед оператором <literal>...</literal> указывают амперсанд
|
||
(<literal>&</literal>).
|
||
</para>
|
||
|
||
</sect2>
|
||
|
||
<sect2 xml:id="functions.named-arguments">
|
||
<title>Именованные аргументы</title>
|
||
|
||
<para>
|
||
В PHP 8.0.0 как расширение позиционных параметров появились именованные аргументы.
|
||
Именованные аргументы передаются в функцию на основе имени, а не позиции параметра.
|
||
Назначение аргумента документирует само себя, аргументы перестают зависеть от порядка,
|
||
в котором передаются, и разрешается произвольно пропускать значения по умолчанию.
|
||
</para>
|
||
|
||
<para>
|
||
Именованные аргументы передают по названию параметра, за которым идёт
|
||
двоеточие и значение аргумента.
|
||
Зарезервированные ключевые слова разрешается указывать как имена параметров.
|
||
Название параметра потребуется указать как идентификатор, нельзя указывать динамические имена
|
||
параметров.
|
||
</para>
|
||
|
||
<example>
|
||
<title>Синтаксис именованного аргумента</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
myFunction(paramName: $value);
|
||
array_foobar(array: $value);
|
||
|
||
// НЕ поддерживается
|
||
function_name($variableStoringParamName: $value);
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<example>
|
||
<title>
|
||
Сравнение позиционных и именованных аргументов
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// Передача позиционных аргументов:
|
||
array_fill(0, 100, 50);
|
||
|
||
// Передача именованных аргументов:
|
||
array_fill(start_index: 0, count: 100, value: 50);
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<para>
|
||
Порядок передачи именованных аргументов неважен.
|
||
</para>
|
||
|
||
<example>
|
||
<title>
|
||
Тот же пример, но с другим порядком аргументов
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
array_fill(value: 50, count: 100, start_index: 0);
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<para>
|
||
Именованные аргументы разрешается комбинировать с позиционными.
|
||
Тогда именованные аргументы потребуется передать после позиционных.
|
||
Разрешается также передавать только часть необязательных аргументов
|
||
функции в произвольном порядке.
|
||
</para>
|
||
|
||
<example>
|
||
<title>
|
||
Объединение именованных аргументов с позиционными аргументами
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
htmlspecialchars($string, double_encode: false);
|
||
|
||
// Аналогично
|
||
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<para>
|
||
При передаче именованных аргументов с одним и тем же названием параметра
|
||
выбрасывается ошибка <classname>Error</classname>.
|
||
</para>
|
||
|
||
<example>
|
||
<title>
|
||
Ошибка, которая возникает при передаче нескольких аргументов с названием
|
||
одного и того же параметра
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<para>
|
||
Начиная с PHP 8.1.0 разрешается передавать именованные аргументы
|
||
после распаковки аргументов. Именованный аргумент <emphasis>не должен</emphasis>
|
||
переопределять распакованный аргумент.
|
||
</para>
|
||
|
||
<example>
|
||
<title>
|
||
Передача именованных аргументов после распаковки
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="functions.returning-values">
|
||
<title>Возврат значений</title>
|
||
|
||
<para>
|
||
Значения возвращаются необязательной инструкцией возврата.
|
||
Разрешается возвращать любой тип, включая массивы и объекты.
|
||
Возврат немедленно завершает выполнение функции и передаёт
|
||
управление обратно — к той строке кода, в которой вызвали функцию.
|
||
Подробную информацию о возврате значений даёт описание инструкции
|
||
<function>return</function>.
|
||
</para>
|
||
<note>
|
||
<para>
|
||
Функция вернёт значение &null;,
|
||
если инструкцию <function>return</function> не указали.
|
||
</para>
|
||
</note>
|
||
|
||
<sect2>
|
||
<title>Инструкция return</title>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Пример функции с инструкцией <function>return</function>
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function square($num)
|
||
{
|
||
return $num * $num;
|
||
}
|
||
|
||
echo square(4); // Выводит 16
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
|
||
<para>
|
||
Функция не умеет возвращать больше одного значения, но аналогичного
|
||
результата добиваются возвратом массива.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Возврат набора значений в виде массива</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function small_numbers()
|
||
{
|
||
return [0, 1, 2];
|
||
}
|
||
|
||
// Деструктуризация массива будет собирать каждый элемент массива индивидуально
|
||
[$zero, $one, $two] = small_numbers();
|
||
|
||
// До версии 7.1.0 единственной эквивалентной альтернативой была языковая конструкция list()
|
||
list($zero, $one, $two) = small_numbers();
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Оператор & указывают и в описании функции,
|
||
и в момент присваивания возвращаемого значения переменной,
|
||
чтобы функция возвращала результат по ссылке:
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Возврат результата по ссылке</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function &returns_reference()
|
||
{
|
||
return $someref;
|
||
}
|
||
|
||
$newref =& returns_reference();
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<simpara>
|
||
Дополнительную информацию о ссылках даёт
|
||
раздел документации «<link linkend="language.references">Объяснение ссылок</link>».
|
||
</simpara>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="functions.variable-functions">
|
||
<title>Функции переменных</title>
|
||
|
||
<para>
|
||
PHP поддерживает концепцию функций переменных. Это означает, что
|
||
если к имени переменной присоединили круглые скобки, PHP ищет
|
||
функцию с тем же именем, что и результат вычисления переменной,
|
||
и пробует выполнить функцию. Этим синтаксисом
|
||
описывают callback-функции, таблицы функций и т. д.
|
||
</para>
|
||
<para>
|
||
Функции переменных не работают с языковыми конструкциями
|
||
<function>echo</function>, <function>print</function>,
|
||
<function>unset</function>, <function>isset</function>,
|
||
<function>empty</function>, <function>include</function>,
|
||
<function>require</function> и т. п.
|
||
Напишите функцию-обёртку, чтобы эти конструкции работали как функции переменных.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Пример функции переменной</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo() {
|
||
echo "В foo()<br />\n";
|
||
}
|
||
|
||
function bar($arg = '')
|
||
{
|
||
echo "В bar(); аргумент был '$arg'.<br />\n";
|
||
}
|
||
|
||
// Функция-обёртка для echo
|
||
function echoit($string)
|
||
{
|
||
echo $string;
|
||
}
|
||
|
||
$func = 'foo';
|
||
$func(); // Вызывает функцию foo()
|
||
|
||
$func = 'bar';
|
||
$func('test'); // Вызывает функцию bar()
|
||
|
||
$func = 'echoit';
|
||
$func('test'); // Вызывает функцию echoit()
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Синтаксис функций переменных работает также для вызова методов объектов.
|
||
<example>
|
||
<title>Пример метода переменной</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
function Variable()
|
||
{
|
||
$name = 'Bar';
|
||
$this->$name(); // Вызывает метод Bar()
|
||
}
|
||
|
||
function Bar()
|
||
{
|
||
echo "Это Bar";
|
||
}
|
||
}
|
||
|
||
$foo = new Foo();
|
||
$funcname = "Variable";
|
||
$foo->$funcname(); // Вызывает $foo->Variable()
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
При вызове статических методов вызов функции «сильнее»,
|
||
чем оператор доступа к статическому свойству:
|
||
<example>
|
||
<title>Пример вызова метода переменной со статическим свойством</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
static $variable = 'статическое свойство';
|
||
|
||
static function Variable()
|
||
{
|
||
echo 'Вызов метода Variable';
|
||
}
|
||
}
|
||
|
||
echo Foo::$variable; // Это выведет «статическое свойство». В области видимости класса нужна переменная $variable
|
||
$variable = "Variable";
|
||
Foo::$variable(); // Вызывает $foo->Variable() после прочтения переменной $variable в текущей области видимости
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Сложные callable-функции</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
static function bar()
|
||
{
|
||
echo "bar\n";
|
||
}
|
||
|
||
function baz()
|
||
{
|
||
echo "baz\n";
|
||
}
|
||
}
|
||
|
||
$func = array("Foo", "bar");
|
||
$func(); // Выведет "bar"
|
||
$func = array(new Foo(), "baz");
|
||
$func(); // Выведет "baz"
|
||
$func = "Foo::bar";
|
||
$func(); // Выведет "bar"
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
|
||
<sect2 role="seealso">
|
||
&reftitle.seealso;
|
||
<para>
|
||
<simplelist>
|
||
<member><function>is_callable</function></member>
|
||
<member><function>call_user_func</function></member>
|
||
<member><function>function_exists</function></member>
|
||
<member><link linkend="language.variables.variable">Переменные переменных</link></member>
|
||
</simplelist>
|
||
</para>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="functions.internal">
|
||
<title>Внутренние, или встроенные, функции</title>
|
||
|
||
<para>
|
||
PHP поставляется с набором языковых конструкций и встроенных функций.
|
||
Отдельные функции требуют, чтобы PHP собрали с конкретными модулями,
|
||
иначе PHP генерирует фатальные ошибки о неизвестной функции.
|
||
Например, чтобы использовать <link linkend="ref.image">функции для работы с изображениями</link>
|
||
наподобие <function>imagecreatetruecolor</function>, требуется собрать PHP
|
||
с поддержкой модуля <productname>GD</productname>.
|
||
Требуется собрать PHP с поддержкой модуля <link linkend="book.mysqli">MySQLi</link>,
|
||
чтобы использовать функцию <function>mysqli_connect</function>.
|
||
Ядро каждой версии PHP включает
|
||
<link linkend="ref.strings">функции обработки строк</link>
|
||
и <link linkend="ref.var">функции для работы с переменными</link>.
|
||
Вызов функции <function>phpinfo</function> или <function>get_loaded_extensions</function>
|
||
покажет, какие модули загрузил PHP.
|
||
Часть модулей PHP включает по умолчанию. Документация описывает каждый модуль отдельно.
|
||
О настройке PHP подробнее рассказывают разделы «<link linkend="configuration">Конфигурация</link>»,
|
||
«<link linkend="install">Установка</link>»
|
||
и разделы, которые описывают отдельные модули.
|
||
</para>
|
||
<para>
|
||
Раздел
|
||
«<link linkend="about.prototypes">Как читать определения функции</link>»
|
||
объясняет, как читать и интерпретировать прототипы функций.
|
||
Программист должен понимать, что возвращает функция, или как функция модифицирует аргументы,
|
||
которые передали в функцию. Функция <function>str_replace</function>, например,
|
||
вернёт изменённую строку, тогда как функция <function>usort</function>
|
||
работает непосредственно с переменной, которую передали в функцию.
|
||
О каждой функции рассказывает отдельная страница документации: описывает параметры,
|
||
изменения поведения, значения, которые возвращает функция в случае успешного выполнения
|
||
или когда возникает ошибка, доступность функции в одной или другой версии PHP.
|
||
Знание важных и часто тонких различий — ключ к правильному PHP-коду.
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
Неясно, какое значение вернёт функция, если аргументы, которые передали в функцию,
|
||
не соответствуют ожиданиям функции; например, передали
|
||
массив (<type>array</type>) вместо строки (<type>string</type>).
|
||
Скорее всего, функция вернёт &null;, но это только соглашение,
|
||
на него нельзя полагаться.
|
||
Начиная с PHP 8.0.0 в таком случае требуется выбрасывать исключение <classname>TypeError</classname>.
|
||
</simpara>
|
||
</note>
|
||
|
||
<note>
|
||
<para>
|
||
В нестрогом режиме типизации скалярные типы встроенных функций по умолчанию обнуляемы, —
|
||
принимают значение &null;.
|
||
Начиная с PHP 8.1.0 передача значения &null; в параметр встроенной функции,
|
||
который не объявили обнуляемым, не рекомендуется, и в принудительном режиме
|
||
выдаёт уведомление об устаревании, чтобы соответствовать поведению пользовательских функций,
|
||
в которых требуется явно помечать скалярные типы как обнуляемые.
|
||
</para>
|
||
|
||
<para>
|
||
Функция <function>strlen</function>, например, ожидает, что параметр
|
||
<literal>$string</literal> будет необнуляемой строкой (&string;).
|
||
По историческим причинам в принудительном режиме PHP разрешает передавать
|
||
значение &null; для этого параметра,
|
||
и параметр неявно приводится к строке (<type>string</type>). В результате
|
||
получается значение <literal>""</literal>.
|
||
В строгом режиме выбрасывается исключение <classname>TypeError</classname>.
|
||
</para>
|
||
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
var_dump(strlen(null));
|
||
// "Deprecated: Passing null to parameter #1 ($string) of type string is deprecated" начиная с PHP 8.1.0
|
||
// int(0)
|
||
|
||
var_dump(str_contains("foobar", null));
|
||
// "Deprecated: Passing null to parameter #2 ($needle) of type string is deprecated" начиная с PHP 8.1.0
|
||
// bool(true)
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</note>
|
||
|
||
<sect2 role="seealso">
|
||
&reftitle.seealso;
|
||
<para>
|
||
<simplelist>
|
||
<member><function>function_exists</function></member>
|
||
<member><link linkend="funcref">справочник функций</link></member>
|
||
<member><function>get_extension_funcs</function></member>
|
||
<member><function>dl</function></member>
|
||
</simplelist>
|
||
</para>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="functions.anonymous">
|
||
<title>Анонимные функции</title>
|
||
|
||
<simpara>
|
||
Анонимные функции, которые также знают как замыкания (<literal>closures</literal>), —
|
||
функции без названия.
|
||
Анонимные функции вызывают или передают как значения
|
||
в параметры с типом <type>callable</type>.
|
||
</simpara>
|
||
<simpara>
|
||
PHP создаёт анонимные функции через класс
|
||
<link linkend="class.closure"><classname>Closure</classname></link>.
|
||
</simpara>
|
||
<example>
|
||
<title>Пример анонимной функции</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
echo preg_replace_callback(
|
||
'~-([a-z])~',
|
||
function ($match) {
|
||
return strtoupper($match[1]);
|
||
},
|
||
'hello-world'
|
||
);
|
||
// Выведет helloWorld
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<simpara>
|
||
Замыкания также присваивают как значения переменным; PHP автоматически
|
||
преобразовывает такие выражения в экземпляры внутреннего класса
|
||
<classname>Closure</classname>.
|
||
Замыкания присваивают переменной тем же синтаксисом,
|
||
что и для другого присваивания, включая конечную точку с запятой:
|
||
</simpara>
|
||
|
||
<example>
|
||
<title>
|
||
Пример присваивания анонимной функции как значения переменной
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$greet = function($name) {
|
||
printf("Привет, %s\r\n", $name);
|
||
};
|
||
|
||
$greet('Мир');
|
||
$greet('PHP');
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<simpara>
|
||
Замыкания также наследуют переменные из родительской
|
||
области видимости. Каждая такая переменная должна быть
|
||
передана в языковую конструкцию <literal>use</literal>. Начиная с
|
||
PHP 7.1 эти переменные не должны включать &link.superglobals;,
|
||
переменную <varname>$this</varname> и переменные с именами, которые
|
||
совпадают с названиями параметров функции.
|
||
Объявление типа для значения, которое возвращает функция,
|
||
указывают <emphasis>после</emphasis> конструкции <literal>use</literal>.
|
||
</simpara>
|
||
|
||
<example>
|
||
<title>
|
||
Пример наследования переменных из родительской области видимости
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$message = 'привет';
|
||
|
||
// Без конструкции use
|
||
$example = function () {
|
||
var_dump($message);
|
||
};
|
||
$example();
|
||
|
||
// Наследуем переменную $message
|
||
$example = function () use ($message) {
|
||
var_dump($message);
|
||
};
|
||
$example();
|
||
|
||
// Анонимная функция наследует переменную с тем значением, которое переменная
|
||
// содержала перед определением функции, а не в месте вызова функции
|
||
$message = 'мир';
|
||
$example();
|
||
|
||
// Сбросим message
|
||
$message = 'привет';
|
||
|
||
// Наследование по ссылке
|
||
$example = function () use (&$message) {
|
||
var_dump($message);
|
||
};
|
||
$example();
|
||
|
||
// Значение, которое изменили в родительской области видимости,
|
||
// отражается внутри вызова функции
|
||
$message = 'мир';
|
||
echo $example();
|
||
|
||
// Замыкания умеют принимать обычные аргументы
|
||
$example = function ($arg) use ($message) {
|
||
var_dump($arg . ', ' . $message);
|
||
};
|
||
$example("привет");
|
||
|
||
// Объявление типа значения, которое вернёт функция, идёт после конструкции use
|
||
$example = function () use ($message): string {
|
||
return "привет, $message";
|
||
};
|
||
var_dump($example());
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.similar;
|
||
<screen>
|
||
<![CDATA[
|
||
Notice: Undefined variable: message in /example.php on line 6
|
||
NULL
|
||
string(12) "привет"
|
||
string(12) "привет"
|
||
string(12) "привет"
|
||
string(6) "мир"
|
||
string(20) "привет, мир"
|
||
string(20) "привет, мир"
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<para>
|
||
Начиная с PHP 8.0.0 списку переменных, которые функция
|
||
наследует из области видимости, разрешается включать конечную запятую,
|
||
которую парсер проигнорирует.
|
||
</para>
|
||
<simpara>
|
||
Наследование переменных из родительской области видимости
|
||
<emphasis>отличается</emphasis> от наследования глобальных переменных.
|
||
Глобальные переменные существуют в глобальной области видимости,
|
||
которая остаётся прежней, какая бы функция ни выполнялась.
|
||
Родительская область видимости замыкания —
|
||
функция, в которой объявили замыкание; не обязательно
|
||
функция, из которой замыкание вызвали. Смотрите следующий
|
||
пример:
|
||
</simpara>
|
||
|
||
<example>
|
||
<title>Замыкания и область видимости</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// Базовая корзина покупок, которая содержит список
|
||
// продуктов и количество каждого продукта. Включает метод,
|
||
// который вычисляет общую цену элементов корзины через
|
||
// callback-замыкание
|
||
class Cart
|
||
{
|
||
const PRICE_BUTTER = 1.00;
|
||
const PRICE_MILK = 3.00;
|
||
const PRICE_EGGS = 6.95;
|
||
|
||
protected $products = array();
|
||
|
||
public function add($product, $quantity)
|
||
{
|
||
$this->products[$product] = $quantity;
|
||
}
|
||
|
||
public function getQuantity($product)
|
||
{
|
||
return isset($this->products[$product]) ? $this->products[$product] :
|
||
FALSE;
|
||
}
|
||
|
||
public function getTotal($tax)
|
||
{
|
||
$total = 0.00;
|
||
|
||
$callback = function ($quantity, $product) use ($tax, &$total)
|
||
{
|
||
$pricePerItem = constant(
|
||
__CLASS__ . "::PRICE_" . strtoupper($product)
|
||
);
|
||
|
||
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
|
||
};
|
||
|
||
array_walk($this->products, $callback);
|
||
return round($total, 2);
|
||
}
|
||
}
|
||
|
||
$my_cart = new Cart;
|
||
|
||
// Добавляем элементы в корзину
|
||
$my_cart->add('butter', 1);
|
||
$my_cart->add('milk', 3);
|
||
$my_cart->add('eggs', 6);
|
||
|
||
// Выводим общую сумму с налогом 5 % на продажу
|
||
print $my_cart->getTotal(0.05) . "\n";
|
||
// Результат будет равен 54.29
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
<example>
|
||
<title>Автоматическая привязка переменной <literal>$this</literal></title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Test
|
||
{
|
||
public function testing()
|
||
{
|
||
return function () {
|
||
var_dump($this);
|
||
};
|
||
}
|
||
}
|
||
|
||
$object = new Test();
|
||
$function = $object->testing();
|
||
$function();
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
object(Test)#1 (0) {
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<para>
|
||
При объявлении замыкания в контексте класса текущий
|
||
класс автоматически привязывается к замыканию, а члены функции
|
||
получают доступ к переменной <literal>$this</literal> в области
|
||
видимости функции. <link linkend="functions.anonymous-functions.static">Статические анонимные функции</link> определяют,
|
||
когда автоматическая привязка к текущему классу не требуется.
|
||
</para>
|
||
|
||
<sect2 xml:id="functions.anonymous-functions.static">
|
||
<title>Статические анонимные функции</title>
|
||
<para>
|
||
Анонимные функции разрешается объявлять статически.
|
||
Это предотвратит автоматическое связывание замыкания
|
||
с текущим классом. Объекты тоже не связываются со статическим замыканием
|
||
во время выполнения кода.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Попытка обратиться к переменной <literal>$this</literal>
|
||
в статической анонимной функции
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
function __construct()
|
||
{
|
||
$func = static function () {
|
||
var_dump($this);
|
||
};
|
||
|
||
$func();
|
||
}
|
||
};
|
||
|
||
new Foo();
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Notice: Undefined variable: this in %s on line %d
|
||
NULL
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Попытка связать объект со статической анонимной функцией
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$func = static function () {
|
||
// Тело функции
|
||
};
|
||
|
||
$func = $func->bindTo(new stdClass());
|
||
$func();
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Warning: Cannot bind an instance to a static closure in %s on line %d
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
</sect2>
|
||
<sect2 role="changelog">
|
||
&reftitle.changelog;
|
||
<para>
|
||
<informaltable>
|
||
<tgroup cols="2">
|
||
<thead>
|
||
<row>
|
||
<entry>&Version;</entry>
|
||
<entry>&Description;</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>8.3.0</entry>
|
||
<entry>
|
||
Замыкания, которые создали из <link linkend="language.oop5.magic">магических методов</link>,
|
||
научились принимать именованные аргументы.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>7.1.0</entry>
|
||
<entry>
|
||
Анонимным функциям нельзя замыкаться вокруг &link.superglobals;,
|
||
переменной <varname>$this</varname> или другой переменной,
|
||
имя которой совпадает с названием параметра.
|
||
</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</informaltable>
|
||
</para>
|
||
</sect2>
|
||
|
||
<sect2 role="notes">
|
||
&reftitle.notes;
|
||
<note>
|
||
<simpara>
|
||
Внутри замыканий разрешается вызывать функции
|
||
<function>func_num_args</function>,
|
||
<function>func_get_arg</function> и <function>func_get_args</function>.
|
||
</simpara>
|
||
</note>
|
||
</sect2>
|
||
|
||
</sect1>
|
||
|
||
<sect1 xml:id="functions.arrow">
|
||
<title>Стрелочные функции</title>
|
||
|
||
<simpara>
|
||
Стрелочные функции появились в PHP 7.4 как
|
||
лаконичный синтаксис для <link linkend="functions.anonymous">анонимных функций</link>.
|
||
</simpara>
|
||
<simpara>
|
||
И анонимные, и стрелочные функции реализовали
|
||
через класс <link linkend="class.closure"><classname>Closure</classname></link>.
|
||
</simpara>
|
||
|
||
<simpara>
|
||
Базовая форма записи стрелочных функций:
|
||
<code>fn (argument_list) => expr</code>.
|
||
</simpara>
|
||
|
||
<simpara>
|
||
Стрелочные функции работают так же,
|
||
как <link linkend="functions.anonymous">анонимные функции</link>,
|
||
за исключением того, что доступ к переменным
|
||
родительской области стрелочные функции получают автоматически.
|
||
</simpara>
|
||
|
||
<simpara>
|
||
Когда стрелочная функция работает с переменной,
|
||
которую определили в родительской области,
|
||
переменная неявно захватывается по значению.
|
||
В следующем примере функции <varname>$fn1</varname>
|
||
и <varname>$fn2</varname> ведут себя одинаково.
|
||
</simpara>
|
||
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Стрелочные функции захватывают переменные по значению автоматически
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$y = 1;
|
||
|
||
$fn1 = fn($x) => $x + $y;
|
||
|
||
// Эквивалентно получению переменной $y по значению:
|
||
$fn2 = function ($x) use ($y) {
|
||
return $x + $y;
|
||
};
|
||
|
||
var_export($fn1(3));
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
4
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<simpara>
|
||
Это также работает во вложенных стрелочных функциях:
|
||
</simpara>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Стрелочные функции захватывают переменные по значению автоматически,
|
||
даже когда функции вложены
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$z = 1;
|
||
$fn = fn($x) => fn($y) => $x * $y + $z;
|
||
|
||
// Выведет 51
|
||
var_export($fn(5)(10));
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<simpara>
|
||
Как и в анонимных функциях,
|
||
синтаксис стрелочных функций допускает произвольные сигнатуры функций,
|
||
включая типы параметров и возвращаемых значений, значения по умолчанию,
|
||
переменные и передачу и возврат по ссылке.
|
||
Корректные примеры стрелочных функций:
|
||
</simpara>
|
||
<para>
|
||
<example>
|
||
<title>Примеры определения стрелочных функций</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
fn(array $x) => $x;
|
||
static fn($x): int => $x;
|
||
fn($x = 42) => $x;
|
||
fn(&$x) => $x;
|
||
fn&($x) => $x;
|
||
fn($x, ...$rest) => $rest;
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<simpara>
|
||
Стрелочные функции привязывают переменные по значению.
|
||
Это примерно эквивалентно выполнению конструкции <code>use($x)</code>
|
||
для каждой переменной <varname>$x</varname>, с которой стрелочная функция
|
||
будет работать внутри.
|
||
Привязка по значению означает, что внутри стрелочной функции невозможно
|
||
изменить значения из внешней области видимости.
|
||
Вместо этого для привязок по ссылкам можно пользоваться
|
||
<link linkend="functions.anonymous">анонимными функциями</link>.
|
||
</simpara>
|
||
<para>
|
||
<example>
|
||
<title>
|
||
Стрелочные функции не умеют изменять значения из внешней области видимости
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$x = 1;
|
||
$fn = fn() => $x++; // Функция ничего не изменит
|
||
$fn();
|
||
var_export($x); // Функция выведет значение 1
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
|
||
<sect2 role="changelog">
|
||
&reftitle.changelog;
|
||
<para>
|
||
<informaltable>
|
||
<tgroup cols="2">
|
||
<thead>
|
||
<row>
|
||
<entry>&Version;</entry>
|
||
<entry>&Description;</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>7.4.0</entry>
|
||
<entry>
|
||
Появились стрелочные функции.
|
||
</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</informaltable>
|
||
</para>
|
||
</sect2>
|
||
|
||
<sect2 role="notes">
|
||
&reftitle.notes;
|
||
<note>
|
||
<simpara>
|
||
Из стрелочной функции разрешается вызывать функции
|
||
<function>func_num_args</function>, <function>func_get_arg</function>
|
||
и <function>func_get_args</function>.
|
||
</simpara>
|
||
</note>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="functions.first_class_callable_syntax">
|
||
<title>Синтаксис создания первоклассных callable-значений</title>
|
||
|
||
<para>
|
||
Синтаксис преобразования callable-выражений в объекты первого класса, которые возможно
|
||
передавать как аргумент, возвращать из функций или присваивать переменным,
|
||
представили в PHP 8.1.0 как способ, который
|
||
создаёт <link linkend="functions.anonymous">анонимные функции</link>
|
||
из <link linkend="language.types.callable">callable-выражений</link>.
|
||
Новый синтаксис вытесняет предыдущий callable-синтаксис со строками и массивами.
|
||
Преимущество нового синтаксиса состоит в доступности для статического анализа
|
||
и наследовании новым синтаксисом области видимости переменных в точке
|
||
получения callable-выражения.
|
||
</para>
|
||
|
||
<para>
|
||
Синтаксис <code>CallableExpr(...)</code> создаёт объект
|
||
<classname>Closure</classname> из выражения, доступного для вызова,
|
||
где <code>CallableExpr</code> — элемент синтаксиса, который принимает выражение,
|
||
доступное для прямого вызова в терминах PHP-грамматики:
|
||
<example>
|
||
<title>Пример создания первоклассных вызываемых значений синтаксисом с многоточием</title>
|
||
<programlisting role="php">
|
||
<;
|
||
$f9 = [Foo::class, 'staticmethod'](...);
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
|
||
<note>
|
||
<para>
|
||
Оператор <code>...</code> — часть синтаксиса, а не пропуск.
|
||
</para>
|
||
</note>
|
||
|
||
<para>
|
||
Выражение <code>CallableExpr(...)</code> и метод <methodname>Closure::fromCallable</methodname>
|
||
семантически идентичны. Поэтому в отличие от callable-синтаксиса
|
||
со строками и массивами, синтаксис <code>CallableExpr(...)</code>
|
||
учитывает область видимости контекста, в котором создаёт замыкание:
|
||
<example>
|
||
<title>
|
||
Сравнение области видимости синтаксиса <code>CallableExpr(...)</code>
|
||
и традиционного callable-синтаксиса
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
public function getPrivateMethod()
|
||
{
|
||
return [$this, 'privateMethod'];
|
||
}
|
||
|
||
private function privateMethod()
|
||
{
|
||
echo __METHOD__, "\n";
|
||
}
|
||
}
|
||
|
||
$foo = new Foo();
|
||
$privateMethod = $foo->getPrivateMethod();
|
||
$privateMethod();
|
||
// Fatal error: Call to private method Foo::privateMethod() from global scope
|
||
// Причина фатальной ошибки состоит в вызове замыкания вне класса Foo,
|
||
// при том что видимость метода проверяется в контексте вызова, а не определения
|
||
|
||
class Foo1
|
||
{
|
||
public function getPrivateMethod()
|
||
{
|
||
// Callable-выражение унаследует область видимости переменных,
|
||
// в которой выражение получат
|
||
return $this->privateMethod(...); // Значение возврата идентично
|
||
// значению вызова Closure::fromCallable([$this, 'privateMethod']);
|
||
}
|
||
|
||
private function privateMethod()
|
||
{
|
||
echo __METHOD__, "\n";
|
||
}
|
||
}
|
||
|
||
$foo1 = new Foo1();
|
||
$privateMethod = $foo1->getPrivateMethod();
|
||
$privateMethod(); // Foo1::privateMethod
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
|
||
</para>
|
||
|
||
<note>
|
||
<para>
|
||
Синтаксисом наподобие <code>new Foo(...)</code> нельзя создать объект,
|
||
поскольку синтаксис <code>new Foo()</code> не относится к вызовам.
|
||
</para>
|
||
</note>
|
||
|
||
<note>
|
||
<para>
|
||
Синтаксис, который создаёт объекты первого класса из callable-выражений,
|
||
нельзя комбинировать
|
||
<link linkend="language.oop5.basic.nullsafe">с null-безопасным оператором</link>.
|
||
Каждая из следующих строк вызывает ошибку времени компиляции:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$obj?->method(...);
|
||
$obj?->prop->method(...);
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
</note>
|
||
</sect1>
|
||
|
||
</chapter>
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|