为什么不能在子类中使用常量值覆盖父变量? (PHP)

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
    }
}

demo

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';
}

demo

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 />";