Späte statische Bindung

PHP unterstützt späte statische Bindung ("Late static binding"). Hiermit kann die aufgerufene Klasse im Kontext statischer Vererbung referenziert werden.

Genauer gesagt funktioniert späte statische Bindung durch das Speichern der Klasse, die im letzten "nicht weiterleitenden Aufruf" angegeben wurde. Im Fall von statischen Methodenaufrufen ist dies die explizit angegebene Klasse (üblicherweise diejenige auf der linken Seite des Operators ::); im Fall von nicht statischen Methodenaufrufen ist es die Klasse des Objekts. Ein "weiterleitender Aufruf" ist ein statischer, der durch self::, parent::, static:: oder, in der Klassenhierarchie nach oben gehend, durch forward_static_call() eingeleitet wurde. Die Funktion get_called_class() kann benutzt werden, um eine Zeichenkette mit dem Namen der aufgerufenen Klasse abzufragen, und static:: führt ihren Geltungsbereich ein.

Diese Funktionalität wurde in Hinblick auf die interne Perspektive als "späte statische Bindung" benannt. "Späte Bindung" bezieht sich auf die Tatsache, dass static:: nicht über die Klasse, in der die aufgerufene Methode definiert ist, aufgelöst wird, stattdessen wird diese mit Hilfe von Laufzeitinformationen bestimmt. Die Benennung als "statische Bindung" beruht darauf, dass dieser Mechanismus unter anderem für statische Methodenaufrufe genutzt werden kann.

Beschränkungen von self::

Statische Referenzen auf die aktuelle Klasse wie self:: oder __CLASS__ werden mit Hilfe der Klasse, zu der die Methode gehört, also in welcher sie definiert ist, aufgelöst.

Beispiel #1 Nutzung von self::

<?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__;
}
}

B::test();

?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

A

Nutzung später statischer Bindung

Späte statische Bindung versucht diese Beschränkung zu umgehen, indem ein neues Schlüsselwort eingeführt wird, das die Klasse referenziert, die tatsächlich zur Laufzeit genutzt wurde. Im Grunde genommen also ein Schlüsselwort, das es im vorherigen Beispiel ermöglicht die Klasse B aus der aufgerufenen Methode test() zu referenzieren. Es wurde entschieden, kein neues Schlüsselwort einzuführen, sondern statt dessen static zu verwenden, das bereits als reserviertes Schlüsselwort existierte.

Beispiel #2 Einfache Nutzung von static::

<?php

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

public static function
test()
{
static::
who(); // Hier kommt die späte statische Bindung
}
}

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

B::test();

?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

B

Hinweis:

In nicht statischen Kontexten ist die aufgerufene Klasse die Klasse des Objekt-Exemplars. Da $this-> versucht private Methoden im gleichen Geltungsbereich aufzurufen, kann die Verwendung von static:: andere Ergebnisse liefern. Ein weiterer Unterschied ist, dass static:: sich nur auf statische Eigenschaften beziehen kann.

Beispiel #3 Nutzung von static:: außerhalb eines statischen Kontexts

<?php

class A
{
private function
foo()
{
echo
"Erfolg!\n";
}

public function
test()
{
$this->foo();
static::
foo();
}
}

class
B extends A
{
/* foo() wird nach B kopiert, weshalb ihr Geltungsbereich immer noch A ist
* und der Aufruf erfolgreich sein wird */
}

class
C extends A
{
private function
foo()
{
/* ursprüngliche Methode wird ersetzt; der Geltungsbereich der neuen ist C */
}
}

$b = new B();
$b->test();

$c = new C();
try {
$c->test();
} catch (
Error $e) {
echo
$e->getMessage();
}

?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

Erfolg!
Erfolg!
Erfolg!
Call to private method C::foo() from scope A

Hinweis:

Die Auflösung später statischer Bindungen endet mit einem vollständig aufgelösten statischen Aufruf ohne Alternative. Statische Aufrufe, die Schlüsselworte wie parent:: oder self:: nutzen, geben dagegen die Aufrufinformationen weiter.

