Анонимные функции
Анонимные функции, которые также знают как замыкания (closures
) —
функции без имени.
Анонимные функции вызывают или передают как значения
параметрам с типом callable.
PHP создаёт анонимные функции через класс
Closure.
Пример #1 Пример анонимной функции
<?php
echo preg_replace_callback(
'~-([a-z])~',
function ($match) {
return strtoupper($match[1]);
},
'hello-world'
);
// Выведет helloWorld
?>
Замыкания также присваивают как значения переменным; PHP автоматически
преобразовывает такие выражения в экземпляры внутреннего класса
Closure.
Замыкания присваивают переменной тем же синтаксисом,
что и для другого присваивания, включая конечную точку с запятой:
Пример #2
Пример присваивания анонимной функции как значения переменной
<?php
$greet = function($name) {
printf("Привет, %s\r\n", $name);
};
$greet('Мир');
$greet('PHP');
?>
Замыкания также наследуют переменные из родительской
области видимости. Каждая такая переменная должна быть
передана в языковую конструкцию use
. Начиная с
PHP 7.1 эти переменные не должны включать superglobals,
переменную $this и переменные с именами, которые
совпадают с названиями параметров функции.
Объявление типа для значения, которое возвращает функция,
указывают после конструкции use
.
Пример #3
Пример наследования переменных из родительской области видимости
<?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());
?>
Вывод приведённого примера будет похож на:
Notice: Undefined variable: message in /example.php on line 6
NULL
string(12) "привет"
string(12) "привет"
string(12) "привет"
string(6) "мир"
string(20) "привет, мир"
string(20) "привет, мир"
Начиная с PHP 8.0.0 списку переменных, которые функция
наследует из области видимости, разрешается включать конечную запятую,
которую парсер проигнорирует.
Наследование переменных из родительской области видимости
отличается от наследования глобальных переменных.
Глобальные переменные существуют в глобальной области видимости,
которая остаётся прежней, какая бы функция ни выполнялась.
Родительская область видимости замыкания —
функция, в которой объявили замыкание; не обязательно
функция, из которой замыкание вызвали. Смотрите следующий
пример:
Пример #4 Замыкания и область видимости
<?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
?>
Пример #5 Автоматическое связывание переменной $this
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test();
$function = $object->testing();
$function();
?>
Результат выполнения приведённого примера:
При объявлении замыкания в контексте класса, текущий
класс автоматически связывается с замыканием, а члены функции
получают доступ к переменной $this
в области
видимости функции. Определяют
статические анонимные функции,
если не требуется автоматическое связывание с текущим классом.
Статические анонимные функции
Анонимные функции разрешается объявлять статически.
Это предотвратит автоматическое связывание замыкания
с текущим классом. Объекты также не будут с связаны с замыканием
во время выполнения.
Пример #6
Попытка обратиться к переменной $this
в статической анонимной функции
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
Результат выполнения приведённого примера:
Notice: Undefined variable: this in %s on line %d
NULL
Пример #7
Попытка связать объект со статической анонимной функцией
<?php
$func = static function() {
// Тело функции
};
$func = $func->bindTo(new stdClass);
$func();
?>
Результат выполнения приведённого примера:
Warning: Cannot bind an instance to a static closure in %s on line %d