Анонимные функции, также известные как closures, позволяют создавать функции без определенного имени. Они наиболее полезны в качестве значений вызываемых параметров, но у них есть много других применений.

Анонимные функции реализованы с помощью. Класс закрытия .

Пример #1 Пример анонимной функции

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
    return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld
?>

Замыкания также могут использоваться как значения переменных; PHP автоматически преобразует такие выражения в экземпляры внутреннего класса Closure . Присваивание замыкания переменной использует тот же синтаксис, что и любое другое присваивание, включая точку с запятой в конце:

Пример #2 Пример назначения переменной анонимной функции

<?php
$greet = function($name)
{
    printf("Hello %s\r\n", $name);
};

$greet('World');
$greet('PHP');
?>

Замыкания также могут наследовать переменные из родительской области. Любые такие переменные должны быть переданы в useязыковую конструкцию. Начиная с PHP 7.1, эти переменные не должны включать суперглобальные значения , $this или переменные с тем же именем, что и параметр. Объявление типа возвращаемого значения функции должно быть помещено после предложения use.

Пример #3 Наследование переменных из родительской области видимости

<?php
$message = 'hello';

// No "use"
$example = function () {
    var_dump($message);
};
$example();

// Inherit $message
$example = function () use ($message) {
    var_dump($message);
};
$example();

// Inherited variable's value is from when the function
// is defined, not when called
$message = 'world';
$example();

// Reset message
$message = 'hello';

// Inherit by-reference
$example = function () use (&$message) {
    var_dump($message);
};
$example();

// The changed value in the parent scope
// is reflected inside the function call
$message = 'world';
$example();

// Closures can also accept regular arguments
$example = function ($arg) use ($message) {
    var_dump($arg . ' ' . $message);
};
$example("hello");

// Return type declaration comes after the use clause
$example = function () use ($message): string {
    return "hello $message";
};
var_dump($example());
?>

Приведенный выше пример выведет что-то похожее на:

Примечание: Неопределенная переменная: сообщение в /example.php в строке 6
НУЛЕВОЙ
строка(5) "привет"
строка(5) "привет"
строка(5) "привет"
строка(5) "мир"
строка (11) "привет, мир"
строка (11) "привет, мир"

Начиная с PHP 8.0.0, список переменных, унаследованных от области видимости, может включать запятую в конце, которая будет игнорироваться.

Наследование переменных из родительской области — это не то же самое, что использование глобальных переменных. Глобальные переменные существуют в глобальной области видимости, которая не зависит от выполняемой функции. Родительская область замыкания — это функция, в которой было объявлено замыкание (не обязательно функция, из которой оно было вызвано). См. следующий пример:

Пример #4 Замыкания и область видимости

<?php
// A basic shopping cart which contains a list of added products
// and the quantity of each product. Includes a method which
// calculates the total price of the items in the cart using a
// closure as a 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;

// Add some items to the cart
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);

// Print the total with a 5% sales tax.
print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
?>

Пример #5 Автоматическая привязка$this

<?php

class Test
{
    public function testing()
    {
        return function() {
            var_dump($this);
        };
    }
}

$object = new Test;
$function = $object->testing();
$function();
    
?>

Приведенный выше пример выведет:

объект(Тест)#1 (0) {
}

При объявлении в контексте класса текущий класс автоматически привязывается к нему, делая его $thisдоступным внутри области видимости функции. Если эта автоматическая привязка текущего класса не нужна, вместо нее можно использовать статические анонимные функции .

Статические анонимные функции

Анонимные функции могут быть объявлены статически. Это предотвращает автоматическую привязку к ним текущего класса. Объекты также могут быть не привязаны к ним во время выполнения.

Пример #6 Попытка использования $thisвнутри статической анонимной функции

<?php

class Foo
{
    function __construct()
    {
        $func = static function() {
            var_dump($this);
        };
        $func();
    }
};
new Foo();

?>

Приведенный выше пример выведет:

Примечание: Неопределенная переменная: это в %s в строке %d
НУЛЕВОЙ

Пример #7 Попытка привязать объект к статической анонимной функции

<?php

$func = static function() {
    // function body
};
$func = $func->bindTo(new StdClass);
$func();

?>

Приведенный выше пример выведет:

Предупреждение: невозможно привязать экземпляр к статическому замыканию в %s в строке %d.