91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

怎么使用PHP的構造函數construct與destory

發布時間:2020-06-01 22:15:02 來源:億速云 閱讀:219 作者:鴿子 欄目:編程語言

基本上所有的編程語言在類中都會有構造函數和析構函數的概念。構造函數是在函數實例創建時可以用來做一些初始化的工作,而析構函數則可以在實例銷毀前做一些清理工作。相對來說,構造函數我們使用得非常多,而析構函數則一般會用在釋放資源上,比如數據庫鏈接、文件讀寫的句柄等。

構造函數與析構函數的使用

我們先來看看正常的構造與析構函數的使用:

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想要實例化時,直接就報錯了。關于單例模式為什么要讓外部無法實例化的問題,我們可以看看之前的設計模式系統文章中的單例模式。‘

以上就是construct()和destory()在PHP中需要注意的詳細內容,更多請關注億速云其它相關文章!

向AI問一下細節

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

AI

安龙县| 理塘县| 六枝特区| 应用必备| 和政县| 巴南区| 汝阳县| 女性| 开化县| 翁牛特旗| 汝南县| 襄汾县| 东平县| 铜川市| 宁夏| 翁牛特旗| 惠州市| 奉节县| 都江堰市| 察隅县| 遵义县| 隆回县| 普格县| 合山市| 合江县| 富裕县| 泊头市| 札达县| 新龙县| 抚顺市| 思南县| 甘南县| 剑阁县| 曲阳县| 田阳县| 苍山县| 迭部县| 武陟县| 祁连县| 木兰县| 菏泽市|