最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PHP關鍵字Self、Static和parent的區(qū)別詳解

 更新時間:2024年12月31日 09:28:44   作者:程序員阿凡提  
在使用PHP代碼時,您可能經(jīng)常會遇到parent::、static::和self::,但是當你第一次作為一個開發(fā)人員開始的時候,有時候你會很困惑,不知道它們是做什么的,以及它們之間的區(qū)別,本文給大家介紹了PHP關鍵字Self、Static和parent的區(qū)別,需要的朋友可以參考下

簡介

在使用PHP代碼時,您可能經(jīng)常會遇到parent::、static::和self::。但是當你第一次作為一個開發(fā)人員開始的時候,有時候你會很困惑,不知道它們是做什么的,以及它們之間的區(qū)別。

在我第一次作為開發(fā)人員開始工作后的很長一段時間里,我認為static::和self::是完全一樣的。

parent::是什么?

假設我們有一個BaseTestCase類,它有一個setUp方法:

class BaseTestCase
{
    public function setUp(): void
    {
        echo 'Run base test case set up here...';
    }
}
 
(new BaseTestCase())->setUp();
 
// Output is: "Run base test case set up here...';

正如我們所看到的,當我們調(diào)用 setUp 方法時,它按預期運行并輸出文本。

現(xiàn)在,讓我們假設我們想要創(chuàng)建一個新的FeatureTest類來繼承BaseTestCase類。如果我們想運行FeatureTest類的setUp方法,我們可以這樣做:

class FeatureTest extends BaseTestCase
{
    //
}
 
(new FeatureTest())->setUp();
 
// Output is: "Run base test case set up here...";

正如我們所看到的,我們沒有在FeatureTest中定義setUp方法,所以在BaseTestCase中定義的方法將被運行。

現(xiàn)在,假設我們想在運行FeatureTest中的setUp方法時運行一些額外的邏輯。例如,如果這些類是作為PhpUnit測試的一部分使用的測試用例,那么我們可能需要在數(shù)據(jù)庫中創(chuàng)建模型或設置測試值。

一開始,你可能(錯誤地)認為你可以在你的FeatureTest方法中定義setUp方法,然后調(diào)用$this->setUp()。老實說,當我第一次學習編程的時候,我總是陷入這個陷阱!

所以我們的代碼可能看起來像這樣:

class FeatureTest extends BaseTestCase
{
    public function setUp(): void
    {
        $this->setUp();
 
        echo 'Run extra feature test set up here...';
    }
}
 
(new FeatureTest())->setUp();

但是,您會發(fā)現(xiàn),如果我們運行這段代碼,我們最終會陷入一個循環(huán),導致您的應用程序崩潰。這是因為我們遞歸地要求setUp一遍又一遍地調(diào)用它自己。你可能會得到類似這樣的輸出:

Fatal error: Out of memory (allocated 31457280 bytes) (tried to allocate 262144 bytes) in /in/1MXtt on line 15
mmap() failed: [12] Cannot allocate memory
mmap() failed: [12] Cannot allocate memory
Process exited with code 255.

因此,我們需要告訴PHP在BaseTestCase中使用setUp方法,而不是使用$this->setUp()。為了做到這一點,我們可以像這樣用parent::setUp()替換$this->setUp()

class FeatureTest extends BaseTestCase
{
    public function setUp(): void
    {
        parent::setUp();
 
        echo 'Run extra feature test set up here...';
    }
}
 
(new FeatureTest())->setUp();
 
// Output is: "Run base test case set up here... Run extra feature test set up here...";

現(xiàn)在,正如你所看到的,當我們在FeatureTest類中運行setUp方法時,我們首先運行BaseTestCase中的代碼,然后繼續(xù)運行子類中定義的其余代碼。

值得注意的是,您并不總是需要將parent::調(diào)用放在方法的頂部。實際上,您可以將其放置在方法中任何最適合代碼目的的位置。例如,如果你想先在FeatureTest類中運行你的代碼,然后在BaseTestCase類中運行,你可以像這樣將parent::setUp()調(diào)用移動到方法的底部:

self::是什么?

假設我們有一個Model類,它有一個靜態(tài)的connection屬性和一個makeConnection方法。我們還可以想象我們有一個User類,它繼承了Model類并覆蓋了connection屬性。

這兩個類可能看起來像這樣:

class Model
{
    public static string $connection = 'mysql';
 
    public function makeConnection(): void
    {
        echo 'Making connection to: '.self::$connection;
    }
}
 
class User extends Model
{
    public static string $connection = 'postgres';
}

現(xiàn)在讓我們在兩個類上運行makeConnection方法,看看我們會得到什么輸出:

(new Model())->makeConnection();
 
// Output is: "Making connection to mysql"
 
(new User())->makeConnection();
 
// Output is: "Making connection to mysql";

正如我們所看到的,這兩個調(diào)用都導致了Model類的connection屬性被使用。這是因為self使用了在方法所在的類上定義的屬性。在這兩種情況下,makeConnection方法在Model類上是打開的,因為User類上不存在一個方法。

