Ответ
Конструкция use в анонимных функциях (замыканиях) позволяет импортировать переменные из внешней области видимости. Без этого замыкание работает в изолированном контексте и не имеет доступа к переменным родительской функции.
Практический пример — фабрика валидаторов:
function createLengthValidator(int $min, int $max): Closure
{
// $min и $max захватываются в момент создания замыкания
return function(string $value) use ($min, $max): bool {
$length = mb_strlen($value);
return $length >= $min && $length <= $max;
};
}
// Создаем специализированные валидаторы
$usernameValidator = createLengthValidator(3, 20);
$passwordValidator = createLengthValidator(8, 255);
// Используем
var_dump($usernameValidator("alice")); // true
var_dump($usernameValidator("ab")); // false
Передача по ссылке:
$counter = 0;
$incrementors = [];
for ($i = 0; $i < 3; $i++) {
// Без & каждая функция получит копию $counter
// С & все функции работают с одной переменной
$incrementors[] = function() use (&$counter) {
$counter++;
return $counter;
};
}
foreach ($incrementors as $inc) {
echo $inc() . " "; // 1 2 3
}
Использование в array_map с внешним контекстом:
$multiplier = 5;
$numbers = [1, 2, 3, 4];
$result = array_map(
function($n) use ($multiplier) {
return $n * $multiplier;
},
$numbers
);
// $result = [5, 10, 15, 20]
Важные особенности:
- Переменные захватываются по значению по умолчанию
- Для захвата по ссылке нужно указать
&перед переменной - Значения фиксируются в момент определения функции, а не вызова
- Можно захватывать несколько переменных:
use ($a, $b, &$c) - В PHP 7.4+ можно использовать стрелочные функции для автоматического захвата
Ответ 18+ 🔞
Давай разберёмся с этим use в анонимных функциях, а то народ иногда нихуя не понимает, как это работает. Представь себе такую хуйню: ты создаёшь функцию внутри другой функции, и эта внутренняя штука живёт в своём маленьком мирке, как будто в аквариуме. Без use она смотрит на внешний мир через стекло и нихуя не может оттуда взять — ни переменных, ни данных, нихуя.
Вот тебе реальный пример, чтобы не быть голословным:
function createLengthValidator(int $min, int $max): Closure
{
// $min и $max захватываются в момент создания замыкания
return function(string $value) use ($min, $max): bool {
$length = mb_strlen($value);
return $length >= $min && $length <= $max;
};
}
// Создаем специализированные валидаторы
$usernameValidator = createLengthValidator(3, 20);
$passwordValidator = createLengthValidator(8, 255);
// Используем
var_dump($usernameValidator("alice")); // true
var_dump($usernameValidator("ab")); // false
Смотри, какая хитрая жопа получается: мы создаём фабрику валидаторов, которая возвращает нам готовую функцию, уже настроенную на конкретные лимиты. Эти $min и $max как бы "замораживаются" внутри замыкания в тот момент, когда мы вызываем createLengthValidator. И потом, когда мы эту функцию используем, она помнит эти значения, ёпта! Удобно же, правда?
А вот ещё прикол с передачей по ссылке, тут вообще веселье начинается:
$counter = 0;
$incrementors = [];
for ($i = 0; $i < 3; $i++) {
// Без & каждая функция получит копию $counter
// С & все функции работают с одной переменной
$incrementors[] = function() use (&$counter) {
$counter++;
return $counter;
};
}
foreach ($incrementors as $inc) {
echo $inc() . " "; // 1 2 3
}
Видишь разницу? Если без амперсанда, то каждая функция получила бы свою копию счётчика, и у нас было бы три единички. А так — все три функции долбят одну и ту же переменную, и счётчик растёт. Это как если бы три человека пили из одной бутылки — понятно, что быстро кончится.
Или вот ещё классика — array_map с внешним контекстом:
$multiplier = 5;
$numbers = [1, 2, 3, 4];
$result = array_map(
function($n) use ($multiplier) {
return $n * $multiplier;
},
$numbers
);
// $result = [5, 10, 15, 20]
Тут всё просто: у нас есть множитель снаружи, и мы его "тащим" внутрь анонимной функции через use. Без этого $multiplier внутри функции был бы не определён, и PHP бы орал, что переменная не найдена. А так — всё работает, красота.
Теперь главные моменты, которые надо запомнить, чтобы не облажаться:
- По умолчанию переменные захватываются по значению — то есть создаётся копия. Хоть ты её внутри функции меняй — снаружи ничего не поменяется.
- Хочешь менять оригинал? Добавь
&перед переменной вuse. Но осторожно, это как играть с огнём — можно нечаянно всё похерить. - Значения фиксируются в момент определения функции, а не когда её вызывают. Это важно! Если ты создал замыкание, а потом поменял переменную снаружи — внутри функции старое значение останется.
- Можно захватывать несколько переменных сразу:
use ($a, $b, &$c)— и по значению, и по ссылке в одном флаконе. - Если ты на PHP 7.4 или новее, можешь использовать стрелочные функции — они автоматически захватывают переменные из внешней области. Но это уже другая история, про которую можно отдельно поговорить.
В общем, use — это такой мостик между мирами. Без него анонимная функция как слепой котёнок — тыкается носом, но нихуя не видит вокруг. А с use она уже может тащить в свой аквариум всё, что нужно. Главное — не переборщить, а то получится такая каша, что разгребать потом овердохуища времени уйдёт.