遅延静的束縛(late static binding)は、継承における静的なコンテキスト内でどのクラスが参照されるかを制御します。重要な区別は次のとおりです。self:: はコードが書かれたクラスを参照し、static:: は実行時に実際に呼び出されたクラスを参照します——これは子クラスが親の静的メソッドを継承する場合に重要になります。
<?php
class ParentClass {
public static function create(): self {
return new self(); // self:: ALWAYS means ParentClass (where it's written)
}
public static function createStatic(): static {
return new static(); // static:: means the CALLED class (runtime)
}
}
class ChildClass extends ParentClass {}
get_class(ChildClass::create()); // "ParentClass" — self:: bound to where written ❌
get_class(ChildClass::createStatic()); // "ChildClass" — static:: bound to the call ✅
self:: は定義時に解決される(常に定義したクラス)ため、ChildClass 経由で呼び出されても new self() は ParentClass を生成します。static:: は実行時に実際に呼び出されたクラスへと解決されます——そのため new static() は正しく ChildClass を生成します。
class Model {
public static function make(): static { // static return type + new static()
return new static(); // ✅ returns an instance of whatever subclass called it
}
}
class User extends Model {}
class Post extends Model {}
User::make(); // returns a User (not a Model) — thanks to late static binding
Post::make(); // returns a Post
遅延静的束縛は、継承されたファクトリメソッド、フルーエントビルダー、ORMパターンが正しいサブクラスのインスタンスを返せるようにするものです——フレームワークが依存する静的メソッドベースのAPIにとって不可欠です。
self:: → the class where the code is WRITTEN (early/static binding)
static:: → the class CALLED at runtime (late static binding) — for subclass-aware code
parent:: → the parent class (for calling overridden parent methods)
遅延静的束縛(static:: vs self::)は重要でありながら誤解されやすいPHPの概念で、特にフレームワークが継承ベースの静的APIをどのように実装しているかを理解するのに関連します。
決定的な区別——self:: はコードが書かれたクラスに束縛されるのに対し、static:: は実行時に実際に呼び出されたクラスに束縛される——は、子クラスがインスタンスを生成したりクラスを参照したりする親の静的メソッドを継承するときにいつでも重要になります。self:: では継承されたファクトリメソッドは常に親の型を返してしまいますが(バグ)、static:: は正しく呼び出し元のサブクラスを返します。
これはまさに、Laravel の Eloquent のようなフレームワークが依存する、継承されたファクトリメソッド、フルーエントビルダー、ORMパターンを可能にするものです(例えば User::make() が基底の Model ではなく User を返す)。
遅延静的束縛を理解することは、これらのフレームワークパターンを正しく使うためにも、サブクラスに対して適切に振る舞う独自の継承を意識した静的メソッドを書くためにも重要です。
より高度なトピックではありますが、これは微妙なバグや混乱(「なぜこれは親クラスを返しているのか?」)のよくある原因であり、self::/static::/parent:: の区別を理解することは、PHPのオブジェクトモデルと継承の振る舞いに対するより深い知識を反映します——モダンなPHPフレームワークでよく見られる、静的メソッドベースで継承の多いAPIを扱い、構築する上で価値があります。