Почему переменная, используемая ссылкой на закрытие функции set_error_handler, не определена? - PullRequest
1 голос
/ 01 октября 2019

Читая исходный код Laravel Framework, я наткнулся на этот код

set_error_handler(function ($type, $msg) use (&$error) {
    $error = $msg;
});

в функции move() класса UploadedFile пакета symfony/http-foundation, который Laravel использует Здесь

Расширение Intelephense на VSCode вызывает предупреждение

Неопределенная переменная '$ error'

Приносим свои извинения за скриншот кода (на всякий случайэто ошибка в расширении, и вы не можете воспроизвести ее, пожалуйста, скажите мне) Извините

enter image description here

При исследовании этого я обнаружил этоответ , который передает использование замыкания в set_error_handler

$that = $this;
set_error_handler( function() use ($that) { $that->customErrorHandler(); } );

Насколько я понимаю, customErrorHandler() - это функция в том же классе или контексте, и ее необходимо определить вне вызова

Поиск аналогичного примера в официальных документах дает те же результаты, см. Здесь

Но класс Symfony UploadedFile определяет только частное свойство $error, глобальное для класса, поэтомуне должно ли быть так?

$error = $this->error;
set_error_handler(function ($type, $msg) use (&$error) {
    $error = $msg;
});

Как дела? Знает ли этот код, чтобы получить переменную $error из свойства, не определяя его? *

*, если он получает его оттуда, в противном случае ...

Как передается $errorВот? undefined предупреждение законно? учитывая, что код действительно работает (просто любопытно)

1 Ответ

1 голос
/ 01 октября 2019

&$error заставляет код работать. По сути, он присваивает переменной $error значение NULL, когда вы передаете вызываемый объект, а затем внутри, он устанавливает его в сообщении об ошибке и затем использует.

set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
$moved = move_uploaded_file($this->getPathname(), $target);
restore_error_handler();

Затем он использует $errorпеременная, если она не может быть перемещена:

if (!$moved) {
    throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
}

Это то же самое, что и:

$error = null;
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });

Без & будет выдано уведомление о неопределенной переменной.

И никакая переменная $error не связана со свойством error.

Вы можете взять этот код, например:

function executeCallback($callable) {
    $callable();   
}

executeCallback(function () use (&$error) {
    $error = 'This is the error message.';
});

echo $error;

Переменная $error определена в use (&$error) и используется позже. И вывод echo будет:

Это сообщение об ошибке.

...