If I make a mother class, with some private variable declared, and some function that uses that private value, and then extend it into a daughter class, redeclaring that private variable, the mentioned function will still use the private variable of the mother class, somehow. This will not happen if the aforementioned variable is protected or public, only if it is private.
See this example:
<?php
class MotherClass {
private $variablePrivate = 'original value';
protected $variableProtected = 'original value';
public $variablePublic = 'original value';
public function someFunction() {
echo '$this->variablePrivate: ' . $this->variablePrivate . '<br>';
echo '$this->variableProtected: ' . $this->variableProtected . '<br>';
echo '$this->variablePublic: ' . $this->variablePublic . '<br>';
}
}
class DaughterClass extends MotherClass {
private $variablePrivate = 'redeclared value';
protected $variableProtected = 'redeclared value';
public $variablePublic = 'redeclared value';
}
echo 'someFunction in MotherClass: <br>';
$mother = new MotherClass();
$mother->someFunction();
echo 'someFunction in DaughterClass: <br>';
$daughter = new DaughterClass();
$daughter->someFunction();
The output will be:
someFunction in MotherClass:
$this->variablePrivate: original value
$this->variableProtected: original value
$this->variablePublic: original value
someFunction in DaughterClass:
$this->variablePrivate: original value
$this->variableProtected: redeclared value
$this->variablePublic: redeclared value
This behaviour is strange for me, I did not expect it and it took me a whole day to discover this was the problem in something I was programming. It feels, for me, somewhat counterintuitive and I do not see the logic behind it, specially because I would think that when I create an object of the daughter class I supposedly do not have access to the private variables of the mother class; and, also, as I redeclared the variable, I am expecting the object to behave according to the variable in the daughter class and not in the mother class; and, finally, I do not see how, if I am making a daught class object, somehow it has mother class characteristics that I supposedly overwrote and that I also cannot actually access normally.
It seems that it has to do with the fact that the function has not been overwritten and somehow that makes it attached to the private variables in the mother class, which then seem to keep existing even though they are impossible to access. However, why is this not happening with the protected variables?
I would like to know the reason behind this, as it is making me see I did not understand the meaning of "private", "protected" and "public" as well as I thought. Thank you very much.
CodePudding user response:
The reason is just how inheritance works.
In memory an instance of MotherClass looks like this:
┌───────────────────┐
│ variablePrivate │ ->original value
├───────────────────┤
│ variableProtected │ ->original value
├───────────────────┤
│ variablePublic │ ->original value
└───────────────────┘
And an instance of DaughterClass looks like this:
┌─────────────────────┐
│┌───────────────────┐│
││ variablePrivate ││ ->original value
│├───────────────────┤│
││ variableProtected ││ ->redeclared value
│├───────────────────┤│
││ variablePublic ││ ->redeclared value
│└───────────────────┘│
├─────────────────────┤
│ variablePrivate │ ->redeclared value
└─────────────────────┘
As you can see the structure of the parent class is inherited first. Protected and public properties are overridable, so their values are overridden. But private properties are not overridable, so a new space is needed to store the new variablePrivate
property declared in the DaughterClass.
In this case, you can think that the keywords public, private and protected are used to mark which properties can be overridden and which can only be appended. (Of course, they have other effects when you try to access them)
You can also verify this with var_dump
in PHP:
var_dump(new DaughterClass());
# object(DaughterClass)#5 (4) {
# ["variablePrivate":"DaughterClass":private]=>
# string(16) "redeclared value"
# ["variableProtected":protected]=>
# string(16) "redeclared value"
# ["variablePublic"]=>
# string(16) "redeclared value"
# ["variablePrivate":"MotherClass":private]=>
# string(14) "original value"
# }