6

I saw this in the PHP OOP manual http://www.php.net/manual/en/language.oop5.visibility.php and I can't get my head around why the output is not: Foo::testPrivate Foo::testPublic

class Bar 
{
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }

    public function testPublic() {
        echo "Bar::testPublic\n";
    }

    private function testPrivate() {
        echo "Bar::testPrivate\n";
    }
}

class Foo extends Bar 
{
    public function testPublic() {
        echo "Foo::testPublic\n";
    }

    private function testPrivate() {
        echo "Foo::testPrivate\n";
    }
}

$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate 
                // Foo::testPublic
camden_kid
  • 12,591
  • 11
  • 52
  • 88
  • 1
    Hint: you'll get the desired output if you change `private` to `protected`. Read about both access modifiers. –  Feb 24 '12 at 15:59
  • check this thread out. The first answer helps me a lot. http://stackoverflow.com/questions/12794290/php-manual-visibilty-example-confused – Sam Mar 06 '13 at 05:31
  • Check this thread out. The first answer helps me a lot. http://stackoverflow.com/questions/12794290/php-manual-visibilty-example-confused – Sam Mar 06 '13 at 05:32

3 Answers3

11

It's all about the visibility of the variables / methods.

You'll notice that in the Bar class, the method testPrivate() is private. That means that ONLY itself can access that method. No children.

So when Foo extends Bar, and then asks to run the test() method, it does two things:

  1. It overrides the testPublic() method because it's public, and Foo has the right to override it with it's own version.
  2. It calls test() on Bar (since test() only exists on Bar()).

testPrivate() is not overridden, and is part of the class that holds test(). Therefore, Bar::testPrivate is printed.
testPublic() is overridden, and is part of the inheriting class. Therefore, Foo::testPublic is printed.

rockerest
  • 10,412
  • 3
  • 37
  • 67
  • Right. Thanks @rockerest for a clean explanation. – camden_kid Feb 24 '12 at 16:06
  • But if you `echo $this->testPrivate()` from within `Foo:testPublic`, it will echo `Foo::testPrivate`. So it looks like it was overridden when called from this context. Now I'm confused! – bfavaretto Feb 24 '12 at 16:08
  • @bfavaretto Remember, `$this` is a dynamic variable that references the class that the code is in. So while it's processing `test()`, `$this` references the temporary copy of the `Bar` class (giving you `Bar::testPrivate()`), but `$this` inside the `Foo` class will reference the `Foo` class (giving you `Foo::testPrivate()`). – rockerest Feb 24 '12 at 16:09
  • @rockerest I did some further research, and still find it confusing. I undertand it works as you say, but could you recommend an article or docs where I can further understand how inheritance works internally in PHP? Using reflection, for example, I can't find any trace of the temporary copy of `Bar` you mentioned -- `get_class($this)` always output `Foo`. – bfavaretto Feb 24 '12 at 16:34
  • @bfavaretto Where is your `get_class()` call? Inside `Bar`? Or in `Foo`? It might be best to ask your own question, with the exact code you have and what you are expecting to happen, and what actually happens. On the other hand, there might already be a question about this somewhere on SO. – rockerest Feb 24 '12 at 16:48
  • @rockerest Agreed, created a new [question](http://stackoverflow.com/questions/9436352/behavior-of-this-on-inherited-methods). Thanks. – bfavaretto Feb 24 '12 at 18:53
1

In some cases, it is easy to notice that you want a private method on the Bar class, but you also wants the Foo class to access it.
But wait, it is public or private?
Here comes the protected modifier.
When a method is private, only the class itself can call the method.
When a method is public, everyone can call it, like a free party.
When a method is protected, the class itself can call it and also whoever inhered this method (children) will be able to call it as a method of their own.

Marco Aurélio Deleu
  • 4,279
  • 4
  • 35
  • 63
-1

I posted the same question few days ago... because this behaviour wasnt logical for me either. $this is always referred to the current object which it is used in. In my opinion example like this should throw an error or warning or something. Because in the above example you are actually accessing private members :SSS WHICH SUPPOSED TO BE INACCESSIBLE!

jrj
  • 1
  • 2