Для чего используется use в анонимных функциях PHP

Ответ

Конструкция 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]

Важные особенности:

  1. Переменные захватываются по значению по умолчанию
  2. Для захвата по ссылке нужно указать & перед переменной
  3. Значения фиксируются в момент определения функции, а не вызова
  4. Можно захватывать несколько переменных: use ($a, $b, &$c)
  5. В 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 бы орал, что переменная не найдена. А так — всё работает, красота.

Теперь главные моменты, которые надо запомнить, чтобы не облажаться:

  1. По умолчанию переменные захватываются по значению — то есть создаётся копия. Хоть ты её внутри функции меняй — снаружи ничего не поменяется.
  2. Хочешь менять оригинал? Добавь & перед переменной в use. Но осторожно, это как играть с огнём — можно нечаянно всё похерить.
  3. Значения фиксируются в момент определения функции, а не когда её вызывают. Это важно! Если ты создал замыкание, а потом поменял переменную снаружи — внутри функции старое значение останется.
  4. Можно захватывать несколько переменных сразу: use ($a, $b, &$c) — и по значению, и по ссылке в одном флаконе.
  5. Если ты на PHP 7.4 или новее, можешь использовать стрелочные функции — они автоматически захватывают переменные из внешней области. Но это уже другая история, про которую можно отдельно поговорить.

В общем, use — это такой мостик между мирами. Без него анонимная функция как слепой котёнок — тыкается носом, но нихуя не видит вокруг. А с use она уже может тащить в свой аквариум всё, что нужно. Главное — не переборщить, а то получится такая каша, что разгребать потом овердохуища времени уйдёт.