Анонимные функции

Анонимные функции, которые также знают как замыкания (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();

?>

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

 object(Test)#1 (0) { } 

При объявлении замыкания в контексте класса, текущий класс автоматически связывается с замыканием, а члены функции получают доступ к переменной $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 

Список изменений

ВерсияОписание
7.1.0 Анонимные функции не могут замыкаться вокруг superglobals, переменной $this или другой переменной, имя которой совпадает с названием параметра.

Примечания

Замечание: Внутри замыканий разрешается вызывать функции func_num_args(), func_get_arg() и func_get_args().

To Top