為了進一步說明這一點,我們將向User類添加makeConnection方法,如下所示:

class Model
{
    public static string $connection = 'mysql';
 
    public function makeConnection(): void
    {
        echo 'Making connection to: '.self::$connection;
    }
}
 
class User extends Model
{
    public static string $connection = 'postgres';
 
    public function makeConnection(): void
    {
        echo 'Making connection to: '.self::$connection;
    }
}

現(xiàn)在,如果我們再次調(diào)用這兩個方法,我們會得到以下輸出:

(new Model())->makeConnection();
 
// Output is: "Making connection to mysql"
 
(new User())->makeConnection();
 
// Output is: "Making connection to postgres";

正如您所看到的,對makeConnection的調(diào)用現(xiàn)在將使用User類上的connection字段,因為這是該方法存在的地方。

static::是什么?

現(xiàn)在我們已經(jīng)知道了self::的作用,讓我們來看看static::。

為了更好地理解它的作用,讓我們更新上面的代碼示例,使用static::而不是self::,如下所示:

class Model
{
    public static $connection = 'mysql';
 
    public function makeConnection()
    {
        echo 'Making connection to: '.static::$connection;
    }
}
 
class User extends Model
{
    public static $connection = 'postgres';
}

如果我們在兩個類上運行makeConnection方法,我們會得到以下輸出:

(new Model())->makeConnection();
 
// Output is: "Making connection to mysql"
 
(new User())->makeConnection();
 
// Output is: "Making connection to postgres";

正如我們所看到的,這個輸出與我們之前使用self::$connection時不同。對User類上的makeConnection方法的調(diào)用使用了User類上的connection屬性,而不是Model類(該方法實際所屬的類)。這是由于PHP中一個名為“后期靜態(tài)綁定”的特性。

根據(jù)PHP文檔:這個特性被命名為“后期靜態(tài)綁定”,從內(nèi)部的角度考慮。“后期綁定”來自這樣一個事實,即static::將不會使用定義方法的類來解析,而是使用運行時信息來計算。它也被稱為“靜態(tài)綁定”,因為它可以用于(但不限于)靜態(tài)方法調(diào)用。"

因此,在我們的示例中,使用了User類上的connection屬性,因為我們在同一個類上調(diào)用了makeConnection方法。

然而,值得注意的是,如果connection屬性在User類上不存在,它將回退到使用Model類上的屬性。

什么時候使用self::或 static::?

現(xiàn)在我們對self::static::之間的區(qū)別有了一個大致的了解,讓我們快速介紹一下如何決定在自己的代碼中使用哪一個。

這一切都取決于您正在編寫的代碼的用例。

一般來說,我通常會使用static::而不是self::,因為我希望我的類是可擴展的

例如,假設我想寫一個類,我完全打算由子類繼承(例如上面示例中的BaseTestCase類)。除非我真的想防止子類重寫屬性或方法,否則我想使用static::

這意味著我可以有信心,如果我重寫任何靜態(tài)方法或字段,我的子類將使用我的重寫。我無法告訴你有多少次我在代碼中遇到了bug,當我在父類中使用self::時,然后無法弄清楚為什么我的子類沒有使用我的重寫!

另一方面,一些開發(fā)人員可能會爭辯說,你應該堅持使用self::,因為你不應該真的從類繼承。他們可能會建議你應該遵循“組合優(yōu)于繼承”的原則。我不會深入研究這個話題,因為這是未來的另一篇博客文章。但從廣義上說,簡單地說,這個原則指出,你應該避免通過將所有邏輯放在父類中來為類添加功能,而是通過用許多更小的類來構建類來添加功能。

這意味著如果你遵循這個原則,你就不需要使用static::,因為你永遠不會擴展你的父類。如果你想確保類不能被擴展,你甚至可以更進一步,在定義類時使用final關鍵字。使用final關鍵字可以防止類被繼承,所以它可以減少您對類可能意外擴展并引入任何潛在錯誤的擔憂。

一般來說,最好在編寫代碼時根據(jù)具體情況決定應該使用static::還是self::

以上就是PHP關鍵字Self、Static和parent的區(qū)別詳解的詳細內(nèi)容,更多關于PHP關鍵字Self、Static和parent的資料請關注腳本之家其它相關文章!

相關文章

最新評論

衡南县| 绍兴县| 金门县| 泰兴市| 兴安县| 丹寨县| 柏乡县| 依安县| 灵武市| 宣威市| 泰州市| 龙里县| 康保县| 民县| 塘沽区| 新乐市| 冕宁县| 太湖县| 西乌| 新郑市| 龙里县| 右玉县| 陆河县| 家居| 鄂尔多斯市| 浑源县| 宜春市| 剑阁县| 南江县| 图片| 舟曲县| 固阳县| 溧阳市| 芜湖市| 全南县| 娄烦县| 类乌齐县| 五大连池市| 个旧市| 屯门区| 凤庆县|