首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 靜態方法呼叫的隱藏陷阱:$this 指向由呼叫端決定

     編輯:PHP 相關知識

核心結論先行

以 :: 靜態方式呼叫非靜態方法時,方法內的 $this 並非指向定義該方法的類別,而是由呼叫時的上下文決定。

經典實驗代碼

<?php
class TestClass1 {
    public $normal_v = 'normal_v from TestClass1';
    public static $STATIC_V = 'STATIC_V from TestClass1';

    public function test_func1() {
        echo $this->normal_v . '
' . self::$STATIC_V; } } class TestClass2 { public $normal_v = 'normal_v from TestClass2'; public static $STATIC_V = 'STATIC_V from TestClass2'; public function test_func2() { TestClass1::test_func1(); // 靜態呼叫非靜態方法 } } $t2 = new TestClass2(); $t2->test_func2();

輸出結果

normal_v from TestClass2
STATIC_V from TestClass1

深度解析

表達式解析規則結果
$this->normal_v$this 來自呼叫端 $t2(TestClass2 實例)TestClass2 的屬性
self::$STATIC_Vself 在編譯期綁定到定義類別 TestClass1TestClass1 的靜態屬性
static::$STATIC_V (晚期靜態綁定)若改用 static::,則綁定到呼叫端 TestClass2TestClass2 的靜態屬性

為什麼 PHP 允許這樣做?

歷史遺留:PHP 4 時代無 static 關鍵字,所有方法預設皆可靜態呼叫。PHP 5 保留相容性,並引入 E_STRICT(PHP 5.3~7.x)與 E_DEPRECATED(PHP 8.0+)警告:

Deprecated: Non-static method TestClass1::test_func1() should not be called statically

實務守則

  1. 嚴禁靜態呼叫非靜態方法:在 php.ini 設定 error_reporting = E_ALL,升級為錯誤。
  2. 方法分類明確:
    • 需用 $this → public function(實例方法)
    • 不需 $this、只操作靜態屬性 → public static function
  3. 晚期靜態綁定 (LSB):若基類別需取得子類別靜態屬性,請用 static::$prop 而非 self::$prop。
  4. 單例/工廠模式:回傳實例,避免靜態呼叫實例方法。

正確重構範例

<?php
class ServiceA {
    public function doWork() { /* ... */ }
}

class ServiceB {
    private $serviceA;
    public function __construct(ServiceA $a) { $this->serviceA = $a; }
    public function execute() {
        $this->serviceA->doWork(); // 正確:實例呼叫實例方法
    }
}

總結

PHP 允許靜態呼叫非靜態方法是為了向下相容,但會導致 $this 指向呼叫端實例,造成極難除錯的行為。現代 PHP(7.4+)開發應嚴格區分實例與靜態方法,並啟用嚴格錯誤報告杜絕此類寫法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved