PHP5.3で追加された遅延静的束縛(Late Static Bindings)について調べ直した

前にまとめたPHP5系で追加された機能を振り返る記事の続き。今回は、よく理解していなかった遅延静的束縛について調べ直した。

転送コールと非転送コールとは

遅延静的束縛を理解するために、先にこの2つについてまとめる。

▼ 転送コールとは

  • self / parent / staticキーワードによる静的なコール
  • クラス階層の中でのforward_static_call()によるコール

▼ 非転送コールとは

  • Hoge::foo()$hoge->foo()のようなクラス名やオブジェクトを明示したコール

遅延静的束縛とは

遅延静的束縛とは、 直近の非転送コールのクラス名 を保存する機能のことである。この機能はstaticキーワードを用いる。(ちなみにstaticキーワードは、遅延静的束縛以外にも、静的なメソッドやプロパティや変数の定義にも用いるので、意味がごちゃごちゃにならないように注意。)

例えば、以下のようなコードがあるとする。

<?php

class A
{
    protected static $message = 'salmon';

    public static function getSelfMessage()
    {
        return self::$message;
    }

    public static function getStaticMessage()
    {
        return static::$message;
    }
}

class B extends A
{
    protected static $message = 'nyaaaan';
}

var_dump([
    A::getSelfMessage(),   // salmon
    B::getSelfMessage(),   // salmon
    A::getStaticMessage(), // salmon
    B::getStaticMessage(), // nyaaaan
]);

selfキーワードの場合、そのメソッドが属するクラスが参照されるため、A::getSelfMessage()B::getSelfMessage()のどちらも、そのメソッドが属するAクラスに存在する$message = 'salmon'が出力される。

それに対し、staticキーワードの場合、遅延静的束縛で直近の非転送コールのクラスを参照するため、B::getStaticMessage()はBクラスに存在する$message = 'nyaaaan'が出力される。

また、以下のようなコードがあるとする。

<?php

class C
{
    protected static $message = 'board game';

    public static function getMessage()
    {
        return C::getStaticMessage();
    }

    public static function getStaticMessage()
    {
        return static::$message;
    }
}

class D extends C
{
    protected static $message = 'sushi';
}

var_dump([
    C::getMessage(), // board game
    D::getMessage(), // board game
]);

staticキーワードは 直近の 非転送コールのクラスを参照するため、D::getMessage()はCクラスに存在する$message = 'board game'を出力する。

所感

Laravelなどのフレームワークやライブラリで遅延静的束縛を用いた処理はよく見かけるので、きちんと理解しておけば、各フレームワークやライブラリの挙動を追いやすくなって良さそうだと思った。

参考