Calls using parent:: or self:: are considered to be static. These are supposed to be evaluated in the context of the defining class, not in the scope of the calling object. PHP 5.3 adds a new meaning to the word static which would be available for static calls like parent and self, but will be evaluated in the context of the calling class. This is called Late Static Binding. More info on this page:
http://www.php.net/lsb
Edit:
After some thought I believe this behavior is perfectly acceptable. First, let's see why would A want that its foo() method to call the foo() method of its parent, given that A has no parent. Because, it wants the method to always be executed regardless of the implementation of the children. If so, there are other solutions, not that nice though:
class A
{
final public function __construct()
{
echo __METHOD__;
$this->foo();
$init = array($this, 'init');
$args = func_get_args();
call_user_func_array($init, $args);
}
// init would be used as a pseudo-constructor in children
public function init()
{}
final private function foo()
{
echo __METHOD__;
}
}
class B extends A
{}
class C extends B
{}
$c = new C;
If what you tried to do was to execute every foo() method in the chain, then it was expected behavior. If there was a B::foo() function then that would have been executed and if it had contain a call to parent::foo() then A::foo() would have been executed too.
So, probably parent::foo() is somehow confusing. It should be read like (sorry, but I couldn't find a better example):
the_first_parent_in_the_inheritance_chain_which_has_a_foo_method::foo()
That's what you are actually interested in. Why would you want to call foo() in the context of B? The only reason I can think of is for accessing private member from B. But then, how would A know what private members B has? It can't. You cannot use in A::foo() members that A hadn't declared. Unless A is abstract and defines some abstract methods. Of course, A may declare that property as private (B cannot give an overridden member a lower visibility than that in the parent and our aim is that B should have a private one).
Then B overrides that property, making it private as we want. Now, if your code would have worked, A or C would have had access to B's private member although it shouldn't. That breaks a rule.
Is there any situation in which you want the behavior you've asked about?