Passing Down Constructor Legacies from Ancestors
We’ve called the parent constructor in the last few articles without actually going into much detail about it. If the child class does not define a constructor, it inherits the parent constructor like any other method. If a child class defines a constructor of its own, the parent constructor will be overridden. To call the parent constructor, a call to parent::__construct() must be done from the child constructor.
Recap: Review the previous article and code.
https://blog.devgenius.io/php-p66-object-comparison-a2e84a8e3e13
https://github.com/dinocajic/php-youtube-tutorials/tree/master
Looking at the Lamborghini class, it’s just an empty class that extends Car. The Car class does contain a constructor.
<?php
class Car extends Vehicle
{
//...
public function __construct(int $year,
string $make,
string $model,
string $color = "",
int $fuel_type = 93,
int $hp = -1,
int $tq = -1,
string $transmission = "5 Speed Manual",
string $vehicle_type = "",
float $exterior_height = -1,
float $exterior_width = -1,
float $exterior_length = -1,
string $exterior_um = "in",
float $weight = -1,
string $weight_um = "lbs",
bool $car_on = false
)
{
$this->year = $year;
$this->make = $make;
$this->model = $model;
$this->color = $color;
$this->fuel_type = $fuel_type;
$this->hp = $hp;
$this->tq = $tq;
$this->transmission = $transmission;
$this->vehicle_type = $vehicle_type;
$this->exterior_height = $exterior_height;
$this->exterior_width = $exterior_width;
$this->exterior_length = $exterior_length;
$this->exterior_um = $exterior_um;
$this->weight = $weight;
$this->weight_um = $weight_um;
$this->car_on = $car_on;
}
//...
}
class Lamborghini extends Car {
}
We can instantiate the class and use the parent constructor without specifying a constructor inside of the Lamborghini class.
<?php
// Parent Constructor
require_once("Lamborghini.php");
$lamborghini = new Lamborghini(1999, "Lamborghini", "Diablo SV");
echo $lamborghini->get_year_make_and_model();
Calling the get_year_make_and_model() method yields 1999 Lamborghini Diablo SV. That means that the parent constructor was in fact called and it set the $year, $make, and $model properties.
What if the Lamborghini class had a constructor? The Lamborghini constructor will also accept 3 arguments: make, model, and color. We’re not going to be passing the year this time.
<?php
require_once("Car.php");
class Lamborghini extends Car {
public function __construct( $make, $model, $color ) {
$this->make = $make;
$this->model = $model;
$this->color = $color;
}
}
We can now try out some test code and see if it works.
<?php
// Parent Constructor
require_once("Lamborghini.php");
$lamborghini = new Lamborghini("Lamborghini", "Diablo SV", "Purple");
echo $lamborghini->getMake() . " " . $lamborghini->getModel() . " " . $lamborghini->getColor();
And sure enough, it does. You might think that it shouldn’t considering that we never passed the year to the parent constructor. Since we’re calling the Lamborghini constructor, the parent constructor is never called.
But what if we did want to call the parent constructor and set the year while utilizing the Lamborghini constructor?
This time we’ll modify the constructor to accept 4 arguments: $year, $make, $model, and $secret_code. Why $secret_code? Because it doesn’t exist within the Car class. That property will exist inside the Lamborghini class. This will make the code easier to follow.
public function construct($year, $make, $model, $secret_code) { }
We can set the $year, $make, and $model properties using $this keyword, or we can be fancy and utilize the parent constructor. How do we call the parent constructor from inside the child constructor?
parent::__construct()
<?php
require_once("Car.php");
class Lamborghini extends Car {
private string $secret_code;
public function __construct( $year, $make, $model, $secret_code ) {
parent::__construct($year, $make, $model);
$this->secret_code = $secret_code;
}
}
This now sets the $secret_code inside of the Lamborghini class and calls the Car constructor to set the other three properties.
Let’s add the getter/setter methods for the $secret_code property so that we can do some additional testing.
<?php
require_once("Car.php");
class Lamborghini extends Car {
private string $secret_code;
public function __construct( $year, $make, $model, $secret_code ) {
parent::__construct($year, $make, $model);
$this->secret_code = $secret_code;
}
/**
* @return string
*/
public function getSecretCode(): string
{
return $this->secret_code;
}
/**
* @param string $secret_code
*/
public function setSecretCode(string $secret_code): void
{
$this->secret_code = $secret_code;
}
}
<?php
// Parent Constructor
require_once("Lamborghini.php");
$lamborghini = new Lamborghini(1999, "Lamborghini", "Diablo SV", "0x4225sdf4");
echo $lamborghini->get_year_make_and_model() . " " . $lamborghini->getSecretCode();
Running the code gives us the result that we were looking for: 1999 Lamborghini Diablo SV 0x4225sdf4.
One last thing to note is the position of the call to the parent constructor. While other object oriented programming languages require that you call the parent constructor first, in PHP you can call it at any time within the constructor. The following code will also work.
I still prefer to call the parent constructor immediately and then execute any additional code within the child class constructor just in case PHP changes its mind in the future.
PITTING CODE TITANS AGAINST EACH OTHER
When using the comparison operator, PHP checks to see if two objects have the same attributes and values, and if they’re instances of the same class.
Passing Down Constructor Legacies from Ancestors
If the child class does not define a constructor, it inherits the parent constructor like any other method. If a child class defines a constructor of its own, the parent constructor will be overridden.
JUST A VIRTUAL DIRECTORY TRICK
Namespaces are used throughout numerous programming languages. If you’re familiar with Java, you might have heard of the term package. Similar but different.