Beispiel #4 Weitergegebene und nicht weitergegebene Aufrufe

<?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();

?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

A
C
C

add a note

User Contributed Notes 30 notes

up
169
sergei at 2440media dot com
17 years ago
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'
up
64
mhh1422 at hotmail dot com
11 years ago
For abstract classes with static factory method, you can use the static keyword instead of self like the following:<?phpabstract class A{        static function create(){        //return new self();  //Fatal error: Cannot instantiate abstract class A        return new static(); //this is the correct way    }    }class B extends A{}$obj=B::create();var_dump($obj);?>
up
25
MelkiySoft
7 years ago
<?phpclass A {    }class B extends A {    public static function foo () {        echo 'new self: ';        var_dump(new self());        echo '<br>new parent: ';        var_dump(new parent());        echo '<br>new static: ';        var_dump(new static());    }}class C extends B {    }c::foo();===========================output://new self: object(B)#1 (0) { }//new parent: object(A)#1 (0) { }//new static: object(C)#1 (0) { }
up
3
MikeT
2 years ago
Word of caution static::class doesn't always work as you might expect<?phpnamespace NameSpace;class Class{    static function getClass()    {         return static::class;    }}Class::getClass()?>may return \NameSpace\Class or Class depending on context
up
3
Anonymous
3 years ago
class P_Class {    public static $val = "Parent";    public static function setVal($val){        static::$val = $val;    }    public static function getVal(){        return static::$val;    }}class C_Class extends P_Class{}C_Class::setVal("Child");var_dump(C_Class::getVal());var_dump(P_Class::getVal());Output:string(5) "Child"string(5) "Child"
up
8
backnot
3 years ago
In the above example (#3) in order to make it work, you can change the child's method from 'private' to 'protected' (or public) and it will be called through 'static'.<?phpclass A {    private function foo() {        echo "success!\n";    }    public function test() {        $this->foo();        static::foo();    }}class B extends A {   /* foo() will be copied to B, hence its scope will still be A and    * the call be successful */}class C extends A {    protected function foo() { //note the change here         echo 'hello world!';    }}$b = new B();$b->test();$c = new C();$c->test();   // 'success' 'hello world'?>
up
2
aabweber at gmail dot com
3 years ago
Simplest way to understand is to run this script:

<?php
class ParentClass
{
    static $A = 'ParentVariable';

    static function parentCall()
    {
        echo get_called_class() . ', self: ' . self::$A . "\n";
        echo get_called_class() . ', static: ' . static::$A . "\n";
        echo "---\n";
    }
}

class ChildClass extends ParentClass
{
    static $A = 'ChildVariable';

    static function childCall()
    {
        echo get_called_class() . ', self: ' . self::$A . "\n";
        echo get_called_class() . ', static: ' . static::$A . "\n";
        echo get_called_class() . ', parent: ' . parent::$A . "\n";
        echo "---\n";
    }
}

echo "Late Static Bindings:\n";
ParentClass::parentCall();
ChildClass::parentCall();
ChildClass::childCall();
?>

----
Output:

Late Static Bindings:
ParentClass, self: ParentVariable
ParentClass, static: ParentVariable
---
ChildClass, self: ParentVariable
ChildClass, static: ChildVariable
---
ChildClass, self: ChildVariable
ChildClass, static: ChildVariable
ChildClass, parent: ParentVariable
up
13
sskaje at gmail dot com
9 years ago
static::class and self::class can be used to get current class name, work under 5.5 and 5.6failed in 5.3.<?phpclass a{     function d() {        echo "=== self::class ===\n";        var_dump(self::class);        echo "=== static::class ===\n";        var_dump(static::class);    }}class b extends a{}class c extends b{}a::d(); b::d();c::d();/*Output: === self::class ===string(1) "a"=== static::class ===string(1) "a"=== self::class ===string(1) "a"=== static::class ===string(1) "b"=== self::class ===string(1) "a"=== static::class ===string(1) "c"*/
up
7
tyler AT canfone [dot] COM
17 years ago
@ 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.
up
8
steven dot karas+nospam at gmail dot com
14 years ago
This function can be used as a workaround for late static binding in PHP >= 5.1.0. There was another similar version of this function elsewhere, but used eval.<?phpfunction & static_var($class, $name){    if (is_object($class))    {        $class = get_class($class);    }    elseif ( ! is_string($class))    {        throw new Exception('Must be given an object or a class name', NULL);    }        $class = new ReflectionClass($class);    return $class->getStaticPropertyValue($name);}?>
up
12
tamilps2 at gmail dot com
11 years ago
I have implemented enum using late static binding.<?phpinterface IEnum {  /**   * Only concrete class should implement this function that should behave as   * an enum.   *    * This method should return the __CLASS__ constant property of that class   *    * @return string __CLASS__   */  public static function who();}abstract class Enum {  /**   * The selected value for the enum implementation   *    * @var mixed   */  public $value;    public function __construct($value) {    $this->value = $value;  }    /**   * The factory method that creates the corresponding enum class.   *    * @param integer $type   * @return false|\class   */  public static function Factory($type) {    if (empty($type)) {      return false;    }        // use of late static binding to get the class.    $class = static::who();        if (array_key_exists($type, static::$_enums)) {      return new $class($type);    }        return false;  }    public function getValue() {    return $this->value;  }    public static function getValues() {    return array_keys(static::$_enums);  }    public function getString() {    return static::$_enums[$this->value];  }    public function __toString() {    return static::$_enums[$this->value];  }}class Fruits extends Enum implements IEnum {      public static $_enums = array(            1 => 'Apple'            2 => 'Orange'            3 => 'Banana'      )      public static function who() {             return __CLASS__;      }}// Usage// user input from dropdown menu of fruits list$input = 3;$fruit = Fruits::Factory($input);$fruit->getValue(); // 3$fruit->getString(); // Banana?>
up
10
jakub dot lopuszanski at nasza-klasa dot pl
14 years ago
Suprisingly consts are also lazy bound even though you use self instead of static:<?phpclass A{  const X=1;  const Y=self::X;}class B extends A{  const X=1.0;}var_dump(B::Y); // float(1.0)?>
up
5
adam dot prall at thinkingman dot com
15 years ago
Just a quick reminder to always check your syntax. While I love LSB, I thought it wasn't working:static::$sKey = not set…until I realized that I’d completely forgotten to make it a variable variable:$sKey = 'testStaticClassVarNameThatExistsInThisClassesScope';static::$$sKey = is set…of course this applies anywhere in PHP, but because of the (current) newness late static bindings, I’ve seen lots of code with this particular snafu in it from others.
up
7
kx
16 years ago
At least as of PHP 5.3.0a2 there's a function get_called_class(), which returns the class on which the static method is called.<?phpclass a {  static public function test() {    print get_called_class();  }}class b extends a {}a::test(); // "a"b::test(); // "b"?>
up
7
Andrea Giammarchi
17 years ago
About static parameters, these work as expected.<?phpclass A {    protected static $__CLASS__ = __CLASS__;    public static function constructor(){        return  static::$__CLASS__;    }}class B extends A {    protected static $__CLASS__ = __CLASS__;}echo    B::constructor(); // B?>
up
2
joost dot t dot hart at planet dot nl
15 years ago
PHP5.3 unavailable, yet in the need for 'static', I did the following.Any objections? Personally I hate using the the eval() statement...<?phpclass mother{    function setStatic( $prop, $val ) {        // After this, self:: refers to mother, yet next $class refers to...        //        $class = get_class( $this );        eval( "$class::\$$prop = \$$val;" );    }}class child extends mother{    protected static $sProp;    function writer( $value ) {        parent::setStatic( 'sProp', $value );    }    function reader()    {        return self::$sProp;    }}$c = new child();$c->writer( 3 );echo $c->reader(); // 3?>
up
3
Taai
12 years ago
I discovered an interesting thing. The class name string must be accessed directly from "flat" variable. Late static binding code that get's it's variable from array that is passed by class instance, throws an syntax error. Bug?<?phpclass A {    public $metadata = array('class' => 'A');    public static function numbers()    {        return 123;    }}$instance = new A();// This throws an error// Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)var_dump( $instance->metadata['class']::numbers() );// Get the class name and store it in "flat" variable and now it's ok$class_name = $instance->metadata['class'];var_dump( $class_name::numbers() );// Other tests -------------------------------------------$arr =  array('class' => 'A');// This works too.var_dump( $arr['class']::numbers() );?>
up
0
emirii dot mei at gmail dot com
4 months ago
I haven't seen anyone use an anonymous function but it works! This way you only have to add ONE function in your parent class instead of cluttering up your children. It works for regular classes, extended classes, abstract classes, and even classes that inherit interfaces<?phpclass A{   public static string $name = 'A';   public static string $birthday = 'February';   public static string $hairColor = 'Light Brown';   public static function getProperty(string $propertyName)    {        $property = function ($name): string {            return static::$$name;        };        return $property($propertyName);    }       public static function getProperties()    {        $properties = function () {            return get_class_vars(static::class);        };        return $properties();    }}class B extends A{    public static string $name = 'B';    public static string $birthday = 'February';    public static string $hairColor = 'Blonde';}// class Aecho 'My name is: '.A::getProperty('name')."\n"; print_r(A::getProperties());echo "\n";// Class Becho 'My name is: '.B::getProperty('name')."\n"; print_r(B::getProperties());?>The result will be:// My name is: A// Array// (//     [name] => A//     [birthday] => February//     [hairColor] => Light Brown// )// // My name is: B// Array// (//     [name] => B//     [birthday] => February//     [hairColor] => Blonde// )Hopefully this helps someone else that likes simple clean code.
up
0
5imun at github dot com
3 years ago
Example of setting up static property in child class from parent only if it isn't already defined, many people would expect that output will be "Foo Bar" but instead we get "Foo Foo":<?phpclass Foo{    public static string $A;    public static function init() {        return "Foo";    }    public static function get() {        if (!isset(static::$A)) {            static::$A = static::init();        }        return static::$A;    }}class Bar extends Foo {    public static function init() {        return "Bar";    }}$foo = new Foo();$bar = new Bar();echo $foo->get();echo $bar->get();?>Output:FooFoo
up
0
sebastien at info-conseil dot fr
17 years ago
Here is a small workaround I made for the static inheritance issue. It's not perfect, but it works.<?php// BaseClass class will be extended by any class needing static inheritance workaroudclass BaseClass {    // Temporarily stores class name for Entry::getStatic() and Entry::setNextStatic()    protected static $nextStatic = false;        // Returns the real name of the class calling the method, not the one in which it was declared.    protected static function getStatic() {        // If already stored        if (self::$nextStatic) {            // Clean and return            $class = self::$nextStatic;            self::$nextStatic = false;            return $class;        }                // Init        $backTrace = debug_backtrace();        $class = false;                // Walk through        for ($i=0; $i<count($backTrace); $i++) {            // If a class is defined            if (isset($backTrace[$i]['class'])) {                // Check if it is not a basic class                if (!in_array($backTrace[$i]['class'], array('BaseClass', 'GenericClass'))) {                    return $backTrace[$i]['class'];                } else {                    $class = $backTrace[$i]['class'];                }            } else {                // Returns last known class                return $class;            }        }                // Default        return $class;    }        // If a static method is called within global env, the previous method won't work, so we need to tell BaseClass which    public static function setNextStatic($class) {        // Save value        self::$nextStatic = $class;    }}// Generic class declaring various static methodsclass GenericClass extends BaseClass {    public static $name = 'Generic';        public function getName() {        $static = get_class_vars(get_class($this));        return $static['name'];    }        public static function basicClassName() {        return self::$name;    }        public static function staticClassName() {        // Get real name        $staticName = self::getStatic();                // Return final class name        $static = get_class_vars($staticName);        return $static['name'];    }}// Final classclass SomeClass extends GenericClass {    public static $name = 'Some';        public static function returnClassNameWith($string) {        return $string.' : '.self::staticClassName();    }}// Instance call// Will print 'Some'$a = new SomeClass();echo 'Name of $a : '.$a->getName().'<br />';// Static calls// Will print 'Generic'echo 'Basic call to SomeClass::$name : '.SomeClass::basicClassName().'<br />';// Will print 'Generic'echo 'Global call to SomeClass::$name : '.SomeClass::staticClassName().'<br />';// Will print 'Some'BaseClass::setNextStatic('SomeClass');echo 'Global call to SomeClass::$name with pre-set : '.SomeClass::staticClassName().'<br />';// Will print 'Some'echo 'Internal call to SomeClass::$name : '.SomeClass::returnClassNameWith('This is a ').'<br />';?>There are two issues with this workaround :- if you call a static method from global env, you need to declare the name of the class BEFORE calling the method, otherwise the workaround won't work (see 3rd and 4th examples). But I assume good programming makes few calls to static methods from global scope, so this shouldn't be long to fix if you use it.- the workaround fails to access to private or protected static vars, as it uses get_class_vars(). If you find any better solution, let us know.With Php 5.3.0, upgrading will be easy : just delete the methods from the basic class, and search/replace any call to getStatic() and setNextStatic() by static:: - or one could use a selector on PHP_VERSION value to include either the BaseClass file with workaround or a BaseClass file using static::
up
0
deadimp at gmail dot com
17 years ago
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 implementationclass 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:<?phpclass 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 sayfunction& 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;}?>
up
0
max at mastershrimp dot com
17 years ago
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
up
-2
gern_ at hotmail dot com
16 years ago
get_called_class for PHP < 5.3

<?php
/**
 * Return called class name
 *
 * @author Michael Grenier
 * @param int $i_level optional
 * @return string
 */
function get_called_class ($i_level = 1)
{
    $a_debug = debug_backtrace();
    $a_called = array();
    $a_called_function = $a_debug[$i_level]['function'];
    for ($i = 1, $n = sizeof($a_debug); $i < $n; $i++)
    {
        if (in_array($a_debug[$i]['function'], array('eval')) || 
            strpos($a_debug[$i]['function'], 'eval()') !== false)
            continue;
        if (in_array($a_debug[$i]['function'], array('__call', '__callStatic')))
            $a_called_function = $a_debug[$i]['args'][0];
        if ($a_debug[$i]['function'] == $a_called_function)
            $a_called = $a_debug[$i];
    }
    if (isset($a_called['object']) && isset($a_called['class']))
        return (string)$a_called['class'];
    $i_line = (int)$a_called['line'] - 1;
    $a_lines = explode("\n", file_get_contents($a_called['file']));
    preg_match("#([a-zA-Z0-9_]+){$a_called['type']}
                {$a_called['function']}( )*\(#", $a_lines[$i_line], $a_match);
    unset($a_debug, $a_called, $a_called_function, $i_line, $a_lines);
    if (sizeof($a_match) > 0)
        $s_class = (string)trim($a_match[1]);
    else
        $s_class = (string)$a_called['class'];
    if ($s_class == 'self')
        return get_called_class($i_level + 2);
    return $s_class;
}
?>
up
-2
php at mikebird dot co dot uk
17 years ago
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.
up
-3
kenneth at kennethjorgensen dot com
16 years ago
Simple basic class which uses to get_called_class() to create singleton instances. A previous post by php at mikebird dot co dot uk explain how to do this, but the extended static variables require you to define them in child classes before they work.<?phpabstract class Singleton {    private static $instances = array();        public function __construct() {        $class = get_called_class();        if (array_key_exists($class, self::$instances))            trigger_error("Tried to construct  a second instance of class \"$class\"", E_USER_WARNING);    }        public static function getInstance() {        $class = get_called_class();        if (array_key_exists($class, self::$instances) === false)            self::$instances[$class] = new $class();        return self::$instances[$class];    }}class A extends Singleton {}class B extends Singleton {}$a1 = A::getInstance();$a2 = A::getInstance();$b1 = B::getInstance();$b2 = B::getInstance();if (get_class($a1) == "A" &&    get_class($a2) == "A" &&    get_class($b1) == "B" &&    get_class($b2) == "B" &&    $a1 === $a2 &&    $b1 === $b2)    echo "All good\n";else    echo "FAIL!\n";?>You probably noticed the use of self:: rather than static::, this is because we want the static variable to be private, and using static:: will not allow us to do that.
up
-2
martinpauly [at] google mail [dot] com
17 years ago
will this work for variables as well?it would be great, if the following worked:<?phpclass 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?>
up
-3
jrfish dot x at gmail dot com
14 years ago
consider this:

<?php
class A
{

 // some stuff....

    public static function getInstance()
    {
        return new self();
    }

}

class B extends A
{
  //stuff...
}

$obj = B::getInstance();

//versus

class A
{

 // some stuff....

    public static function getInstance()
    {
        return new static();
    }

}

class B extends A
{
  //stuff...
}

$obj = B::getInstance();
?>

also works the same way with static variables and constants
up
-3
iamscrumpyjack
16 years ago
I have been dying to see this issue resolved. I'm very much looking forward to the production release of PHP 5.3...In my case I have been trying to do the following:class A {  function __construct() {    echo "I was called by " . static::__CLASS__;  }}class B extends A {  function Foo() {    echo "I am class " . __CLASS__;  }}$b = new B; // Should echo "I was called by B"$b->Foo(); // Should echo "I am class B"At the moment I do the following workaround:class A {  function __construct($child) {    echo "I was called by " . $child;  }}class B extends A {  function __construct() {    parent::__construct(__CLASS__);  }  function Foo() {    echo "I am class " . __CLASS__;  }}$b = new B; // Echos "I was called by B"$b->Foo(); // Echo "I am class B"As you can see, my current workaround has some overhead and is not as water-tight as the late static binding method.
up
-4
Anonymous
17 years ago
Trying to recreate an inheritable static part for an object through a singleton pattern.<?php/** * "Inheritable static" for PHP < 5.3 * << Library/Inheritable.php >> */abstract class Inheritable_Static extends Singleton{}abstract class Inheritable{    public static function getStatic($className)    {        // Use an abstract Singleton        return Singleton::getInstance($className . '_Static') ;    }        public function goStatic()    {        return self::getStatic(get_class($this)) ;    }}/** * Abstract * << Library/SayIt/Abstract.php >> */abstract class SayIt_Abstract_Static extends Inheritable_Static{    public $format ;}abstract class SayIt_Abstract extends Inheritable{    protected $_name ;        public function __construct($name)    {        $this->_name = $name ;    }        final public function sayIt()    {        echo sprintf($this->goStatic()->format, $this->_name) . "\n" ;    }    }/** * Concrete * << Library/SayIt/Hello.php >> */class SayIt_Hello_Static extends SayIt_Abstract_Static{}class SayIt_Hello extends SayIt_Abstract{    public static function getStatic() { return parent::getStatic(__CLASS__) ; }}/** * Test */SayIt_Hello::getStatic()->format = 'Hello %s' ;$w = new SayIt_Hello('World') ;$j = new SayIt_Hello('Joe') ;echo $w->sayIt() ; // Hello Worldecho $j->sayIt() ; // Hello Joe
up
-2
5imun at github dot com
3 years ago
You must be careful when getting static property of extended class from parent class, in example below you can see that using property_exists (method getA2) instead of isset with static keyword (method getA1) to check if the static property exist gives much more intuitive result:<?phpclass Foo{    public static string $A;    public static function init() {        return static::class;    }    public static function getA1() {        if (!isset(static::$A)) {            static::$A = static::class;        }        return static::$A;    }        public static function getA2() {        if (property_exists(static::class, 'A')) {            static::$A = static::class;        }        return static::$A;    }}class Bar extends Foo {}$foo = new Foo();echo $foo->getA1();echo $foo->getA2();echo $foo->getA1();$bar = new Bar();echo $bar->getA1();echo $bar->getA2();echo $bar->getA1();?>Output:FooFooFooFooBarBarNotice how $bar->getA1() returns "Foo" instead of "Bar" that many people would expect to see.
To Top