Passing Down Code Wisdom through Generations
In Object Oriented Programming, you can inherit both properties and methods from other classes. The class that inherits is called the child class; it inherits from the parent class. Child classes are also called subclasses and parent classes are referred to as superclasses.
We’re going to be modifying our GermanShepherd class from the previous article.
https://www.dinocajic.com/php-getters-and-setters/
We’ll move quite a few properties outside of the GermanShepherd class and into a more generic Dog class. We can also modify the Car class, even though it’s an abstract enough concept, to inherit from a more generic Vehicle class. We’ll cover that in the next article.
Let’s start with the GermanShepherd class. Every GermanShepherd is a Dog and there are different dog breeds like Poodles and German Shepherds.
<?php
// Inheritance
class GermanShepherd
{
const HAS_HEART = true;
const HAS_TAIL = true;
private $eye_color;
private $dob;
private $does_shed = true;
private $kingdom = "Animalia";
private $phylum = "Chordata";
private $class = "Mammalia";
private $order = "Carnivara";
private $family = "Canidae";
private $genus = "Canis";
private $species = "Canis Lupus";
private $subspecies = "Canis Lupus Familiaris";
private $breed = "German Shepherd Dog";
private $fur_color;
public function __construct(string $eye_color,
string $dob,
string $fur_color)
{
$this->eye_color = $eye_color;
$this->dob = $dob;
$this->fur_color = $fur_color;
}
/**
* @return string
*/
public function getEyeColor(): string
{
return $this->eye_color;
}
/**
* @param string $eye_color
*/
public function setEyeColor(string $eye_color): void
{
$this->eye_color = $eye_color;
}
/**
* @return string
*/
public function getDob(): string
{
return $this->dob;
}
/**
* @param string $dob
*/
public function setDob(string $dob): void
{
$this->dob = $dob;
}
/**
* @return bool
*/
public function isDoesShed(): bool
{
return $this->does_shed;
}
/**
* @param bool $does_shed
*/
public function setDoesShed(bool $does_shed): void
{
$this->does_shed = $does_shed;
}
/**
* @return string
*/
public function getFurColor(): string
{
return $this->fur_color;
}
/**
* @param string $fur_color
*/
public function setFurColor(string $fur_color): void
{
$this->fur_color = $fur_color;
}
public function walk()
{
echo "I'm walking";
}
public function bark()
{
echo "I'm barking";
}
public function sleep(int $energy_level = 100)
{
if ($energy_level < 40) {
echo "I'm sleeping";
} else {
echo "I don't want to sleep";
}
}
public function get_scientific_classification(): array
{
return [
"kingdom" => $this->kingdom,
"phylum" => $this->phylum,
"class" => $this->class,
"order" => $this->order,
"family" => $this->family,
"genus" => $this->genus,
"species" => $this->species,
"subspecies" => $this->subspecies,
"breed" => $this->breed
];
}
public function __destruct()
{
// var_dump(
// [
// "eye_color" => $this->eye_color,
// "dob" => $this->dob,
// "does_shed" => $this->does_shed = true,
// "kingdom" => $this->kingdom = "Animalia",
// "phylum" => $this->phylum = "Chordata",
// "class" => $this->class = "Mammalia",
// "order" => $this->order = "Carnivara",
// "family" => $this->family = "Canidae",
// "genus" => $this->genus = "Canis",
// "species" => $this->species = "Canis Lupus",
// "subspecies" => $this->subspecies = "Canis Lupus Familiaris",
// "breed" => $this->breed = "German Shepherd Dog",
// "fur_color" => $this->fur_color,
// ]
// );
}
}
Starting with the constants, each Dog has a heart and a tail, so we can move that to our new Dog class.
<?php
class Dog{
const HAS_HEART = true;
const HAS_TAIL = true;
}
<?php
// Class Inheritance
class Dog {
const HAS_HEART = true;
const HAS_TAIL = true;
protected $eye_color;
protected $dob;
protected $does_shed = true;
protected $kingdom = "Animalia";
protected $phylum = "Chordata";
protected $class = "Mammalia";
protected $order = "Carnivara";
protected $family = "Canidae";
protected $genus = "Canis";
protected $species = "Canis Lupus";
protected $subspecies = "Canis Lupus Familiaris";
protected $breed;
protected $fur_color;
}
If we moved the properties with the private visibility modifier to the Dog class, our GermanShepherd class would not have access to those properties when inheriting. To make sure that our GermanShepherd class inherits those properties, we have to make the modification from private to protected.
We’ve talked about inheritance as a concept so far, but how can the GermanShepherd class actually inherit properties from the Dog class. With the help of the extends keyword.
class ChildClass extends ParentClass
You can only extend (inherit) one class. Our Dog class can also inherit from another class, like Animal.
<?php
// Class Inheritance
class Dog {
const HAS_HEART = true;
const HAS_TAIL = true;
protected $eye_color;
protected $dob;
protected $does_shed = true;
protected $kingdom = "Animalia";
protected $phylum = "Chordata";
protected $class = "Mammalia";
protected $order = "Carnivara";
protected $family = "Canidae";
protected $genus = "Canis";
protected $species = "Canis Lupus";
protected $subspecies = "Canis Lupus Familiaris";
protected $breed;
protected $fur_color;
}
class GermanShepherd extends Dog
{
public function __construct(string $eye_color,
string $dob,
string $fur_color)
{
$this->eye_color = $eye_color;
$this->dob = $dob;
$this->fur_color = $fur_color;
}
//...
}
<?php
$gs_dog = new GermanShepherd("Green", "Oct 10, 2015", "Brown");
echo "Eye Color: " . $gs_dog->getEyeColor();
The result that you should receive is Green. Even though the eye_color property does not exist within the child class, it does exist in the parent class and is being inherited. The concept can be confusing for beginners, especially when you see that the getEyeColor() method is returning $this->eye_color. The keyword $this is referencing the object it’s in, i.e. GermanShepherd, and the eye_color property does not exist there any more. And yet, the eye color is returned properly. To visualize it better, think of the properties as being copied from the parent class to the child class; however, when you’re looking through the code and can’t find the property, you’ll start making your way up the inheritance tree. You’ll find the eye_color property in the Dog parent class.
As mentioned earlier, we can move properties and methods to our parent class. Taking a look at our GermanShepherd class, none of the methods are unique to GermanShepherds, so we can move them all to our Dog class.
<?php
// Class Inheritance
class Dog {
const HAS_HEART = true;
const HAS_TAIL = true;
protected $eye_color;
protected $dob;
protected $does_shed = true;
protected $kingdom = "Animalia";
protected $phylum = "Chordata";
protected $class = "Mammalia";
protected $order = "Carnivara";
protected $family = "Canidae";
protected $genus = "Canis";
protected $species = "Canis Lupus";
protected $subspecies = "Canis Lupus Familiaris";
protected $breed;
protected $fur_color;
/**
* @return string
*/
public function getEyeColor(): string
{
return $this->eye_color;
}
/**
* @param string $eye_color
*/
public function setEyeColor(string $eye_color): void
{
$this->eye_color = $eye_color;
}
/**
* @return string
*/
public function getDob(): string
{
return $this->dob;
}
/**
* @param string $dob
*/
public function setDob(string $dob): void
{
$this->dob = $dob;
}
/**
* @return bool
*/
public function isDoesShed(): bool
{
return $this->does_shed;
}
/**
* @param bool $does_shed
*/
public function setDoesShed(bool $does_shed): void
{
$this->does_shed = $does_shed;
}
/**
* @return string
*/
public function getFurColor(): string
{
return $this->fur_color;
}
/**
* @param string $fur_color
*/
public function setFurColor(string $fur_color): void
{
$this->fur_color = $fur_color;
}
public function get_scientific_classification(): array
{
return [
"kingdom" => $this->kingdom,
"phylum" => $this->phylum,
"class" => $this->class,
"order" => $this->order,
"family" => $this->family,
"genus" => $this->genus,
"species" => $this->species,
"subspecies" => $this->subspecies,
"breed" => $this->breed
];
}
public function walk()
{
echo "I'm walking";
}
public function bark()
{
echo "I'm barking";
}
public function sleep(int $energy_level = 100)
{
if ($energy_level < 40) {
echo "I'm sleeping";
} else {
echo "I don't want to sleep";
}
}
}
class GermanShepherd extends Dog
{
public function __construct(string $eye_color,
string $dob,
string $fur_color)
{
$this->eye_color = $eye_color;
$this->dob = $dob;
$this->fur_color = $fur_color;
}
}
Looks pretty clean. You may be tempted to change all of your public methods to protected methods. Your child class will have access to the methods, however, once the object is instantiated, no methods will be visible.
Let’s change the getEyeColor() visibility modifier from public to protected and run our code again. You’ll see a Fatal Error displayed.
You may be asking yourself what the point of even creating a GermanShepherd object is if we’re just moving everything to the Dog class. Aside from it being the right thing to do, you can override your methods inside of the GermanShepherd class and make them GermanShepherd specific. For example, there is a default bark() method that echos “I’m barking.” We can override that method inside of our GermanShepherd class so that the GermanShepherd can say “Loud Barking.”
How do you override a method? You create a method inside of the child class (GermanShepherd) and name it the method that you’re trying to override. You do not delete the bark method from the Dog class.
<?php
// Class Inheritance
class Dog {
//...
protected $eye_color;
//...
public function bark()
{
echo "I'm barking";
}
//...
}
class GermanShepherd extends Dog
{
public function __construct(string $eye_color,
string $dob,
string $fur_color)
{
$this->eye_color = $eye_color;
$this->dob = $dob;
$this->fur_color = $fur_color;
}
public function bark() {
echo "Loud Barking";
}
//...
}
$gs_dog = new GermanShepherd("Green", "Oct 10, 2015", "Brown");
echo "Eye Color: " . $gs_dog->getEyeColor() . "<br>";
echo $gs_dog->bark() . "<br>";
Calling the bark() method outputs Loud Barking since the method was successfully overridden. When we call the bark() method, PHP will go into the GermanShepherd object and start looking for the bark() method. If it finds it, great. If it doesn’t, it starts looking up the inheritance tree.
There are still a couple of more concepts to learn when it comes to inheritance, but we’ll cover that in the next article.
Continue your learning with these articles
SAFEGUARDING AND SCULPTING WITH GETTERS AND SETTERS
PHP – P52: GETTERS AND SETTERS
If we wanted to access those properties or modify them in their current state, we wouldn’t be able to. That’s where getters and setters, or accessors and mutators, come into play.
Passing Down Code Wisdom through Generations
Who would have guessed that PHP supports inheritance? Everyone using PHP since Object Oriented Programming became a thing, that’s who.
TRACING THE LINEAGE OF FUNCTIONALITY IN INHERITANCE CHAINS
In the last article I mentioned briefly that you can’t extend multiple classes at once. But the parent class can itself be a child class and extend a class of its own.