1、定義:它是一個特殊的函數
public function destruct(){}
2、作用:清理對象,釋放內存
3、特點:
1、自動執行,而非手動調用
2、類一旦定義了析構函數,程序結束前就會銷毀該類下的所有實例對象
3、在應用程序結束前的最后一刻執行,除非一些特殊情況,比如第4點,或者當對象的生命周期結束以后也會自動執行
4、 一旦我們手動的銷毀一個對象,系統會自動的觸發該對象的析構函數
特別注意一個特殊的情況:就是如果對象還被其他對象引用的情況下,它的析構函數也不會被觸發
5、在對象的生命周期結束前執行
6、應用程序結束前的最后一刻,會銷毀掉還未銷毀的對象,已經銷毀的對象不會再次被銷毀
進一步得出,一個對象的析構函數只能執行1次,不會執行多次
7、在php中如果我們不為類定義個析構函數,那么php會自動的為類創建一個析構函數,然后在
程序結束前調用默認的析構函數,但是一旦定義了析構函數,就會執行我們寫的析構函數
進一步我們就可以在自己的析構函數里寫自己的業務代碼
比如如果程序使用了打印機資源,我們可以銷毀對象前釋放打印機資源
相關的代碼如下:
<?php class NbaPlayer{ public $name = "";//姓名 public $height = "";//身高 public $weight = "";//體重 public $team = "";//團隊 public $playerName = "";//球員號碼 public function __construct( $name,$height,$weight,$team,$playerName ){ $this->name = $name; $this->height=$height; $this->weight = $weight; $this->team = $team; $this->playName = $playerName; echo "構造函數執行了,當前對象是{$this->name}<br/>"; } //析構函數 public function __destruct(){ echo "銷毀對象".$this->name."<br/>"; } //跑步 public function run(){ echo "跑步中<br/>"; } //跳躍 public function jump(){ echo "跳躍<br/>"; } //運球 public function dribble(){ echo "運球<br/>"; } //傳球 public function pass(){ echo "傳球<br/>"; } //投籃 public function shoot(){ echo "投籃<br/>"; } //扣籃 public function dunk(){ echo "扣籃<br/>"; } } //創建喬丹對象 $jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23"); //輸出喬丹對象 echo "名稱= ".$jordon->name."<br/>"; //讓喬丹跑步 $jordon->run(); //創建科比對象 $kobe = new NbaPlayer("科比","2米","93公斤","湖人","24"); //創建詹姆斯對象 $james = new NbaPlayer("詹姆斯","2.03米","120公斤","熱火","6"); $james1 = new NbaPlayer("詹姆斯1","2.03米","120公斤","熱火","6"); $james2 = new NbaPlayer("詹姆斯2","2.03米","120公斤","熱火","6"); $jordon = null;//手動的銷毀了對象 ,此時喬丹對象的析構函數將會被觸發 $kobe = null;//手動的銷毀了對象 ,此時科比對象的析構函數將會被觸發 echo "<b>程序結束完畢</b><br/>"; ?>
接下來,我代碼修改如下,添加一個Mysql數據庫連接類,然后在NbaPlayer構造函數里面調用它
這是Mysql.class.php,里面定義了一個析構函數
<?php //數據庫類 class Mysql{ //定義屬性 public $conn = ""; //構造函數 public function __construct( ){ //初始化行為 初始化方法 $this->initConn(); } //析構函數 銷毀數據庫連接 public function __destruct(){ //銷毀連接 if( $this->conn ){ mysqli_close( $this->conn ); echo "銷毀了連接<br/>"; } } //定義方法 //創建公共的方法 獲取數據庫連接 public function initConn(){ $config = Array( "hostname"=>"127.0.0.1", "database"=>"Nbaplayer", "username"=>"root", "password"=>"root" ); $this->conn = mysqli_connect( $config['hostname'],$config['username'] ,$config['password'], $config['database']); } } ?>
接下來還是定義個NbaPlayer類,但是為了突出重點,所以NbaPlayer類我會簡寫如下:
<?php require_once "Mysql.class.php"; class NbaPlayer{ public $name = "";//姓名 public $height = "";//身高 public $weight = "";//體重 public $team = "";//團隊 public $playerName = "";//球員號碼 public $conn = "";//添加一個數據庫連接屬性 public function __construct( $name,$height,$weight,$team,$playerName ){ $this->name = $name; $this->height=$height; $this->weight = $weight; $this->team = $team; $this->playName = $playerName; //初始化數據庫連接屬性 $mysql = new Mysql(); $this->conn = $mysql->conn; } //新增獲取所有Nba球員的方法 public function getAll(){ //創建數據庫連接 $conn = $this->conn; //寫sql $sql = " select * from ".$this->tableName; //執行sql $result = mysqli_query( $conn,$sql ); //獲取數據 // mysqli_fetch_all($result)//特點:不會包含字段名 $list = Array(); while( $row = mysqli_fetch_assoc( $result ) ){ $list[] = $row; } //返回數據 return $list; } } //創建喬丹對象 $jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23"); $list = $jordon->getAll(); echo "<b>程序結束完畢</b><br/>"; ?>
當你運行,你會發現錯誤,會發現連接已經被銷毀,在getAll函數調用之前,也就是說,一旦 實例化了 $jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23");
數據庫連接對象就銷毀了,其實如果你去調試,你會發現,構造函數里的mysql對象其實是在NbaPlayer類的構造函數的最后一個}執行完成后,它就會被銷毀,為什么呢
這其實就涉及到變量作用域的問題,因為mysql對象是在構造函數里定義的,所以外面是無法訪問到它的,所以一旦構造函數執行完成后,系統會認為它將不再有用,所以就會
把它清理掉,從而執行它的析構函數,所以最終你去調用getAll方法的時候,數據庫連接都早已斷開,自然無法再去執行sql,
其實想要解決掉這個問題,那么就需要了解對象引用,我們可以結合對象引用來解決這個問題,接下來先來了解對象引用
總結:
1、變量1=變量2=對象 會創建對象的2個獨立引用,但是他們指向的還是同一個對象,所以還是會互相影響
2、變量1=&變量2 只會創建對象的一個引用,因為它們使用同一個對象引用
3、一個對象有沒有用,就要看它是否完全沒有被引用了,如果沒有任何變量引用它,它就真的沒用了,
才會被銷毀,進而它的析構函數才會得以執行
4、變量1=clone 變量2=對象,不會創建對象的新引用,而是仿造了一個新的該對象,具有該對象通用的屬性和方法
相關代碼如下:
<?php class NbaPlayer{ public $name = "";//姓名 public $height = "";//身高 public $weight = "";//體重 public $team = "";//團隊 public $playerName = "";//球員號碼 public function __construct( $name,$height,$weight,$team,$playerName ){ $this->name = $name; $this->height=$height; $this->weight = $weight; $this->team = $team; $this->playName = $playerName; echo "構造函數執行了,當前對象是{$this->name}<br/>"; } public function __destruct(){ echo "銷毀對象".$this->name."<br/>"; } //跑步 public function run(){ echo "跑步中<br/>"; } //跳躍 public function jump(){ echo "跳躍<br/>"; } //運球 public function dribble(){ echo "運球<br/>"; } //傳球 public function pass(){ echo "傳球<br/>"; } //投籃 public function shoot(){ echo "投籃<br/>"; } //扣籃 public function dunk(){ echo "扣籃<br/>"; } } //創建喬丹對象 $jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23"); //輸出喬丹對象 echo "名稱= ".$jordon->name."<br/>"; //讓喬丹跑步 $jordon->run(); //創建科比對象 $kobe = new NbaPlayer("科比","2米","93公斤","湖人","24"); //創建詹姆斯對象 $james = new NbaPlayer("詹姆斯","2.03米","120公斤","熱火","6"); $james1 = new NbaPlayer("詹姆斯1","2.03米","120公斤","熱火","6"); $james2 = new NbaPlayer("詹姆斯2","2.03米","120公斤","熱火","6"); $jordon1 = $jordon;//&符號表示左邊對象和右邊對象其實就是一個對象 $jordon = null;//手動的銷毀了對象 echo "<b>程序結束完畢</b><br/>"; ?>
重點解析:本來不加$jordon1 = $jordon;當程序執行到$jordon=null,喬丹對象的析構函數將會被執行,也就是說 “銷毀對象喬丹”在“程序結束完畢” 前顯示
但是加了這句以后,你會發現執行到$jordon=null的時候,喬丹對象的析構函數并沒有馬上執行,而是到應用程序結束后才被系統自動執行 ,也就是說
“銷毀對象喬丹”在“程序結束完畢” 后顯示
為什么會這樣:
接下來就來具體分析$jordon1 = $jordon 這行代碼到底讓系統做了什么事情
結合上面的代碼,其實我們寫的代碼順序是
$jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23");
$jordon1 = $jordon;
那么$jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23");
說明就是
1、創建了喬丹對象
2、創建了一個變量,變量名叫jordon
3、創了一個喬丹對象的獨立引用,就是上圖的箭頭
然后$jordon1 = $jordon;
說明就是
1、創建了一個新的變量,名叫jordon1
2、又創建了一個喬丹對象的獨立引用,就是上圖的第二個箭頭
那么說明 喬丹對象此時被兩個變量引用,當我們$jordon=null 的時候,喬丹對象還被jordon1變量引用,所以此時喬丹對象還有用,還有用就不能當做垃圾清理掉,
所以這就可以解釋上面的問題,喬丹對象 在最后 才會被系統銷毀,所以要看一個對象是否有用,要看它到底還存不存在變量引用,如果完全不存在變量引用了,那么這個
對象才可以被視作完全無用,它的析構函數才會被執行
好這是對象引用賦值的一種形式,還有另外一種 就是 =&
代碼如下:
<?php class NbaPlayer{ public $name = "";//姓名 public $height = "";//身高 public $weight = "";//體重 public $team = "";//團隊 public $playerName = "";//球員號碼 public function __construct( $name,$height,$weight,$team,$playerName ){ $this->name = $name; $this->height=$height; $this->weight = $weight; $this->team = $team; $this->playName = $playerName; echo "構造函數執行了,當前對象是{$this->name}<br/>"; } public function __destruct(){ echo "銷毀對象".$this->name."<br/>"; } //跑步 public function run(){ echo "跑步中<br/>"; } //跳躍 public function jump(){ echo "跳躍<br/>"; } //運球 public function dribble(){ echo "運球<br/>"; } //傳球 public function pass(){ echo "傳球<br/>"; } //投籃 public function shoot(){ echo "投籃<br/>"; } //扣籃 public function dunk(){ echo "扣籃<br/>"; } } //創建喬丹對象 $jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23"); //輸出喬丹對象 echo "名稱= ".$jordon->name."<br/>"; //讓喬丹跑步 $jordon->run(); //創建科比對象 $kobe = new NbaPlayer("科比","2米","93公斤","湖人","24"); //創建詹姆斯對象 $james = new NbaPlayer("詹姆斯","2.03米","120公斤","熱火","6"); $james1 = new NbaPlayer("詹姆斯1","2.03米","120公斤","熱火","6"); $james2 = new NbaPlayer("詹姆斯2","2.03米","120公斤","熱火","6"); $jordon1 = &$jordon;//&符號表示左邊對象和右邊對象其實就是一個對象 $jordon = null;//手動的銷毀了對象 echo "<b>程序結束完畢</b><br/>"; ?>
當我們把上面的代碼僅僅加上一個 &,也就是把$jordon1 = $jordon 改成 $jordon1 =& $jordon,你會發現結果又變了
變成什么呢,就是當執行$jordon=null的時候,喬丹對象的析構函數還是被執行了,為什么呢
我們再來看下 $jordon1 = & $jordon 做了什么事情
系統所做事情如下:
1、創建變量,jordon1
2、然后不會再次創建喬丹對象引用,$jordon1通過$jordon變量來使用同一個對象引用來訪問喬丹對象
所以此時喬丹對象,只有一個對象引用,不是2個,所以當我們$jordon=null的時候,其實就是銷毀了那唯一的對象引用,進而導致喬丹對象完全沒有了對象引用,所以他的析構函數此時會被觸發執行
不管是$jordon1=$jordon 還是 $jordon1=&jordon ,修改任意變量里面的名稱,都會導致另外變量的名稱被修改掉,因為他們都是引用的同一個喬丹對象
其實對象賦值,除了上面2種方式外,還有第三種,就是 clone(淺復制) ,也就是比如$jordon1 = clone $jordon;
那這樣的賦值方式它究竟又是什么意思呢,其實相當于 仿造了 一個喬丹對象
接下來我們通過代碼演示
<?php class NbaPlayer{ public $name = "";//姓名 public $height = "";//身高 public $weight = "";//體重 public $team = "";//團隊 public $playerName = "";//球員號碼 public function __construct( $name,$height,$weight,$team,$playerName ){ $this->name = $name; $this->height=$height; $this->weight = $weight; $this->team = $team; $this->playName = $playerName; // echo "構造函數執行了,當前對象是{$this->name}<br/>"; } public function __destruct(){ echo "銷毀了對象".$this->name."<br/>"; } //跑步 public function run(){ echo "跑步中<br/>"; } //跳躍 public function jump(){ echo "跳躍<br/>"; } //運球 public function dribble(){ echo "運球<br/>"; } //傳球 public function pass(){ echo "傳球<br/>"; } //投籃 public function shoot(){ echo "投籃<br/>"; } //扣籃 public function dunk(){ echo "扣籃<br/>"; } } //創建喬丹對象 $jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23"); $jordon1 = clone $jordon; $jordon1 = null; $jordon = null; echo "應用程序結束<br/>"; ?>
執行結果如下:
所以$jordon1=clone $jordon;其實就是 仿造了一個喬丹對象,擁有和喬丹對象一樣的屬性和方法
到目前為止,我們了解了對象引用,那么結合對象引用,我們如何解決最開始的那個問題呢?
大家思考一下再看下面的解決方案
....................................
好,接下來我們來看上面我們遇到的問題
問題是:mysql對象在構造函數執行完畢后,就被銷毀了,導致后面getAll函數里的數據庫連接無法使用
解決思路:
1.mysql對象在構造函數執行完成后,就被銷毀了,說明mysql對象此時沒有了對象引用
2.那我們就要讓他在構造函數執行完成后,依然存在對象引用,那么mysql對象就還有用,還有用就不會被銷毀
3.在構造函數里,創建mysql對象的引用,讓它在構造函數執行完成后,這個引用依然存在
4.我們可以定義個類的新屬性比如$mysql,然后讓$this->mysql = $mysql;這樣就創建了一個mysql對象的獨立引用,而且當構造函數執行完成后
類的mysql屬性還有用,所以這個對象引用還有用,進而mysql對象還有用,就不會被銷毀
具體代碼如下:
<?php require_once "Mysql.class.php"; class NbaPlayer{ public $name = "";//姓名 public $height = "";//身高 public $weight = "";//體重 public $team = "";//團隊 public $playerName = "";//球員號碼 public $conn = "";//添加一個數據庫連接屬性 public $mysql = "";//新增一個mysql屬性 public function __construct( $name,$height,$weight,$team,$playerName ){ $this->name = $name; $this->height=$height; $this->weight = $weight; $this->team = $team; $this->playName = $playerName; //初始化數據庫連接屬性 $mysql = new Mysql(); $this->conn = $mysql->conn; //解決問題的重點代碼 $this->mysql = $mysql;//加了這行代碼,getAll中的conn 數據庫連接就不會銷毀 } //新增獲取所有Nba球員的方法 public function getAll(){ //創建數據庫連接 $conn = $this->conn; //寫sql $sql = " select * from ".$this->tableName; //執行sql $result = mysqli_query( $conn,$sql ); //獲取數據 // mysqli_fetch_all($result)//特點:不會包含字段名 $list = Array(); while( $row = mysqli_fetch_assoc( $result ) ){ $list[] = $row; } //返回數據 return $list; } } //創建喬丹對象 $jordon = new NbaPlayer("喬丹","1.98米","98公斤","公牛","23"); $list = $jordon->getAll(); echo "<b>程序結束完畢</b><br/>"; ?>
好了,最后我們再稍微做下總結:
1、了解了析構函數的定義,它其實就是一個特殊函數
2、了解了析構函數的作用,就是8個字,清理對象,釋放內存
3、了解了析構函數的特點,特點有點多,主要7點
4、知道了對象引用的3種賦值方式,一個是=一個是=&,還有一個是clone
以上就是php面向對象之析構函數和對象引用的詳細內容,更多請關注億速云其它相關文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。