Ok let me try [Again]
Basically both methods exist side by side.
Private by design means that this thing (method or property) is not visible or accessible or writable by anything besides the class it was defined in. So children cannot use it in any way nor modify it in any way. This is the behaviour of private.
The why (the reason) behind the concept, is to guarantee a specific functionality (or value, of properties) no matter how the class is extended. This is good because when designing the Parent class we may not know how it will be used by any extending classes, and there may be functionality that is critical and should not be changed. This gives us a way to guarantee that in our code without knowing the implementation of the children.
One reason they can exist side by side, is inside of the child class when you call $this->foo()
there is no ambiguity about which foo is being called as only the public version C::foo()
visible to class C
(the child) class.
class A {
private function foo() {
echo "A!";
}
public function parentTest() { //formerly A::test()
//if we used C::foo() from here Overriding A::foo().
//having a concept of private would lose all meaning
//because we would be allowing the child to modify
// the functionality of private A:foo()
$this->foo();
}
}
class C extends A {
public function foo() {
echo 'C!';
}
public function childTest() {
//A::foo() cannot be used from here
//so PHP knows to use C::foo()
$this->foo();
}
}
In short there is only one Foo available to the child class C::foo()
, so there is no way it can be confused with the private version A::foo()
by PHP. In this way both methods can exist without the child overriding the parents method.
Don't let me confuse you more here, because in some ways the childs method does override the parents. We can see this if we call $obj->foo()
from the global space. If we don't define foo in the child C
then we get an error. But if we do define a public one in C
it is used. Another thing that shows that it does overwrite (in some ways) is if we set the parent's copy A::foo()
to be final. In this case if we try to define C::foo()
we get an error as we would expect.
But (here is the important part), neither of these affect the functionality of the private stuff as far as the parent is concerned and so they do not violate the private principle.
Now for the parents call to its own private method.
This is where most people get confused and you asked:
When calling what is for all intents and purposes C::test, why does it prefer the private A::foo over the public C::foo
It doesn't because you are calling the private method A::foo()
from another method A::test()
in the same class class A
where the private one was defined.
If it preferred the child's method over it's own, then then there would be no point in having a private visibility because we would have just violated it by allowing the child to modify the method. In other words we would be using the child's functionality instead of that marked by private.
Really it's the only sensible way that it could work. On the same token if you overwrite A::test()
with the same exact code but in class C
or C::test()
the same call would now access the public method because that is the only one visible inside of class C
where the new call came from.
Summery
This is the only logical way for private to work, if the class defining the private method was allowed to use a child definition of the method it would completely nullify the reason for having private in the first place, and I wouldn't be trying to explain it. Because it would then simply be what we call protected
, which we already have.
UPDATE
So, sometimes it calls method from its own, sometimes it calls the one from parent's.
Not entirely true. Calls to the private method (foo) coming from a method defined only in the parent(A) will always access the parent(A)s private method (foo). Calls coming from a method defined in the child(C) will access either the Child(C)s method (foo), or throw an error when trying to access the Parent(A)s private method(foo).
Case1: if A:foo()
is called from within A
(no matter the instance) it will call it's private method regardless if there is a method from the child class that overrides foo
. In this context is called from within A
means called from any method defined within A and not overwritten in B. The call to foo
comes from class A
.
class A {
private function foo() {
echo "A!\n";
}
public function parentTest() {
//parentTest Is not overwritten in C
//so when C::parentTest() is called that call goes here
//inside the A class where foo is defined.
$this->foo();
}
}
class C extends A {
private function foo() {
echo "C!\n";
}
}
//this is called from A
//because there is no method named parentTest outside of A
(new C)->parentTest(); //A!
See the mistake your making is (new C)->parentTest();
does not physically exist in C. It's included in C by inheritance and its scope is still within the parent class when it comes to private access, because both foo
and parentTest
exist only in class A
.
Therefore it has access to class A's private methods, because it is class A, even though the object is an instance of C.
You could remove class C altogether and the behavior would be the same.
class A {
private function foo() {
echo "A!\n";
}
public function parentTest() {
$this->foo();
}
}
//the path the code follows to execute is identical to the previous example.
(new A)->parentTest(); //A!
Case2: if A:foo()
is called directly from a child of A
and is not overwritten, you get an access to private method error. The call to foo
comes from class C
.
class A {
private function foo() {
echo "A!\n";
}
}
class C extends A {
public function childTest() {
//A::foo() is not visable, and no C::foo() exists
$this->foo();
}
}
//this comes direct from Class C,
//which cannot directly access Class A's private scope
(new C)->childTest(); //Error: Call to private method A::foo()
Case3: if A:foo()
is called from a child of A
and is overridden it will call the Child's method. is called from a child of A
means any method defined within C
regardless if it overrides a (public/protected) method of A
. The call to foo
comes from class C
.
class A {
private function foo() {
echo "A!\n";
}
}
class C extends A {
public function foo() {
echo "C!\n";
}
public function test() {
//C::test() calls it's foo function
//because the call comes from here not inside the A class
$this->foo();
}
}
//this is called from C, the method childTest is defined in C
(new C)->childTest(); //C!
This is true regardless of there being a public method of the same name (test) in the parent.
class A {
private function foo() {
echo "A!\n";
}
public function test() {
//this is a public method that is overwritten as normal by C
//when this is called the, C::test() is called as normal
//because of inheritance
$this->foo();
}
}
class C extends A {
public function foo() {
echo "C!\n";
}
public function test() {
//C::test() calls it's foo function
//again the call comes from here not inside the A class
$this->foo();
}
}
//This is called from C, because test is overwritten in C and is visible (public)
(new C)->test(); //C!
As I showed in the first example in this Update (except its backwards), you could remove the A class entirely and the way the code executes would not change:
class C{
private function foo() {
echo "C!\n";
}
public function test() {
$this->foo();
}
}
//the code executes along the same path even without A
(new C)->test(); //C!
In short: inheritance is not a simple Copy And Paste operation. The code from A is not copied and Pasted into C. Each class still exists, its just that A shares anything that is accessible with C (protected, public)
I hope that helps, that's the best I can do.