PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

名前空間> <クラスとオブジェクト (PHP 5)
Last updated: Fri, 04 Jul 2008

view this page in

遅延静的束縛 (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

注意: 遅延静的束縛の解決は、静的コールが代替なしに完全に解決された時点で終了します。

例4 完全に解決された静的コール

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

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

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

B::test();
?>

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

A

特殊な場合

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


名前空間> <クラスとオブジェクト (PHP 5)
Last updated: Fri, 04 Jul 2008
 
add a note add a note User Contributed Notes
遅延静的束縛 (Late Static Bindings)
Andrea Giammarchi
22-Jun-2008 05:06
About static parameters, these work as expected.
<?php
class A {
   
protected static $__CLASS__ = __CLASS__;
   
public static function constructor(){
        return  static::
$__CLASS__;
    }
}

class
B extends A {
   
protected static $__CLASS__ = __CLASS__;
}

echo   
B::constructor(); // B
?>
martinpauly [at] google mail [dot] com
18-Jun-2008 09:54
will this work for variables as well?

it would be great, if the following worked:

<?php
class A {
protected static $table = "table";
public static function connect(){
    
//do some stuff here
    
echo static::$table;
     return static::
getInstance(); //function getInstance() now can return classes A or B depending on the context it was called
}
...
}

class
B extends A {
protected static $table = "subtable";
...
}

$table = B::connect(); //hopefully the output will be: subtable
?>
deadimp at gmail dot com
06-Jun-2008 02:39
I think this will be pretty helpful too.
My question is, can just 'static' by itself resolve to the late static class?
I ask this because it could help in making new instances of the derived class, from a base class, by calling a derived class's static method instead of having to create a new instance of the derived class - or explicitly defining a 'getClass' method for each derived class.
Example:
<?php
//There isn't really any purpose for this example I posted
//Just a random implementation
class Base {
    static function
useful() {
       
//Create a list of instances of the derived class
       
$list=array();
        for (
$i=0;$i<10;$i++) $list[]=new static(); //Here's the point in question
       
return $list;
    }
}
class
Derived extends Base {
    static function
somethingElse() {
       
//...
       
$list=static::useful();
    }
}
?>
I'm not sure what kind of lexical / whatever-it's-called problems this would make with parsing. I don't think it could really collide with any contexts where you would use static otherwise - variable / method declaration.

Even more so, is there a way to get the class's name to which the keywords 'self', 'parent', or 'static' refer?
Example:
<?php
class Base {
    static function
stuff() {
        echo
"Self: ".get_class(self);
        echo
"Parent: ".get_class(parent);
        echo
"Derived: ".get_class(static);
    }
}
class
Derived extends Base {
    static function
stuff() {
        static::
stuff();
    }
}
?>

I don't think there should be a massive bloat in the PHP core to support all of this, but it would be nice to take advantage of the dynamic nature of PHP.

And yet another side note:
If you're in the instance-level scope in a method of a base, and you want to get a top-level static, here's an ugly workaround (from Thacmus /lib/core.php - see SVN repo):
<?php
//Get reference [?] to static from class
    //$class - Class name OR object (uses get_class())
    //$var - Not gonna say
function& get_static($class,$var) { //'static_get'?
   
if (!is_string($class)) $class=get_class($class);
    if (!@
property_exists($class,$var)) {
       
trigger_error("Static property does not exist: $class::\$$var");
       
//debug_callstack(); //This is just a wrapper for debug_backtrace() for HTML
       
return null;
    }
   
//Store a reference so that the base data can be referred to
        //The code [[ return eval('return &'.$class.'::$'.$var.';') ]] does not work - can not return references...
        //To establish the reference, use [[ $ref=&get_static(...) ]]
   
eval('$temp=&'.$class.'::$'.$var.';'); //using
   
return $temp;
}
?>
tyler AT canfone [dot] COM
05-Jun-2008 02:48
@ php at mikebird

You can pass arguments to your constructor through your getInstance method, assuming you are running php5.

        public static function getInstance($params = null) {
            if (self::$objInstance == null) {
                $strClass = static::getClass();
                self::$objInstance = new $strClass($params);
            }
            return self::$objInstance;
        }

This would pass the params to your constructor. Love for php.
sergei at 2440media dot com
29-May-2008 05:22
Finally we can implement some ActiveRecord methods:

<?php

class Model
{
   
public static function find()
    {
        echo static::
$name;
    }
}

class
Product extends Model
{
   
protected static $name = 'Product';
}

Product::find();

?>

Output: 'Product'
php at mikebird dot co dot uk
24-Apr-2008 12:39
This should make life easier and neater if you have a project with a lot of singleton classes e.g.

<?php

   
class Singleton {
       
       
public static $objInstance;
   
       
public static function &getInstance() {
            if (
self::$objInstance == null) {
               
$strClass = static::getClass();
               
self::$objInstance = new $strClass;
            }
            return
self::$objInstance;
        }
       
       
public static function getClass() {
            return
__CLASS__;
        }
   
    }

    class
Foo extends Singleton {
       
       
public $intBar;
       
       
public function __construct() {
           
$this->intBar = 1;
        }
       
       
public static function getClass() {
            return
__CLASS__;
        }
       
    }
   
   
   
$objFooTwo = Foo::getInstance();
   
$objFooTwo->intBar = 2;
   
   
$objFooOne = Foo::getInstance();
   
    if (
$objFooOne->intBar == $objFooTwo->intBar) {
        echo
'it is a singleton';
    } else {
        echo
'it is not a singleton';
    }

?>

The above will output 'it is a singleton'. The obvious downfall to this method is not being able to give arguments to the constructor.
max at mastershrimp dot com
11-Apr-2008 07:24
If you are using PHP < 5.3.0 you might be interested in the following workaround for late static binding: http://de2.php.net/manual/de/function.get-class.php#77698

名前空間> <クラスとオブジェクト (PHP 5)
Last updated: Fri, 04 Jul 2008
 
 
show source | credits | sitemap | contact | advertising | mirror sites