问题
Object not being destroyed before script ends can someone explain why using spl_autoload_register() prevents object from destruction when unset().
The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.
Does spl_autoload_register() have reference to the object that registered it or what happens?
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
回答1:
Does spl_autoload_register() have reference to the object that registered it or what happens?
Yes, it does. But, doesn't because spl_autoload_register was called inside the class. That's happening because of your Closure.
As you can read in manual:
As of PHP 5.4.0, when declared in the context of a class, the current class is automatically bound to it, making $this available inside of the function's scope. If this automatic binding of the current class is not wanted, then static anonymous functions may be used instead.
When the closure has been created inside the class, it'll bound automatically the pseudo-variable $this. Then your instance will have two references:
$MyAutoLoadervariable;Closurepassed tospl_autoload_register.
I've rewritten your example with a few differences which you can see the behavior:
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 created outside of a class doesn't have the class scope
$MyAutoLoader2->registerAutoLoader(function($class){});
unset($MyAutoLoader , $MyAutoLoader2);
echo 'End of script<br/>';
And the result will be:
Destroying: MyAutoLoader - Outside the instance
End of script
Destroying: MyAutoLoader - Inside the instance
In the last example, the Closure has been created out of the class scope. So only the variable $MyAutoLoader2 has the instance of the class.
Another possible example can be:
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/>';
In this last example, I'm creating the Closure outside of class, but I'm binding the class scope into the class, creating a new reference to MyAutoLoader class. The result will be:
End of script
Destroying: MyAutoLoader
A few more tips from bind and bindTo you can read at the link below:
How can I invoke a ReflectionFunction wrapping a closure that utilizes $this?
来源:https://stackoverflow.com/questions/40348781/object-not-being-destroyed-until-end-of-the-script-if-it-registers-spl-autoload