首頁 >後端開發 >php教程 >php為什麼先執行後實例化的物件的析構函數

php為什麼先執行後實例化的物件的析構函數

黄舟
黄舟原創
2017-07-02 10:44:571685瀏覽

問題1:問題如題,自己做了測試

class Obj{        
public $i;        
        public function construct($t){            
        $this->i = $t;            
        echo "执行构造函数$this->i";            
        echo "<br>";
        }        
        public function destruct(){            
        echo "执行析构函数$this->i";            
        echo "<br>";
        }
    }
    $obj1 = new Obj(1);
    $obj2 = new Obj(2);

执行构造函数1执行构造函数2执行析构函数2执行析构函数1

問題2:在子類別中呼叫父類別的建構方法是否只是對父類別進行初始化,是否產生父類別的對象?

======================================UPDATE===== =================================

找到一段理解比較深刻說法:

使用堆疊或堆疊來儲存資料是由PHP引擎決定的,PHP開發者不需要關心.
轉:
在PHP5的Zend Engine的實作中,所有的值都是在堆上分配空間,並且透過引用計數和垃圾收集來管理.
PHP5的Zend Engine主要使用指向zval結構的指標來操作值,在很多地方甚至透過zval的二級指標來操作.
而在PHP7的Zend Engine實作中,值是透過zval結構本身來操作(非指標).
新的zval結構直接被存放在VM的棧上,HashTable的桶裡,以及屬性槽裡.
這樣大大減少了在堆上分配和釋放記憶體的操作,也避免了對簡單值的參考計數和垃圾收集.

======================= =================UPDATE1================================ ======

找到了具體說明的地方

$p1 = new Person();對於這個條碼,$p1 是物件名稱在堆疊記憶體裡面new Person()是真正的物件是在堆記憶體裡面的,具體的請看下圖:

php為什麼先執行後實例化的物件的析構函數

#這樣就解釋了為什麼先實例化的物件是後釋放的

new Person();實際上傳回的是一個物件的引用,然後引用賦值給$p1,$p1是儲存在堆疊中的變量,是一個指針,指向該物件在堆中分配的實體

這同時也解釋了php底層儲存變數是有hash符號表來維護變數的生命週期的,符號表中存有key=>value鍵值對,key為變數名稱,key指向zval結構體,即value的首地址

構造函數和析構函數的執行事實上使用的是一個 棧 結構,由於 Obj(2) 是在後面創建的,因此位於頂部的位置,依照棧 先進後出 的順序,銷毀時,Obj(2) 就是先被銷毀了。

看完樓主的題當時也是好多疑問,我也想知道為什麼不是

执行构造函数1
执行构造函数1
执行析构函数2
执行析构函数2

PHP 5 引入了析構函數的概念,這類似於其它面向對象的語言,如 C++。析構函數會在到某個物件的所有參考都被刪除或當物件被明確銷毀時執行

也就是流程是這樣的

Obj(1) 启动,申请自己的内存空间与上下文环境
Obj(2) 启动,申请自己的内存空间与上下文环境
Obj(2) 销毁,垃圾回收
Obj(1) 销毁,垃圾回收

就是Obj(1 ) 先進後出一樣,他是後實例化,所以先銷毀

----------------------------
Obj(1) Obj(2) Obj(2) Obj(1)
----------------------------

問題2:在子類別中呼叫父類別的建構方法是否只是對父類別進行初始化,是否產生父類別的物件?

同樣手冊。繼承已為大家所熟知的一個程式設計特性,PHP 的物件模型也使用了繼承。繼承將會影響到類別與類,物件與物件之間的關係。

例如,當擴展一個類,子類別就會繼承父類所有公有的和受保護的方法。除非子類別覆寫了父類別的方法,被繼承的方法都會保留其原始功能。

子類別可以呼叫父類別方法,繼承關係不存在實例化

我的想法:

問題1:持有物件參考的變數是存放在堆疊裡面的,堆疊是先進後出,變數obj2先與obj1銷毀

問題2:只會產生一個子類別的物件

第一個問題:obj1和obj2很顯然都是存放在棧內存中,根據棧內存的特徵先進後出,銷毀的時候自然是obj2先銷毀,也就是obj2的destruct先執行,然後才是obj1銷毀,即執行obj1的_desctruct。這也就解釋了你的順序問題。

第二個問題:不會產生父類別對象,當你實例化一個子類別的時候,父類別的公有和受保護的方法會在實例化的對像上。因此你就可以呼叫父類別的方法。

以上是php為什麼先執行後實例化的物件的析構函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn