staticなメソッドやプロパティは、オブジェクトではなくクラスそのものに属します。静的メソッドはClassName::method()で呼び、静的プロパティはClassName::$propertyで読み、先にオブジェクトを作る必要はありません。クラスの中ではself::で同じメンバーを参照します。
どこにもnew Temperature()はありません。静的メンバーは、オブジェクトの状態を必要としないヘルパー(変換、ファクトリー、検証)や、カウンターのようにクラス全体に属するデータに便利です。
静的プロパティはすべてのオブジェクトで共有される
普通のプロパティはオブジェクトごとに1つの値を持ちます。静的プロパティはクラス全体で1つの値を持つので、すべてのオブジェクトが同じものを見ます。ここでは新しいUserが作られるたびに共有のカウンターを増やし、次のIDを受け取ります。
self::$nextIdの$に注意してください。静的プロパティは::のあとも$が残りますが、定数(self::MAX)には付きません。静的プロパティが生きているのは1回のPHPリクエストの間だけです。一般的なWebサイト(PHP-FPMやApache)ではページを読み込むたびに最初からやり直すので、訪問者をまたいでデータを保存する場所にはなりません。
静的メソッドには$thisがない
静的メソッドはオブジェクトなしで実行されるので、中には$thisが存在しません。静的メソッドはself::でほかの静的メソッドを呼べますが、普通のプロパティは読めません。普通のメソッドを静的に呼んでも失敗します。
逆の方向は問題ありません。withSeparator()がself::make()でしているように、普通のメソッドは静的メソッドを呼べます。
selfとstatic:遅延静的束縛
self::はコードが書かれているクラスを指します。static::は実行時にメソッドが呼ばれたクラスを指します。違いが表れるのは継承があるときだけで、いちばん重要になるのはファクトリーメソッドです。
Post::createWithSelf()はModelを返しますが、呼び出し側が望んでいたものであることはまずありません。staticは呼び出しで名前を挙げたクラスなのでPostに解決されます。PHPはこれを遅延静的束縛と呼びます。継承されることを前提にしたメソッドではstatic::とnew static()を使い、本当にこのクラスそのものを指したいときにself::を使います。同じルールは定数にも当てはまり、static::TABLEは子自身のTABLEを拾い、self::TABLEは常にコードが書かれたクラスのものを読みます。
継承した静的プロパティは共有される
子クラスは、自分で宣言しない限り、親の静的プロパティを共有します。これはstaticの定番の驚きで、2つのサブクラスが1つの数を数えてしまうのです。
Applesは自分の$countを持たないので、Apples::$countはCounter::$countで、どちらも2と出力します。Pearsはプロパティを宣言し直しているので、自分で数えます。トレイトで宣言した静的プロパティは動きが違い、トレイトを使う各クラスが別々のコピーを得ます。
関数の中のstatic変数
staticには、関数の本体の中で2つ目の意味があります。static変数は呼び出しの間で値を保ちます。初期値が代入されるのは、関数が最初に実行されたときだけです。
2回目のslowSquare(12)は計算を飛ばします。静的プロパティと同じく、これらの値も各リクエストの終わりにリセットされます。変数のスコープ全般については変数のページで扱っています。
staticが不適切な場面
静的メソッドは便利なので、使いすぎてしまいがちです。すべてのメソッドが静的プロパティを読み書きするクラスは、クラス名を付けたグローバルな状態です。すべての呼び出し側がそれを共有し、テストでは新しいコピーを得られず、別の実装に差し替えることもできません。
staticの適した使い方は、状態を持たない純粋なヘルパー(Slug::make())、名前付きコンストラクタ(Color::fromHex())、クラス全体の定数です。2回の使用で異なりうるデータが必要なメソッドには、オブジェクトが必要です。
よくある質問
PHPで静的メソッドを呼び出すには?
クラス名と::を使います:MathHelper::square(4)。同じクラスの中ではself::square(4)かstatic::square(4)を使います。オブジェクトは不要で、静的メソッドの中には$thisがありません。
PHPのselfとstaticの違いは何ですか?
self::は常にコードが書かれているクラスを意味します。static::は実際にメソッドが呼ばれたクラスを意味し、それは子クラスのこともあります。これを遅延静的束縛と呼びます。そのため親のcreate()メソッドの中で、new self()は常に親を作り、new static()は呼び出したどの子でも作ります。
PHPの静的プロパティとは何ですか?
public static int $count = 0;と宣言したプロパティはクラスに属するので、そのクラスのすべてのオブジェクト(と、子が宣言し直さない限りその子)が共有する1つの値になります。ClassName::$countかself::$countで読み書きします。$に注意してください。
PHPでオブジェクトから静的メソッドを呼べますか?
呼べます。$obj->square(4)も$obj::square(4)も、オブジェクトのクラスの静的メソッドを呼びますが、中にはやはり$thisはありません。失敗するのは逆の方向で、staticでないメソッドをClassName::method()として呼ぶと、PHP 8以降はErrorが投げられます。
静的メソッドの中で$thisを使えますか?
使えません。静的メソッドはオブジェクトなしで実行されるので、そこでは$thisが定義されておらず、使うとError("Using $this when not in object context")が投げられます。ほかの静的メンバーにはself::かstatic::でアクセスします。