PHP技術者認定試験の勉強で遅延的束縛(Late Static Bind)について調べて完全に理解したので、備忘録として残しておきます!
遅延的束縛とは
PHP5.3.0から導入された遅延的束縛(Late Static Binding)は簡単にいうと、呼び出すまで実行結果がわからないというものです。
まずは実行前から結果が固定されているパターンから見ていきます。
<?php
class A
{
public static function who()
{
echo __CLASS__;
}
public static function test()
{
self::who();
}
}
class B extends A
{
public static function who()
{
echo __CLASS__;
}
}
A::test();
B::test();
このコードの10行目に記述されているselfは呼び出し元に関係なく、selfが記述されたクラス内の静的メソッドを呼び出します。
なので、Aを継承しているBからtestメソッドを呼び出しても必ずAクラス内のwho()メソッドが呼び出されてAという結果が出力されます。
次は遅延的束縛を利用したパターンです。
<?php
class A
{
public static function who()
{
echo __CLASS__;
}
public static function test()
{
static::who();
}
}
class B extends A
{
public static function who()
{
echo __CLASS__;
}
}
A::test();
B::test();
selfと記述されたいた箇所をstaticに変更しただけで他は同じです。
staticは呼び出し元クラスを参照するので、B::test()を呼び出した時のtestメソッド内の処理はB::who()と同じ意味となり、Bと出力します。
このように、呼び出してからstaticの参照先が決まるので遅延的束縛と呼ばれます。
遅延的束縛をもっと詳しく
冒頭で分かりやすくするためにざっくりと紹介しましたが、遅延的束縛を詳しく説明すると、非転送コール時に明示されたクラス名を保持する機能と言えます。
まずは非転送コールと転送コールの違いを理解しておきましょう。
非転送コール
X::foo()や$x->foo()といったクラス名やオブジェクトを明示的に指定した呼び出し
転送コール
self::, parent::, static::のこと
非転送コールと転送コールを使った例
<?php
class A
{
public static function foo()
{
static::who();
}
public static function who()
{
echo __CLASS__ . "\n";
}
}
class B extends A
{
public static function test()
{
A::foo();
parent::foo();
self::foo();
}
public static function who()
{
echo __CLASS__ . "\n";
}
}
class C extends B
{
public static function who()
{
echo __CLASS__ . "\n";
}
}
C::test();
Cクラスのtest()メソッドを呼び出すことで、
A::foo() 転送コール
parent::foo() 非転送コール
self::foo() 非転送コール
が実行されます。
C::test()は非転送コールでA::foo()も非転送コール。
Aクラス内のwho()メソッドのstaticは直近の非転送コールのクラス名を保持しているためAを指し、A::whoを呼び出すことになり、Aを出力する。
parent::foo()は転送コールなので直近の非転送コールのクラス名を保持します。
つまり、foo()メソッド内でC::who()が実行され、Cが出力される。
self::foo()も転送コールなので直近の非転送コールを保持し、foo()メソッド内でC::who()が呼び出されることになり、Cが出力される。