Объект не уничтожается до конца скрипта, если он регистрирует spl_autoload_register ();

Объект, который не уничтожается до завершения скрипта, может объяснить, почему использование spl_autoload_register() предотвращает уничтожение объекта при unset() .

Метод деструктора будет вызываться, как только нет других ссылок на конкретный объект или в любом порядке во время последовательности выключения.

Имеет ли spl_autoload_register() ссылку на объект, который его зарегистрировал или что происходит?

 class MyAutoLoader { public function registerAutoLoader() { spl_autoload_register(function ($class) { }); } public function __destruct() { echo 'Destroying: ' . get_class($this) . "<br/>"; } } $MyAutoLoader = new MyAutoLoader(); $MyAutoLoader->registerAutoLoader(); unset($MyAutoLoader); echo 'End of script<br/>'; //End of script //Destroying: MyAutoLoader с class MyAutoLoader { public function registerAutoLoader() { spl_autoload_register(function ($class) { }); } public function __destruct() { echo 'Destroying: ' . get_class($this) . "<br/>"; } } $MyAutoLoader = new MyAutoLoader(); $MyAutoLoader->registerAutoLoader(); unset($MyAutoLoader); echo 'End of script<br/>'; //End of script //Destroying: MyAutoLoader 

Имеет ли ссылка spl_autoload_register () ссылку на объект, который его зарегистрировал или что происходит?

Да, он делает, но не потому, что в spl_autoload_register был вызван spl_autoload_register . Это происходит потому, что ваше Closure .

Как вы можете прочитать в руководстве:

Начиная с PHP 5.4.0, когда объявляется в контексте класса, текущий класс автоматически привязывается к нему, делая $ this доступным внутри области действия. Если это автоматическое связывание текущего класса не требуется, вместо него могут использоваться статические анонимные функции.

Когда закрытие было создано внутри класса, оно автоматически свяжет псевдо переменную $this . Тогда ваш экземпляр будет иметь две ссылки:

  • $MyAutoLoader Переменная $MyAutoLoader ;
  • Closure передано spl_autoload_register .

Я переписал ваш пример с несколькими отличиями, которые вы можете видеть в поведении:

 class MyAutoLoader { private $instance = "Outside"; public function registerAutoLoader(Closure $closure = null) { //If a closure ins't passed as parameter, a new one will be created if (!$closure instanceof Closure) { $this->instance = "Inside"; //A closure created inside a class will bound the pseudo-variable $this $closure = function ($class) {}; } spl_autoload_register($closure); } public function __destruct() { printf('Destroying: %s - %s instance<br/>' , get_class($this) , $this->instance); } } $MyAutoLoader = new MyAutoLoader(); $MyAutoLoader->registerAutoLoader(); $MyAutoLoader2 = new MyAutoLoader(); //A closure create outside of a class won't have the class scope $MyAutoLoader2->registerAutoLoader(function($class){}); unset($MyAutoLoader , $MyAutoLoader2); echo 'End of script<br/>'; 

И результат будет:

 Destroying: MyAutoLoader - Outside instance End of script Destroying: MyAutoLoader - Inside instance 

В последнем примере Closure был создан из класса. Таким образом, только переменная $MyAutoLoader2 имеет экземпляр класса.

Другим возможным примером может быть:

 class MyAutoLoader { public function registerAutoLoader(Closure $closure) { //Binding the class scope to the closure $closure = $closure->bindTo($this); spl_autoload_register($closure); } public function __destruct() { printf('Destroying: %s <br/>' , get_class($this)); } } $MyAutoLoader = new MyAutoLoader(); $MyAutoLoader->registerAutoLoader(function($class){}); unset($MyAutoLoader); echo 'End of script<br/>'; с class MyAutoLoader { public function registerAutoLoader(Closure $closure) { //Binding the class scope to the closure $closure = $closure->bindTo($this); spl_autoload_register($closure); } public function __destruct() { printf('Destroying: %s <br/>' , get_class($this)); } } $MyAutoLoader = new MyAutoLoader(); $MyAutoLoader->registerAutoLoader(function($class){}); unset($MyAutoLoader); echo 'End of script<br/>'; 

В этом последнем примере я создаю Closure вне класса, но я привязываю класс к классу, создавая новую ссылку на класс MyAutoLoader . Результатом будет:

 End of script Destroying: MyAutoLoader 

Еще несколько советов по bind и bindTo вы можете прочитать по ссылке ниже:

Как я могу вызвать функцию ReflectionFunction, закрывающую закрытие, которое использует $ this?