PHPコレクション実装を通じて理解するLate Static Bindings
Late Static Bindingsとは?
Late Static Bindings
は、実行時にクラスの静的な参照を解決するPHPの機能です。これは特に、メソッドチェーンや継承されたクラスで重要となります。static
キーワードを使うことで、実行時にどのクラスが使用されているかに基づいてメソッドやプロパティを参照できます。
コレクションの実装例
PHPでコレクションを実装する際、メソッドチェーンをサポートするためにLate Static Bindings
を活用することができます。
以下に、基本的なコレクションクラスの例を示します。
class Collection
{
protected $items = [];
public function __construct(
array $items = []
) {
$this->items = $items;
}
public function filter (callable $callback): Collection
{
return new static(array_filter($this->items, $callback));
}
public function map(callable $callback): Collection
{
return new static(array_map($callback, $this->items));
}
}
$collection = new Collection([1, 2, 3, 4, 5]);
$results = $collection->filter(function ($item) {
return $item % 2 === 0;
})->map(function ($item) {
return $item * 2;
});
// 実行結果: $results = [4, 8];
static、selfの使い分け
new static()
、new self()
には、次のような違いがあります。
-
new static()
- 実行時に解決され、サブクラスでオーバーライドされた場合、そのサブクラスのインスタンスを生成します。これは、継承を活用する場合に適しています。
-
new self()
- 常に
self
が定義されたクラス(この例ではCollection
クラス)のインスタンスを生成します。これは、継承を考慮する必要がない場合に使用します。
- 常に
したがって、UserCollection
のようなサブクラスを考慮するコレクションを実装する場合は、new static()
の使用が適切です。一方で、final
クラスなど継承できないクラスに対しては、new self()
の使用が効果的です。
以下にUserCollection
の実装例を示します。
class UserCollection extends Collection
{
// UserCollectionに特有のメソッドやプロパティをここに追加
public function sortByEmail(): static
{
$sorted = $this->items;
usort($sorted, function ($a, $b) {
return $a['email'] <=> $b['email'];
});
return new static($sorted);
}
}
// UserCollectionのインスタンスを作成
$userCollection = new UserCollection([
['email' => 'user1@example.com', 'name' => 'User 1'],
['email' => 'user2@example.com', 'name' => 'User 2'],
]);
// emailでソート
$sortedCollection = $userCollection->sortByEmail();
この実装により、静的解析ツールを使用する際にも、適切な型情報としてUserCollection
を扱うことが可能になります。
まとめ
PHPのコレクション実装を例に、Late Static Bindingsの有効性について解説しました。
適切なキーワード(static
、self
)を選択することで、継承の柔軟性とコードの明確性のバランスを取ることができます。
設計の意図に基づいてこれらのオプションを選択し、より堅牢で再利用可能なコードを作成しましょう。
参考URL
おまけ
記事の主題とは少し離れますが、PHPのオブジェクト指向プログラミングにおいて重要な、static::
とself::
の違いについても触れておきます。
static::メソッド()
は、Late Static Bindingsを利用して、実行時にクラスの解決を行います。これにより、サブクラスでオーバーライドされたメソッドがあれば、そのサブクラスのメソッドが呼び出されます。対してself::メソッド()
は、常にそのメソッドが定義されているクラスのメソッドを呼び出します。
class ParentClass {
public static function test() {
static::who(); // Late Static Bindingsを使用
self::who(); // 通常のStatic Bindingsを使用
}
public static function who() {
echo "ParentClass\n";
}
}
class ChildClass extends ParentClass {
public static function who() {
echo "ChildClass\n";
}
}
class AnotherChildClass extends ParentClass {
// whoメソッドはオーバーライドしていない
}
ChildClass::test();
// 出力:
// ChildClass
// ParentClass
AnotherChildClass::test();
// 出力:
// ParentClass
// ParentClass
このサンプルコードを通じて、static::
とself::
がPHPのオブジェクト指向プログラミングにおいてどのように機能するかをより深く理解することができると思います。
Discussion