Закрытие PHP: используйте ключевое слово с определением функции: аргумент объекта для использования: параметр не скопирован
Следующий код является слегка измененной версией примера из
Руководство по PHP -> Справочник по языку -> Функции -> Анонимные функции.
В примере упоминается, но не объясняется, почему нельзя передать объект PHP по значению в список аргументов после ключевого слова use в функции. В частности, почему объект не передается по значению в списке параметров использования, как в следующем коде, скопированном внутри анонимной функции $ broken, как это можно сделать со скалярными значениями?
Вот код:
class MyClass {
function doSomething() { echo "HELLO WORLD\n"; }
}
$myInstance = null;
$broken = function() use ($myInstance) {
if(!empty($myInstance)) $myInstance->doSomething();
else echo "\$myInstance is empty.\n";
var_dump($myInstance); // NULL
};
$working = function() use (&$myInstance) {
if(!empty($myInstance)) $myInstance->doSomething();
else print "\$myInstance is empty.\n";
};
$myInstance = new MyClass();
$myInstance->doSomething(); // Outputs HELLO WORLD.
$broken(); // Outputs $myInstance is empty. NULL
$working(); // Outputs HELLO WORLD.
Благодарю.
Это обновление моего поста после ответа, полученного от Валентина Родыгина. Если $ myInstance = null; строка закомментирована, я получаю следующую ошибку:
Notice: Undefined variable: myInstance in C:\xampp\htdocs\myexamples\use.php on line 11
По сути, когда параметр ключевому слову use передается по значению, он копируется во время определения функции, использующей ключевое слово use, а не при вызове функции, использующей ключевое слово use. То же самое верно для переменных, которые передаются по ссылке, но, поскольку они передаются по ссылке, любая последующая модификация такой переменной до вызова функции сделает обновленное значение такой переменной доступным внутри функции.
Благодарю.
1 ответ
Давайте внимательнее посмотрим на ваш код.
$myInstance = null;
$broken = function() use ($myInstance) {
if(!empty($myInstance)) $myInstance->doSomething();
else echo "\$myInstance is empty.\n";
var_dump($myInstance); // NULL
};
На данный момент вы уже создали замыкание и передали туда копию переменной, и она NULL.
$working = function() use (&$myInstance) {
if(!empty($myInstance)) $myInstance->doSomething();
else print "\$myInstance is empty.\n";
};
И здесь вы передали ссылку, поэтому позже, когда вы создали экземпляр $myInstance, он стал доступен в закрытии.