Search code examples
phplate-static-binding

PHP Late Static Binding referencing calling class


I have a static function being called that is giving a strange error. Here is an example of the php code:

class foo {
     public $stat;
     public function __construct() {
         $this->stat = stat::isValid('two');
     }
}

class stat {
     protected static $invalidNumbers = array('one', 'two');
     function isValid($number) {
         return in_array($number, static::$invalidNumbers);
     }
}

$foo = new foo();
var_dump($foo->stat);

This code results in the following error:

Fatal error: Access to undeclared static property: foo::$invalidNumbers

However changing static:: to self:: makes the code behave as expected. I was under the impression that in this context using static:: should work.

Why does this error occur using static?


Solution

  • You begin by making a method call in a static context:

    stat::isValid('two');
    

    When you do this, PHP "remembers" the context from within which isValid was called specifically so that it can resolve what to bind to when it sees something like static:: inside the method body, determine if some property you are trying to access is visible, and in general be able to implement some OO-related language features.

    The actual method isValid is not static, but PHP still allows you to call it using the static method syntax (it does give an E_STRICT warning about that). However, this has the side effect that isValid itself does not participate in modifying the curent calling context for (late) static bindings.

    The result: when PHP sees static::$invalidNumbers, it still thinks you are halfway through making a static method call from within the foo class! Once you realize this, it is obvious why static:: resolves to foo:: and it ends up looking for the property at the wrong place.

    If you correctly declare isValid as static

     static function isValid($number) {
         return in_array($number, static::$invalidNumbers);
     }
    

    then upon calling the method PHP does update its context internally and manages to bind to the intended member.