I have a class first where $name
is set to 'bob'. In the child class, I set $name
to 'Karen' but it doesn't work.
In my echo statements, the 1st one says "bob" instead of 'Karen'. The second one, using a child class method, works though.
Why is this behavior?
class First {
public $name;
public function __construct() {
$this->name = 'bob';
}
}
class Third extends First {
public $name = 'Karen';
public function set_name ($name) {
$this->name = $name;
}
}
$instance_of_third = new Third;
$third_name = $instance_of_third->name;
echo "<br />We're looking for Karen: $third_name<br />";
// $third_name here is 'bob' from parent class
$instance_of_third->set_name("Karen");
$third_name = $instance_of_third->name;
// $third_name here is 'Karen' only after using set_name()
echo "<br />We're looking for Karen: $third_name<br />";
EDIT: I added 2 lines showing what the output was exactly.
Even though $name
is explicitly set to 'Karen' in child class, it shows as 'bob' unless the set_name()
function is used to change it.
Because your Third
does not have it's own constructor, it will inherit the constructor from First
. Inheritance creates an behaves-as relationship between supertype and subtype.
So when you create a new instance of Third
, the instance will have a $name
property of 'Karen', but then the inherited constructor will get called. And that sets the name to Bob. If you don't want that behavior in the subtype, you have to add an empty constructor to Third
, e.g.
class Third extends First
{
public function __construct()
{
// prevents parent First::__construct
}
}
An alternative would be to remove the ctor (or at least not set $name
in it) and preset the $name
property in the parent to Bob. Then your initial idea would work, e.g.
class First
{
public $name = 'Bob';
}
class Third extends First
{
public $name = 'Karen';
}
Please check the chapters on Inheritance and Visibility in the PHP Manual:
When you create a object of class, then constructor is called.
So constructor of parent class is over writing the value of $name in your case.
Because the constructor is called after fields are initialized , so it overrides your $name field.
The interpreter most likely reads from top to bottom, just like us.
In the first example, you set the public variable to Karen, however since the child class inherits the constructor of the first class, "Bob" will be set.
The constructor overrides the default value. (Generally because it's called after the default value instantiation), a more robust way would be something like so:
class First {
public $name;
public function __construct($name) {
$this->name = $name;
}
}
Then call it by:
$first_instance = new First("Bob");
It will also extend to the Third
class.
Try declaring the $name as static. and access it via Third::$name for example.
class First {
public static $name;
public function __construct() {
self::$name = 'bob';
}
// edit late static binding
public function getName() {
return static::$name;
}
}
class Third extends First {
public static $name = 'karen';
}
$instance_of_third = new Third();
//$third_name = $instance_of_third::$name;
$third_name = $instance_of_third->getName();
echo "<br />We're looking for Karen: $third_name<br />";