<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 簡介 在使用PHP代碼時,您可能經常會遇到`parent::`、`static::`和`self::`。但是當你第一次作為一個開發人員開始的時候,有時候你會很困惑,不知道它們是做什么的,以及它們之間的區別。 在我第一次作為開發人員開始工作后的很長一段時間里,我認為`static::`和`self::`是完全一樣的。 ## `parent::`是什么? 假設我們有一個`BaseTestCase`類,它有一個`setUp`方法: ```php 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...'; ``` 正如我們所看到的,當我們調用 setUp 方法時,它按預期運行并輸出文本。 現在,讓我們假設我們想要創建一個新的`FeatureTest`類來繼承`BaseTestCase`類。如果我們想運行`FeatureTest`類的`setUp`方法,我們可以這樣做: ``` class FeatureTest extends BaseTestCase { // } (new FeatureTest())->setUp(); // Output is: "Run base test case set up here..."; ``` 正如我們所看到的,我們沒有在`FeatureTest`中定義`setUp`方法,所以在`BaseTestCase`中定義的方法將被運行。 現在,假設我們想在運行`FeatureTest`中的`setUp`方法時運行一些額外的邏輯。例如,如果這些類是作為PhpUnit測試的一部分使用的測試用例,那么我們可能需要在數據庫中創建模型或設置測試值。 一開始,你可能(錯誤地)認為你可以在你的`FeatureTest`方法中定義`setUp`方法,然后調用`$this->setUp()`。老實說,當我第一次學習編程的時候,我總是陷入這個陷阱! 所以我們的代碼可能看起來像這樣: ```php class FeatureTest extends BaseTestCase { public function setUp(): void { $this->setUp(); echo 'Run extra feature test set up here...'; } } (new FeatureTest())->setUp(); ``` 但是,您會發現,如果我們運行這段代碼,我們最終會陷入一個循環,導致您的應用程序崩潰。這是因為我們遞歸地要求`setUp`一遍又一遍地調用它自己。你可能會得到類似這樣的輸出: ``` 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..."; ``` 現在,正如你所看到的,當我們在`FeatureTest`類中運行`setUp`方法時,我們首先運行`BaseTestCase`中的代碼,然后繼續運行子類中定義的其余代碼。 值得注意的是,您并不總是需要將`parent::`調用放在方法的頂部。實際上,您可以將其放置在方法中任何最適合代碼目的的位置。例如,如果你想先在`FeatureTest`類中運行你的代碼,然后在`BaseTestCase`類中運行,你可以像這樣將`parent::setUp()`調用移動到方法的底部: ## `self::`是什么? 假設我們有一個`Model`類,它有一個靜態的`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'; } ``` 現在讓我們在兩個類上運行`makeConnection`方法,看看我們會得到什么輸出: ``` (new Model())->makeConnection(); // Output is: "Making connection to mysql" (new User())->makeConnection(); // Output is: "Making connection to mysql"; ``` 正如我們所看到的,這兩個調用都導致了`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; } } ``` 現在,如果我們再次調用這兩個方法,我們會得到以下輸出: ``` (new Model())->makeConnection(); // Output is: "Making connection to mysql" (new User())->makeConnection(); // Output is: "Making connection to postgres"; ``` 正如您所看到的,對`makeConnection`的調用現在將使用`User`類上的`connection`字段,因為這是該方法存在的地方。 ## `static::`是什么? 現在我們已經知道了`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`方法的調用使用了`User`類上的`connection`屬性,而不是`Model`類(該方法實際所屬的類)。這是由于PHP中一個名為“后期靜態綁定”的特性。 如果您有興趣閱讀更多關于后期靜態綁定的內容,可以在這里查看PHP文檔。https://www.php.net/manual/en/language.oop5.late-static-bindings.php > 根據PHP文檔:*這個特性被命名為“后期靜態綁定”,從內部的角度考慮。“后期綁定”來自這樣一個事實,即static::將不會使用定義方法的類來解析,而是使用運行時信息來計算。它也被稱為“靜態綁定”,因為它可以用于(但不限于)靜態方法調用。"* 因此,在我們的示例中,使用了`User`類上的`connection`屬性,因為我們在同一個類上調用了`makeConnection`方法。 然而,值得注意的是,如果`connection`屬性在`User`類上不存在,它將回退到使用`Model`類上的屬性。 ## 什么時候使用self::或 static::? 現在我們對`self::`和`static::`之間的區別有了一個大致的了解,讓我們快速介紹一下如何決定在自己的代碼中使用哪一個。 這一切都取決于您正在編寫的代碼的用例。 一般來說,我通常會使用`static::`而不是`self::`,因為我希望我的類是可擴展的 例如,假設我想寫一個類,我完全打算由子類繼承(例如上面示例中的`BaseTestCase`類)。除非我真的想防止子類重寫屬性或方法,否則我想使用`static::`。 這意味著我可以有信心,如果我重寫任何靜態方法或字段,我的子類將使用我的重寫。我無法告訴你有多少次我在代碼中遇到了bug,當我在父類中使用`self::`時,然后無法弄清楚為什么我的子類沒有使用我的重寫! 另一方面,一些開發人員可能會爭辯說,你應該堅持使用`self::`,因為你不應該真的從類繼承。他們可能會建議你應該遵循“組合優于繼承”的原則。我不會深入研究這個話題,因為這是未來的另一篇博客文章。但從廣義上說,簡單地說,這個原則指出,你應該避免通過將所有邏輯放在父類中來為類添加功能,而是通過用許多更小的類來構建類來添加功能。 這意味著如果你遵循這個原則,你就不需要使用`static::`,因為你永遠不會擴展你的父類。如果你想確保類不能被擴展,你甚至可以更進一步,在定義類時使用`final`關鍵字。使用`final`關鍵字可以防止類被繼承,所以它可以減少您對類可能意外擴展并引入任何潛在錯誤的擔憂。 一般來說,最好在編寫代碼時根據具體情況決定應該使用`static::`還是`self::`。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看