Poonam Bhatt
Poonam Bhatt

Reputation: 10302

Late static binding in php 5.3

Please go through below given code it is from php manual

<?php
class 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 {
    private function foo() {
        /* original method is replaced; the scope of the new one is C */
    }
}

$b = new B();
$b->test();
$c = new C();
$c->test();   //fails
?> 

can any one explain what is exactly going on here?

How come foo() will be copied to B ?

Upvotes: 3

Views: 677

Answers (2)

Mihai Todor
Mihai Todor

Reputation: 8239

I remember now why late static binding is useful. Unfortunately, the php.net example is kind of poorly explained. See this (modified) example:

<?php
class A {
    private function foo() {
        echo __CLASS__;
    }
    public function test() {
        $this->foo();
        static::foo();
    }
}

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

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

If you run the above code, you will notice that it works and you will get AB. Why?

  • It works because test() is a public getter for foo(), so it does not matter if you call test() from an object of type A, or from an object of type B, that inherits from A, because test() will always have access to the private members of the class in which it is defined.
  • In the first case $this->foo(); will always call A::foo() because the binding is done locally, inside A's scope, which is quite undesirable sometimes. See this comment: http://www.php.net/manual/en/language.oop5.late-static-bindings.php#83502
  • In the second case, static::foo(); instructs the interpreter to determine $b's type and see in which class to try and find foo(). In this case, B::foo() is seen as an override method for A::foo(), so, basically, if B::foo() exists, it will be called, otherwise, the interpreter will look for A::foo().
  • Try to mark B::foo() as private and run the example I provided, to see what happens. I think this test and my rants above will clarify the issue for you ;)

Also, I accept any comments to my above points, because I haven't used PHP in quite a while.

Upvotes: 4

Jonathan S.
Jonathan S.

Reputation: 2228

foo isn't copied to B per se (it is inherited but invisible; see Gordon's comment below). B inherits A->foo, which calls A->test. To demonstrate, look at what happens when you echo __CLASS__ from within test and foo (and remove the static::foo() call, which is causing the error):

class A {
    private function foo() {
        echo __CLASS__."->foo\n";
        echo "success!\n";
    }
    public function test() {
        echo __CLASS__."->test\n";
        $this->foo();
    }
}

Output:

A->test
A->foo
success!
A->test
A->foo
success!

This is one of the fundamentals of inheritance as it relates to information hiding/encapsulation. This allows you to do things like this:

class ListOfThings {
    // internal structure (top secret!)
    private $_list = array();

    // add item to list
    public function add($item) {
        $this->_list[] = $item;
    }

    // return number of items in list
    public function count() {
        return count($this->_list);
    }
}

class ListOfStates extends ListOfThings {

    // do we have all 50 states?
    public function allStatesListed() {
        return $this->count() === 50;
    }

    // try to access internal structure of ListOfThings
    public function accessInternalStructure() {
        sort($this->_list);
    }
}

$states = new ListOfStates;
$states->add('ME');
$states->add('NH');
$states->add('VT');
$states->add('RI');
$states->add('CT');
var_dump($states->count());
var_dump($states->allStatesListed());
$states->accessInternalStructure();

Output:

int(5)
bool(false)

Warning: sort() expects parameter 1 to be array, null given...

As you can see, ListOfStates is able to use all the public functionality of ListOfThings, even though those functions all depend on the private variable $_list. That said, ListOfStates cannot directly manipulate $_list; it can only act on $_list indirectly through the public functions defined in ListOfThings.

Check out the Visibility page in the PHP documentation for more details on such things.

Upvotes: 2

Related Questions