4

I am reading the php manual about the LSB feature, I understand how it works in the static context, but I don't quite understand it in the non-static context. The example in the manual is this:

<?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
?>

The output is this:

success!
success!
success!


Fatal error:  Call to private method C::foo() from context 'A' in /tmp/test.php on line 9

I do not understand for class B, how a private method in A could be inherited to B? Can anyone walk me through what is going on here? Many thanks!

Michael
  • 2,075
  • 7
  • 32
  • 46
  • 3
    Just a general note: You probably shouldn't be using `::` to call non-static properties or methods. – Kevin Ji Apr 08 '12 at 04:59
  • 1
    @mc10 - `static::` is how you invoke [late static binding](http://php.net/manual/en/language.oop5.late-static-bindings.php) in PHP 5.3. But I agree you should reserve it for static members. – David Harkness Apr 08 '12 at 05:13
  • hi @Kevin Ji excellent, self:: should also be used only for static properties and static methods, correct? + 1, thanks in advance –  Jan 22 '23 at 01:36

1 Answers1

3

The use of late static binding only changes the method that gets chosen for the call. Once the method is chosen, visibility rules are applied to determine whether or not it may be called.

For B, A::test finds and calls A::foo. The comment in B isn't correct--foo isn't copied to B. Since it's private, it is only callable from other methods in A such as A::test.

C fails because the late static binding mechanism locates the new private method C::foo, but A's methods don't have access to it.

I recommended that you reserve late static binding for static fields and methods to avoid confusion.

David Harkness
  • 35,992
  • 10
  • 112
  • 134
  • Thanks. But I don't get it why foo() is inherited by B since it is private. Do you mean that when $b->test() is executed, $b here is actually treated as object of class A, or should be? – Michael Apr 08 '12 at 06:41
  • 4
    @Michael - Technically `A::foo` isn't even inherited since it's private. The key is that only methods of `A` can call it. – David Harkness Apr 08 '12 at 08:39
  • 1
    Exactly, you can't call a private method in a child from the parent like that. – BenOfTheNorth Apr 08 '12 at 08:47
  • 1
    OK, so this is my interpretation. When C is instantiated, it got no test() in itself, but found upstream in the parent which is A, so the context of "$c->test()" is actually A. Hence, $this->foo() resolves to the foo() in A, but C::foo() results in error since the method is overwritten in C. Is that right? – Michael Apr 08 '12 at 10:46
  • 1
    @Michael - Private methods cannot be overridden because technically they are not inherited. They are local to the class that declares them and invisible externally. The context of `$c->test()` is the class `C`. This is why LSB looks in `C` for a method named `foo`. LSB bypasses inheritance which doesn't apply to static and private methods. – David Harkness Apr 08 '12 at 18:45
  • 1
    @DavidHarkness, if the calling context is class C, why does the fatal error say "call to private C::foo() from context A"? foo() in C is private, so class A does not have access to it. – Michael Apr 09 '12 at 00:40
  • @Michael - This is where LSB muddles the water. In terms of *locating* the method (`A::foo` vs. `C::foo`), the calling context is `C`. But when *calling* the method, the calling context is always the location of the method making the call, `A` in this case. – David Harkness Apr 09 '12 at 03:54
  • Hi @David Harkness, excellent response +1, `I recommended that you reserve late static binding for static fields and methods to avoid confusion`. Have a doubt, it is also better to use self ONLY for static properties and static methods, right? thanks in advance –  Jan 22 '23 at 01:32