Reputation: 10302
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
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?
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.$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#83502static::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()
.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
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