無料CGI、PHPサイト(確認画面付きメールフォーム・メーリングリスト・メルマガ設置、逆アクセスランキング、画像カウンター等)PHPマニュアル by k-sky

遅延静的束縛 (Late Static Bindings)

PHP 5.3.0 以降、PHP に遅延静的束縛と呼ばれる機能が搭載されます。 これを使用すると、静的継承のコンテキストで呼び出し元のクラスを参照できるようになります。

この "遅延静的束縛" という機能名は、内部動作を考慮してつけられたものです。 "遅延束縛 (Late binding)" の由来は、メソッドを定義しているクラス名を使用しても static:: の解決ができなくなったことによります。 その代わりに、実行時情報をもとに解決するようになります。 "静的束縛 (static binding)" の由来は、 静的メソッドのコールに使用できることによります (ただし、静的メソッド以外でも使用可能です)。

self:: の制限

self:: あるいは __CLASS__ による現在のクラスへの静的参照は、 そのメソッドが属するクラス (つまり、 そのメソッドが定義されているクラス) に解決されます。

例1 self:: の使用例

<?php
class {
    public static function 
who() {
        echo 
__CLASS__;
    }
    public static function 
test() {
        
self::who();      
    }  
}  

class 
extends {      
    public static function 
who() {
         echo 
__CLASS__;
    }  
}   

B::test();
?>

上の例の出力は以下となります。

A

遅延静的束縛の使用法

遅延静的束縛は、この制限を解決するためのキーワードを導入し、 実行時に最初にコールされたクラスを参照するようにしています。 このキーワードを使用すると、先ほどの例における test() から B を参照できるようになります。 このキーワードは新たに追加したものではなく、すでに予約済みである static を使用しています。

例2 static:: のシンプルな使用法

<?php
class {
    public static function 
who() {
        echo 
__CLASS__;
    }
    public static function 
test() {
        static::
who(); // これで、遅延静的束縛が行われます
    
}  
}  

class 
extends {      
    public static function 
who() {
         echo 
__CLASS__;
    }  
}   

B::test();
?>

上の例の出力は以下となります。

B

注意: static:: の動作は、静的メソッドにおいては $this と異なります! $this-> は継承規則に従いますが、 static:: は従いません。 この違いについては、後ほど詳しく説明します。

例3 非静的コンテキストにおける static:: の使用法

<?php
class TestChild extends TestParent {
    public function 
__construct() {
        static::
who();
    }

    public function 
test() {
        
$o = new TestParent();
    }

    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}

class 
TestParent {
    public function 
__construct() {
        static::
who();
    }

    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}
$o = new TestChild;
$o->test();

?>

上の例の出力は以下となります。

TestChild
TestParent

注意: 遅延静的束縛の解決は、静的コールが代替なしに完全に解決された時点で終了します。 一方、parent::self:: といったキーワードを使用する静的コールは、コール元の情報を転送します。

例4 転送するコールと転送しないコール

<?php
class {
    public static function 
foo() {
        static::
who();
    }
        
    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}

class 
extends {
    public static function 
test() {
        
A::foo();
        
parent::foo();
        
self::foo();
    }

    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}
class 
extends {
    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}

C::test();
?>

上の例の出力は以下となります。

A
C
C

特殊な場合

PHP でメソッドをコールするには、さまざまな方法があります。 たとえばコールバックやマジックメソッドなどもそのひとつです。 遅延静的束縛は実行時の情報にもとづいて解決を行うので、 このように特殊な場合には予期せぬ結果となる可能性があります。

例5 マジックメソッド内における遅延静的束縛

<?php
class {

   protected static function 
who() {
        echo 
__CLASS__."\n";
   }

   public function 
__get($var) {
       return static::
who();
   }
}

class 
extends {

   protected static function 
who() {
        echo 
__CLASS__."\n";
   }
}

$b = new B;
$b->foo;
?>

上の例の出力は以下となります。

B