Что такое замыкание (closure) в PHP и зачем нужен оператор use?
Что такое замыкание и зачем нужен use?
Начнём с главного: замыкание (closure) — это анонимная функция, которая может использовать переменные из внешней области видимости. Оператор use — это механизм, который явно указывает, какие именно внешние переменные "захватываются" замыканием.
В PHP анонимные функции имеют свою собственную область видимости. Они не видят переменные, объявленные вне их тела, если эти переменные не переданы через use. Это сделано для безопасности и контроля: вы сами решаете, к каким внешним данным у функции есть доступ.
Почему нельзя просто использовать переменную?
В обычных функциях PHP тоже не работает обращение к глобальным переменным без ключевого слова global или суперглобальных массивов. Это особенность языка: функции изолированы от внешнего контекста. Анонимные функции — не исключение, но use даёт более гибкий и безопасный способ "импортировать" переменные.
// Пример: как НЕ работает
$name = "Иван";
$func = function() {
echo $name; // Notice: Undefined variable: name
};
$func();
// А так — работает
$func = function() use ($name) {
echo $name; // Иван
};
$func();
Как работает захват переменных?
Когда вы пишете use ($variable), PHP копирует значение переменной в момент создания замыкания. Это захват по значению. Если вы измените исходную переменную после создания замыкания, внутри замыкания останется старое значение. Чтобы захватить по ссылке (чтобы изменения отражались), используйте &:
$count = 0;
$increment = function() use (&$count) {
$count++;
};
$increment();
echo $count; // 1 — работает, потому что передали по ссылке
Реальные примеры использования замыканий
- Callback-функции: передача поведения в функции вроде
array_mapилиarray_filter. - Фабрики функций: создание функций с предустановленными параметрами.
- Инкапсуляция состояния: "запоминание" значения между вызовами.
Пример: создание множителя
function createMultiplier($factor) {
return function($number) use ($factor) {
return $number * $factor;
};
}
$double = createMultiplier(2);
$triple = createMultiplier(3);
echo $double(5); // 10
echo $triple(5); // 15
Здесь $factor "запоминается" внутри замыкания, хотя внешняя функция createMultiplier уже завершила работу. Это и есть суть замыкания: функция + окружение, в котором она была создана.
Пример: обработчик событий
$items = ['apple', 'banana', 'cherry'];
$searchTerm = 'an';
$filtered = array_filter($items, function($item) use ($searchTerm) {
return strpos($item, $searchTerm) !== false;
});
print_r($filtered); // ['banana']
Итог
- Замыкание = анонимная функция + захваченные переменные.
- use — явный способ указать, какие переменные захватывать.
- Захват может быть по значению (копия) или по ссылке (&).
- Замыкания удобны для callback'ов, фабрик функций и инкапсуляции состояния.
Не бойтесь использовать use — это не магия, а просто способ сделать код понятным и безопасным. Со временем вы привыкнете и оцените эту возможность.
Альтернативный взгляд: замыкания как объекты
В PHP замыкания — это не просто функции, а объекты класса Closure. Это значит, что у них есть методы, например bindTo() и call(), которые позволяют менять контекст выполнения.
Оператор use можно рассматривать как конструктор, который "вшивает" внешние данные в объект-функцию. Это похоже на то, как вы передаёте аргументы в конструктор класса, чтобы сохранить их в свойствах.
// Пример с bindTo
$greeting = function() {
return "Привет, {$this->name}!";
};
$user = new stdClass();
$user->name = "Мария";
$boundGreeting = $greeting->bindTo($user);
echo $boundGreeting(); // Привет, Мария!
Но use проще и удобнее, когда нужно просто захватить переменную, а не менять контекст объекта. Выбирайте подход по ситуации:
- use — для простого захвата переменных из текущей области видимости.
- bindTo/call — когда нужно выполнить функцию в контексте другого объекта.
Также стоит помнить, что с PHP 7.4 появились стрелочные функции (fn), которые автоматически захватывают переменные по значению и не требуют use:
$factor = 2;
$multiply = fn($x) => $x * $factor; // $factor захвачен автоматически
echo $multiply(5); // 10
Но стрелочные функции подходят только для однострочных выражений. Для сложной логики по-прежнему используйте обычные замыкания с use.
Ответов пока нет.
Войдите чтобы оставить ответ