基本上所有的程式語言在類別中都會有建構子和析構函式的概念。建構函式是在函式實例建立時可以用來做一些初始化的工作,而析構函式則可以在實例銷毀前做一些清理工作。相對來說,建構函式我們使用得非常多,而析構函式則一般會用在釋放資源上,例如資料庫連結、檔案讀寫的句柄等。
建構子與析構函式的使用
我們先來看看正常的建構子與析構函式的使用:
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) { $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;
如果我們不打開gc_collect_cycles()那一行的註釋,析構函數執行的順序是這樣的:
// 不使用gc回收的结果 // E destory // E:析构函数被调用,e1 // ----- // E:析构函数被调用,e2 // ----- // E:析构函数被调用,e3 // ----- // E:析构函数被调用,e4 // -----
如果我們打開了gc_collect_cycles()的註釋,析構函數的執行順序是:
// 使用gc回收后结果 // E:析构函数被调用,e1 // ----- // E:析构函数被调用,e2 // ----- // E destory // E:析构函数被调用,e3 // ----- // E:析构函数被调用,e4 // -----
可以看出,必須要讓php使用gc回收一次,確定物件的參考都被釋放了之後,類別的析構函數才會被執行。引用如果沒有釋放,析構函數是不會執行的。
建構子的低版本相容問題
在PHP5以前,PHP的建構子是與類別名稱同名的一個方法。也就是說如果我有一個F類,那麼function F(){}方法就是它的建構子。為了向低版本相容,PHP依然保留了這個特性,在PHP7以後如果有與類別名稱同名的方法,就會報過時警告,但不會影響程式執行。
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:这也是构造函数,与类同名,不区分大小写", 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:这也是构造函数,与类同名", PHP_EOL; // } // function __construct(){ // echo "F:这是构造函数,__construct()", PHP_EOL; // } } $f = new F();
如果__construc()和類別同名方法同時存在的話,會優先走__construct()。另外要注意的是,函數名不區分大小寫,所以F()和f()方法是一樣的都會成為建構子。同理,因為不區分大小寫,所以f()和F()是不能同時存在的。當然,我們都不建議使用類別同名的函數來做建構函數,畢竟已經是過時的特性了,說不定哪天就被取消了。
建構子重載
PHP是不運行方法的重載的,只支援重寫,就是子類別重寫父類別方法,但不能定義多個同名方法而參數不同。在Java等語言中,重載方法非常方便,特別是在類別實例化時,可以方便地實現多態性能力。
$r1 = new R(); // 默认构造函数 $r2 = new R('arg1'); // 默认构造函数 一个参数的构造函数重载,arg1 $r3 = new R('arg1', 'arg2'); // 默认构造函数 两个参数的构造函数重载,arg1,arg2
就像上述程式碼一樣,如果你試著定義多個__construct(),PHP會很直接地告訴你執行不了。那麼有沒有別的方法實現上述程式碼的功能呢?當然有,否則咱也不會寫了。
class R { private $a; private $b; public function __construct() { echo '默认构造函数', 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 '一个参数的构造函数重载,' . $a, PHP_EOL; $this->a = $a; } public function constructB($a, $b) { echo '两个参数的构造函数重载,' . $a . ',' . $b, PHP_EOL; $this->a = $a; $this->b = $b; } } $r1 = new R(); // 默认构造函数 $r2 = new R('arg1'); // 默认构造函数 一个参数的构造函数重载,arg1 $r3 = new R('arg1', 'arg2'); // 默认构造函数 两个参数的构造函数重载,arg1,arg2
相對來說比Java之類的語言要麻煩一些,但是也確實是實現了相同的功能哦。
建構子和析構函式的存取限制
建構子和析構函式預設都是public的,和類別中的其他方法預設值一樣。當然它們也可以設定成private和protected。如果將建構函式設定成非公共的,那麼你將無法實例化這個類別。這點在單例模式被廣泛應用,下面我們直接透過一個單例模式的程式碼看來。
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
當$s3想要實例化時,直接就報錯了。關於單例模式為什麼要讓外部無法實例化的問題,我們可以看看先前的設計模式系統文章中的單例模式。
總結
沒想到我們天天用到的建構子還能玩出這麼多花樣來吧,日常在開發中比較需要注意的就是子類別繼承時對建構子重寫時父類別建構子的呼叫問題以及引用時的析構問題。
推薦教學:《PHP教學》
以上是__construct() 和 __destory() 在 PHP 中需要注意的地方的詳細內容。更多資訊請關注PHP中文網其他相關文章!

PHP在現代Web開發中仍然重要,尤其在內容管理和電子商務平台。 1)PHP擁有豐富的生態系統和強大框架支持,如Laravel和Symfony。 2)性能優化可通過OPcache和Nginx實現。 3)PHP8.0引入JIT編譯器,提升性能。 4)雲原生應用通過Docker和Kubernetes部署,提高靈活性和可擴展性。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP在現代編程中仍然是一個強大且廣泛使用的工具,尤其在web開發領域。 1)PHP易用且與數據庫集成無縫,是許多開發者的首選。 2)它支持動態內容生成和麵向對象編程,適合快速創建和維護網站。 3)PHP的性能可以通過緩存和優化數據庫查詢來提升,其廣泛的社區和豐富生態系統使其在當今技術棧中仍具重要地位。

在PHP中,弱引用是通過WeakReference類實現的,不會阻止垃圾回收器回收對象。弱引用適用於緩存系統和事件監聽器等場景,需注意其不能保證對象存活,且垃圾回收可能延遲。

\_\_invoke方法允許對象像函數一樣被調用。 1.定義\_\_invoke方法使對象可被調用。 2.使用$obj(...)語法時,PHP會執行\_\_invoke方法。 3.適用於日誌記錄和計算器等場景,提高代碼靈活性和可讀性。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

WebStorm Mac版
好用的JavaScript開發工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

Dreamweaver Mac版
視覺化網頁開發工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。