溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

php中的析構函數和對象引用是什么?

發布時間:2020-05-25 15:07:49 來源:億速云 閱讀:290 作者:鴿子 欄目:編程語言

(一)、析構函數

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 這行代碼到底讓系統做了什么事情

php中的析構函數和對象引用是什么?

結合上面的代碼,其實我們寫的代碼順序是

$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 做了什么事情

php中的析構函數和對象引用是什么?

系統所做事情如下:

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/>";


?>

執行結果如下:

php中的析構函數和對象引用是什么?

所以$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面向對象之析構函數和對象引用的詳細內容,更多請關注億速云其它相關文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女