Namal
Namal

Reputation: 2071

php manual visibility example confused

I have confused from an example in php manual. It's about visibility. Here is the example.

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();  
?>

http://www.php.net/manual/en/language.oop5.visibility.php

This example outputs

Bar::testPrivate 
Foo::testPublic

Please can you explain how this happen?

why both testPublic() are not called?

I put a var_dump($this) in Bar class construct. It prints object(Foo)[1]. The thing I know is private properties can be called withing same class.

Then how "Bar::testPrivate" is called?

Upvotes: 6

Views: 184

Answers (6)

Ja͢ck
Ja͢ck

Reputation: 173572

Then how "Bar::testPrivate" is called?

When you call $myFoo->test(), it runs the code in the context of Bar because the Foo class didn't override it.

Inside Bar::test(), when $this->testPrivate() gets called, the interpreter will look at Foo first but that method is private (and private methods from descendent classes can't be called from Bar), so it goes one level up until it can find a suitable method; in this case that would be Bar::testPrivate().

In contrast, when $this->testPublic() gets called, the interpreter immediately finds a suitable method in Foo and runs it.

Edit

why both testPublic() are not called?

Only one method gets called when you run $this->testPublic(), the furthest one (in terms of distance to the base class).

If Foo::testPublic() needs to also execute the parent's implementation, you should write parent::testPublic() inside that method.

Upvotes: 6

bhovhannes
bhovhannes

Reputation: 5679

I guess the comment of user 'omega at 2093 dot es' (http://www.php.net/manual/en/language.oop5.visibility.php#109324) is describing the same thing. There is said: "Methods defined in a parent class can NOT access private methods defined in a class which inherits from them. They can access protected, though."

In your case $this object in Bar::test() method is of Foo type (your var_dump proves that). Because Foo::testPrivate() method is private, it cannot be accessed from parent class Bar, and the only method, which can be accessed remains Bar::testPrivate() (try to comment definition, and you'll get fatal error). That is why first output is Bar::testPrivate.

The line $this->testPublic(); calls Foo::testPublic() method, because $this is of Foo type and method is defined as public.

To be short, private methods are accessible only from the class, where they are defined. They cannot be accessed neither from child nor from parent classes.

To make the method accessible from child or parent classes make it protected. For example, if you'll make testPrivate() method protected in both classes, it will print Foo::testPrivate Foo::testPublic.

Upvotes: 1

Terry Harvey
Terry Harvey

Reputation: 9444

Private doesn't mean you can't call it. It means that you can only call it from the current class. Public means that you can call it from any class.

To call Bar::testPrivate, try this:

$Bar->testPublic();

or

parent::testPublic();

BUT, you can't call $Bar->testPrivate() because the method is private.

Upvotes: 1

FrediWeber
FrediWeber

Reputation: 1099

The class Foo extends the class Bar. Then the function test is called wich is defined in Bar. In this function are two calls. One to the public and one to the private function in the class Bar.

Upvotes: 0

Karel Frajták
Karel Frajták

Reputation: 4489

You call

$myFoo->test();

See function test:

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

When this is called on an instance of a Bar class (including inherited classes) it invokes testPrivate and testPublic.

These methods are overridden in class Foo, that means the methods of Foo are used. You can always call method of a base class:

// in Foo
public function testPublic() {
    parent::testPublic();
    echo "Foo::testPublic\n";
}    

Bar::testPrivate is called because it is private and not overridden by Foo::testPrivate.

See more here or here.

Upvotes: 1

hjpotter92
hjpotter92

Reputation: 80639

Your function lies in the Barclass and you are using the magic $this pointer to call the member functions.

Try moving the function test() to Foo class, and see what happens. The output shall be:

Foo::testPrivate
Foo::testPublic

In your example, the private function of Bar was called because it was applicable only to that class. The class Foo does not have a test function in it, and hence the test function from Bar class has no access to call them.

Then, class Foo's public function was called instead of Bar's because of function overloading.

Both the classes have a function of that name, so the child class's function has importance.

Upvotes: 2

Related Questions