這個自我和靜態加上單例

使用 $this 來引用當前物件。使用 self 來引用當前的類。換句話說,將 $this->member 用於非靜態成員,將 self::$member 用於靜態成員。

在下面的例子中,sayHello()sayGoodbye() 正在使用 self$this 差異可以在這裡觀察到。

class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();

static 指的是你呼叫方法的層次結構中的任何類。它允許在繼承類時更好地重用靜態類屬性。

請考慮以下程式碼:

class Car {
    protected static $brand = 'unknown';
    
    public static function brand() {
         return self::$brand."\n";
    }
}

class Mercedes extends Car {
    protected static $brand = 'Mercedes';
}

class BMW extends Car {
    protected static $brand = 'BMW';
}

echo (new Car)->brand();
echo (new BMW)->brand();
echo (new Mercedes)->brand();

這不會產生你想要的結果:

未知的
未知
未知

這是因為 self 只要呼叫方法 brand() 就會引用 Car 類。

要引用正確的類,你需要使用 static 代替:

class Car {
    protected static $brand = 'unknown';
    
    public static function brand() {
         return static::$brand."\n";
    }
}

class Mercedes extends Car {
    protected static $brand = 'Mercedes';
}

class BMW extends Car {
    protected static $brand = 'BMW';
}

echo (new Car)->brand();
echo (new BMW)->brand();
echo (new Mercedes)->brand();

這確實產生了所需的輸出:

未知的
寶馬
梅賽德斯

另請參見 Late static binding

單例

如果你建立的物件很昂貴,或者表示要重用的某個外部資源的連線,即沒有連線池的資料庫連線或其他系統的套接字,則可以使用 staticself 關鍵字。使它成為單例的類。關於是否應該使用單例模式有強烈的意見,但它確實有其用途。

class Singleton {
    private static $instance = null;

    public static function getInstance(){
        if(!isset(self::$instance)){
            self::$instance = new self();
        }
        
        return self::$instance;
    }
    
    private function __construct() {
        // Do constructor stuff
    }
}

正如你在示例程式碼中看到的,我們定義了一個私有靜態屬性 $instance 來儲存物件引用。由於這是靜態的,因此該引用在此型別的所有物件之間共享。

getInstance() 方法使用一種稱為延遲例項化的方法來將物件延遲到最後可能的時刻,因為你不希望未使用的記憶體中存在未使用的物件。它還節省了頁面載入的時間和 CPU,而不必載入超過必要的物件。該方法是檢查物件是否已設定,如果沒有則建立它,並返回它。這確保了只建立了這種物件。

我們還將建構函式設定為私有,以確保沒有人使用外部的 new 關鍵字建立它。如果你需要繼承此類,只需將 private 關鍵字更改為 protected 即可。

要使用此物件,你只需編寫以下內容:

$singleton = Singleton::getInstance();

現在我懇請你儘可能使用依賴注入,並針對鬆散耦合的物件,但有時候這是不合理的,單例模式可以使用。