Search code examples
phpconstructoroverriding

Constructor overriding in PHP


According to this answer, we need the same signature for the parent and child constructors.

But I tried the following code, and it is working fine. I am finding it difficult to understand this.

<?php
class Person{
    var $name;

    function __construct( string $name){
        $this->name = $name;
    }
}
class Student extends Person{
    public int $age;

    function __construct(int $age){
        $this->age = 0;
    }
}
$ob1 = new Person("David");
$ob2 = new Student(23);

echo "$ob1->name \n $ob2->age \n";

?>

Of course, $ob2->name is empty. I am not even using parent::__construct as given in the manual. Is it because I use var $name in the base class instead of the typed variable public int $name?

Edit: I tried public int $name also, and it is working.


Solution

  • There are a couple of things.

    • we need the same signature for the parent and child constructors. Well, in case of constructors, this signature rule is exempted. See here. Quoting from the manual:

    When overriding a method, its signature must be compatible with the parent method. Otherwise, a fatal error is emitted, or, prior to PHP 8.0.0, an E_WARNING level error is generated. A signature is compatible if it respects the variance rules, makes a mandatory parameter optional, adds only optional new parameters and doesn't restrict but only relaxes the visibility. This is known as the Liskov Substitution Principle, or LSP for short. The constructor, and private methods are exempt from these signature compatibility rules, and thus won't emit a fatal error in case of a signature mismatch.

    • When you don't mention any constructor in child class, it gets inherited from parent class(unless it is declared as private in parent class).

    Snippet:

    <?php
    
    class Person{
        var $name;
    
        function __construct( string $name){
            $this->name = $name;
        }
    }
    class Student extends Person{
        public int $age;
    }
    
    $ob = new Student("James");
    
    echo $ob->name;
    

    Online Demo

    The manual on this states the same.

    Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method (if it was not declared as private).

    • In your case, you are overriding the constructor in your child class and not explicitly calling the parent class constructor. Since constructors are exempt from the LSP rule, the semantic and syntax is perfectly valid and doesn't emit any error. If you wish to initialize the name as well, you are allowed to create a new parameter for this in your child class constructor, pass in some value and then call the parent constructor to initialize values.

    Snippet:

    <?php
    
    class Person{
        var $name;
    
        function __construct(string $name){
            $this->name = $name;
        }
    }
    class Student extends Person{
        public int $age;
        
        function __construct(int $age, string $name){
            parent::__construct($name);
            $this->age = $age;
        }
    }
    
    $ob = new Student(25, "James");
    
    echo $ob->age, " " ,$ob->name;
    

    Online Demo