基本上所有的編程語言在類中都會有構(gòu)造函數(shù)和析構(gòu)函數(shù)的概念。構(gòu)造函數(shù)是在函數(shù)實例創(chuàng)建時可以用來做一些初始化的工作,而析構(gòu)函數(shù)則可以在實例銷毀前做一些清理工作。相對來說,構(gòu)造函數(shù)我們使用得非常多,而析構(gòu)函數(shù)則一般會用在釋放資源上,比如數(shù)據(jù)庫鏈接、文件讀寫的句柄等。
創(chuàng)新互聯(lián)建站專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站制作、成都網(wǎng)站設(shè)計、肅寧網(wǎng)絡(luò)推廣、成都小程序開發(fā)、肅寧網(wǎng)絡(luò)營銷、肅寧企業(yè)策劃、肅寧品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們大的嘉獎;創(chuàng)新互聯(lián)建站為所有大學(xué)生創(chuàng)業(yè)者提供肅寧建站搭建服務(wù),24小時服務(wù)熱線:18982081108,官方網(wǎng)址:muchs.cn構(gòu)造函數(shù)與析構(gòu)函數(shù)的使用
我們先來看看正常的構(gòu)造與析構(gòu)函數(shù)的使用:
class A { public $name; public function __construct($name) { $this->name = $name; echo "A:構(gòu)造函數(shù)被調(diào)用,{$this->name}", PHP_EOL; } public function __destruct() { echo "A:析構(gòu)函數(shù)被調(diào)用,{$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:構(gòu)造函數(shù)被調(diào)用,{$this->name}", PHP_EOL; } public function __destruct() { parent::__destruct(); echo "B:析構(gòu)函數(shù)被調(diào)用,{$this->name}", PHP_EOL; } } class C extends A { public function __construct($name) { $this->name = $name; echo "C:構(gòu)造函數(shù)被調(diào)用,{$this->name}", PHP_EOL; } public function __destruct() { echo "C:析構(gòu)函數(shù)被調(diào)用,{$this->name}", PHP_EOL; } } class D extends A { } // unset($a); // $a的析構(gòu)提前 // $a = null; // $a的析構(gòu)提前 $b = new B('$b'); $c = new C('$c'); $d = new D('$d'); echo '-----', PHP_EOL;exit; // A:構(gòu)造函數(shù)被調(diào)用,$a // ----- // A:構(gòu)造函數(shù)被調(diào)用,$b // B:構(gòu)造函數(shù)被調(diào)用,$b // C:構(gòu)造函數(shù)被調(diào)用,$c // A:構(gòu)造函數(shù)被調(diào)用,$d // ----- // A:析構(gòu)函數(shù)被調(diào)用,$d // C:析構(gòu)函數(shù)被調(diào)用,$c // A:析構(gòu)函數(shù)被調(diào)用,$b // B:析構(gòu)函數(shù)被調(diào)用,$b // A:析構(gòu)函數(shù)被調(diào)用,$a
上面的代碼是不是有一些內(nèi)容和我們的預(yù)期不太一樣?沒事,我們一個一個來看:
子類如果重寫了父類的構(gòu)造或析構(gòu)函數(shù),如果不顯式地使用parent::__constuct()調(diào)用父類的構(gòu)造函數(shù),那么父類的構(gòu)造函數(shù)不會執(zhí)行,如C類子類如果沒有重寫構(gòu)造或析構(gòu)函數(shù),則默認(rèn)調(diào)用父類的析構(gòu)函數(shù)如果沒顯式地將變量置為NULL或者使用unset()的話,會在腳本執(zhí)行完成后進行調(diào)用,調(diào)用順序在測試代碼中是類似于棧的形式先進后出(C->B->A,C先被析構(gòu)),但在服務(wù)器環(huán)境中則不一定,也就是說順序不一定固定
析構(gòu)函數(shù)的引用問題
當(dāng)對象中包含自身相互的引用時,想要通過設(shè)置為NULL或者unset()來調(diào)用析構(gòu)函數(shù)可能會出現(xiàn)問題。
class E { public $name; public $obj; public function __destruct() { echo "E:析構(gòu)函數(shù)被調(diào)用," . $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類的對象,他們又各自持有對方的引用。其實簡單點來說的話,自己持有自己的引用都會出現(xiàn)類似的問題。
$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;
如果我們不打開gc_collect_cycles()那一行的注釋,析構(gòu)函數(shù)執(zhí)行的順序是這樣的:
// 不使用gc回收的結(jié)果 // E destory // E:析構(gòu)函數(shù)被調(diào)用,e1 // ----- // E:析構(gòu)函數(shù)被調(diào)用,e2 // ----- // E:析構(gòu)函數(shù)被調(diào)用,e3 // ----- // E:析構(gòu)函數(shù)被調(diào)用,e4 // -----
如果我們打開了gc_collect_cycles()的注釋,析構(gòu)函數(shù)的執(zhí)行順序是:
// 使用gc回收后結(jié)果 // E:析構(gòu)函數(shù)被調(diào)用,e1 // ----- // E:析構(gòu)函數(shù)被調(diào)用,e2 // ----- // E destory // E:析構(gòu)函數(shù)被調(diào)用,e3 // ----- // E:析構(gòu)函數(shù)被調(diào)用,e4 // -----
可以看出,必須要讓php使用gc回收一次,確定對象的引用都被釋放了之后,類的析構(gòu)函數(shù)才會被執(zhí)行。引用如果沒有釋放,析構(gòu)函數(shù)是不會執(zhí)行的。
構(gòu)造函數(shù)的低版本兼容問題
在PHP5以前,PHP的構(gòu)造函數(shù)是與類名同名的一個方法。也就是說如果我有一個F類,那么function F(){}方法就是它的構(gòu)造函數(shù)。為了向低版本兼容,PHP依然保留了這個特性,在PHP7以后如果有與類名同名的方法,就會報過時警告,但不會影響程序執(zhí)行。
class F { public function f() { // Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; F has a deprecated constructor echo "F:這也是構(gòu)造函數(shù),與類同名,不區(qū)分大小寫", PHP_EOL; } // function F(){ // // Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; F has a deprecated constructor // echo "F:這也是構(gòu)造函數(shù),與類同名", PHP_EOL; // } // function __construct(){ // echo "F:這是構(gòu)造函數(shù),__construct()", PHP_EOL; // } } $f = new F();
如果__construc()和類同名方法同時存在的話,會優(yōu)先走__construct()。另外需要注意的是,函數(shù)名不區(qū)分大小寫,所以F()和f()方法是一樣的都會成為構(gòu)造函數(shù)。同理,因為不區(qū)分大小寫,所以f()和F()是不能同時存在的。當(dāng)然,我們都不建議使用類同名的函數(shù)來做為構(gòu)造函數(shù),畢竟已經(jīng)是過時的特性了,說不定哪天就被取消了。
構(gòu)造函數(shù)重載
PHP是不運行方法的重載的,只支持重寫,就是子類重寫父類方法,但不能定義多個同名方法而參數(shù)不同。在Java等語言中,重載方法非常方便,特別是在類實例化時,可以方便地實現(xiàn)多態(tài)能力。
$r1 = new R(); // 默認(rèn)構(gòu)造函數(shù) $r2 = new R('arg1'); // 默認(rèn)構(gòu)造函數(shù) 一個參數(shù)的構(gòu)造函數(shù)重載,arg1 $r3 = new R('arg1', 'arg2'); // 默認(rèn)構(gòu)造函數(shù) 兩個參數(shù)的構(gòu)造函數(shù)重載,arg1,arg2
就像上述代碼一樣,如果你嘗試定義多個__construct(),PHP會很直接地告訴你運行不了。那么有沒有別的方法實現(xiàn)上述代碼的功能呢?當(dāng)然有,否則咱也不會寫了。
class R { private $a; private $b; public function __construct() { echo '默認(rèn)構(gòu)造函數(shù)', PHP_EOL; $argNums = func_num_args(); $args = func_get_args(); if ($argNums == 1) { $this->constructA(...$args); } elseif ($argNums == 2) { $this->constructB(...$args); } } public function constructA($a) { echo '一個參數(shù)的構(gòu)造函數(shù)重載,' . $a, PHP_EOL; $this->a = $a; } public function constructB($a, $b) { echo '兩個參數(shù)的構(gòu)造函數(shù)重載,' . $a . ',' . $b, PHP_EOL; $this->a = $a; $this->b = $b; } } $r1 = new R(); // 默認(rèn)構(gòu)造函數(shù) $r2 = new R('arg1'); // 默認(rèn)構(gòu)造函數(shù) 一個參數(shù)的構(gòu)造函數(shù)重載,arg1 $r3 = new R('arg1', 'arg2'); // 默認(rèn)構(gòu)造函數(shù) 兩個參數(shù)的構(gòu)造函數(shù)重載,arg1,arg2
相對來說比Java之類的語言要麻煩一些,但是也確實是實現(xiàn)了相同的功能哦。
構(gòu)造函數(shù)和析構(gòu)函數(shù)的訪問限制
構(gòu)造函數(shù)和析構(gòu)函數(shù)默認(rèn)都是public的,和類中的其他方法默認(rèn)值一樣。當(dāng)然它們也可以設(shè)置成private和protected。如果將構(gòu)造函數(shù)設(shè)置成非公共的,那么你將無法實例化這個類。這一點在單例模式被廣泛應(yīng)用,下面我們直接通過一個單例模式的代碼看來。
class Singleton { private static $instance; public static function getInstance() { return self::$instance == null ? self::$instance = new Singleton() : self::$instance; } private function __construct() { } } $s1 = Singleton::getInstance(); $s2 = Singleton::getInstance(); echo $s1 === $s2 ? 's1 === s2' : 's1 !== s2', PHP_EOL; // $s3 = new Singleton(); // Fatal error: Uncaught Error: Call to private Singleton::__construct() from invalid context
當(dāng)$s3想要實例化時,直接就報錯了。關(guān)于單例模式為什么要讓外部無法實例化的問題,我們可以看看之前的設(shè)計模式系統(tǒng)文章中的單例模式?!?/p>
以上就是construct()和destory()在PHP中需要注意的詳細(xì)內(nèi)容,更多請關(guān)注創(chuàng)新互聯(lián)其它相關(guān)文章!
分享名稱:怎么使用PHP的構(gòu)造函數(shù)construct與destory-創(chuàng)新互聯(lián)
本文網(wǎng)址:http://muchs.cn/article6/dejiog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護、微信公眾號、網(wǎng)站策劃、移動網(wǎng)站建設(shè)、網(wǎng)站營銷、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容