基本上所有的编程语言在类中都会有构造函数和析构函数的概念。构造函数是在函数实例创建时可以用来做一些初始化的工作,而析构函数则可以在实例销毁前做一些清理工作。相对来说,构造函数我们使用得非常多,而析构函数则一般会用在释放资源上,比如数据库链接、文件读写的句柄等。
构造函数与析构函数的使用
我们先来看看正常的构造与析构函数的使用:
class A{ public $name; public function __construct($name) { $this->name = $name; echo "A:构造函数被调用,{$this->name}", PHP_EOL; } public function __destruct() { echo "A:析构函数被调用,{$this->name}", PHP_EOL; }}$a = new A('$a');echo '-----', PHP_EOL;class B extends A{ public function __construct($name) { $this->name = $name; parent::__construct($name); echo "B:构造函数被调用,{$this->name}", PHP_EOL; } public function __destruct() { parent::__destruct(); echo "B:析构函数被调用,{$this->name}", PHP_EOL; }}class C extends A{ public function __construct($name) { <span>%本文来源gaodai#ma#com搞*代#码9网#</span><strong>搞gaodaima代码</strong> $this->name = $name; echo "C:构造函数被调用,{$this->name}", PHP_EOL; } public function __destruct() { echo "C:析构函数被调用,{$this->name}", PHP_EOL; }}class D extends A{}// unset($a); // $a的析构提前// $a = null; // $a的析构提前$b = new B('$b');$c = new C('$c');$d = new D('$d');echo '-----', PHP_EOL;exit;// A:构造函数被调用,$a// -----// A:构造函数被调用,$b// B:构造函数被调用,$b// C:构造函数被调用,$c// A:构造函数被调用,$d// -----// A:析构函数被调用,$d// C:析构函数被调用,$c// A:析构函数被调用,$b// B:析构函数被调用,$b// A:析构函数被调用,$a
上面的代码是不是有一些内容和我们的预期不太一样?没事,我们一个一个来看:
子类如果重写了父类的构造或析构函数,如果不显式地使用parent::__constuct()调用父类的构造函数,那么父类的构造函数不会执行,如C类子类如果没有重写构造或析构函数,则默认调用父类的析构函数如果没显式地将变量置为NULL或者使用unset()的话,会在脚本执行完成后进行调用,调用顺序在测试代码中是类似于栈的形式先进后出(C->B->A,C先被析构),但在服务器环境中则不一定,也就是说顺序不一定固定
析构函数的引用问题
当对象中包含自身相互的引用时,想要通过设置为NULL或者unset()来调用析构函数可能会出现问题。
class E{ public $name; public $obj; public function __destruct() { echo "E:析构函数被调用," . $this->name, PHP_EOL; echo '-----', PHP_EOL; }}$e1 = new E();$e1->name = 'e1';$e2 = new E();$e2->name = 'e2';$e1->obj = $e2;$e2->obj = $e1;
类似于这样的代码,$e1和$e2都是E类的对象,他们又各自持有对方的引用。其实简单点来说的话,自己持有自己的引用都会出现类似的问题。
$e1 = new E();$e1->name = 'e1';$e2 = new E();$e2->name = 'e2';$e1->obj = $e2;$e2->obj = $e1;$e1 = null;$e2 = null;// gc_collect_cycles();$e3 = new E();$e3->name = 'e3';$e4 = new E();$e4->name = 'e4';$e3->obj = $e4;$e4->obj = $e3;$e3 = null;$e4 = null;echo 'E destory', PHP_EOL;