Override
Let's take out this dummy code and get to the real stuff. Our database
is created via this init_db
script which you can execute from the
command line whenever the mood strikes to make sure that your database is
setup correctly. DING!
This creates a table with a team
column. In here we can see that the first
two team columns are team rebel
and the second two are team empire
. Since
these two ships work differently, inside of our ShipLoader
where we take that
data and turn it into ship objects, I want to create ship objects for the empire
and the rebels.
So let's do that, if ($shipData['team'] == 'rebel')
which is the key inside the
database. Then we'll have $ship = new RebelShip($shipData['name']);
. Else, we'll
throw in our normal ship line, which represents the Empire ship:
// ... lines 1 - 2 | |
class ShipLoader | |
{ | |
// ... lines 5 - 44 | |
private function createShipFromData(array $shipData) | |
{ | |
if ($shipData['team'] == 'rebel') { | |
$ship = new RebelShip($shipData['name']); | |
} else { | |
$ship = new Ship($shipData['name']); | |
} | |
// ... lines 52 - 57 | |
return $ship; | |
} | |
// ... lines 60 - 76 | |
} | |
// ... lines 78 - 79 |
Ok, this doesn't have anything to do with Object Oriented coding, it's just a nice example of a use case for multiple classes. We have a database table, and you can create different objects from that table. This is nice because we'll be able to have these two objects behave differently.
Overriding Class Methods
So far RebelShip
and Ship
have all the same stuff except for the one extra method
I have on RebelShip
that I'm not using.
If we go back and refresh, everything still works perfectly! Now, technically I'm fairly
certain that two of these are RebelShip
objects and two are Ship
objects but we can't
really tell right now. Clearly we need to add identifiers so we know who to cheer on.
To do this, start by adding public function getType()
to our Ship
and return a description,
like 'Empire':
// ... lines 1 - 2 | |
class Ship | |
{ | |
// ... lines 5 - 134 | |
public function getType() | |
{ | |
return 'Empire'; | |
} | |
} |
Since we added that to Ship
, we can call getType
on both Ship
and
RebelShip
.
Back in index.php
towards the bottom add a new column for this called Type
and
echo $ship->getType();
:
// ... lines 1 - 57 | |
<table class="table table-hover"> | |
// ... line 59 | |
<thead> | |
<tr> | |
// ... lines 62 - 65 | |
<th>Type</th> | |
// ... line 67 | |
</tr> | |
</thead> | |
<tbody> | |
<?php foreach ($ships as $ship): ?> | |
<tr> | |
// ... lines 73 - 76 | |
<td><?php echo $ship->getType(); ?></td> | |
// ... lines 78 - 84 | |
</tr> | |
<?php endforeach; ?> | |
</tbody> | |
</table> | |
// ... lines 89 - 123 |
Back to the browser and refresh. Everything has joined to fight for the Empire! Which makes sense. Both ship classes use this same method.
Time for the next really powerful thing with inheritance. In addition to adding methods
to a sub class like RebelShip
you can override methods. Copy the getType
from Ship
and paste it into RebelShip
and change what it returns to 'Rebel':
// ... lines 1 - 2 | |
class RebelShip extends Ship | |
{ | |
// ... lines 5 - 12 | |
public function getType() | |
{ | |
return 'Rebel'; | |
} | |
// ... lines 17 - 21 | |
} |
RebelShip
copies the entire blue print of Ship
but it can replace any of those
pieces. When we refresh now, we have two 'Rebel' ships in addition to our two 'Empire' ships.
Excellent!
Overridden Methods are not Called
A key part of this is that the parent getType
class is never called for all rebel ship
objects it is completely replaced. If I echo 'Parent Function' inside of getType
in the
Ship
class and refresh, we see our ugly text echoing for the Empire ships and not the Rebel
ships. This is thanks to our parent function not being called in RebelShip
.
On to more methods, another one on Ship
is isFunctional
which we setup to have a 30%
chance of a ship being broken, which is what our cute cloud here indicates:
// ... lines 1 - 2 | |
class Ship | |
{ | |
// ... lines 5 - 16 | |
public function __construct($name) | |
{ | |
// ... lines 19 - 20 | |
$this->underRepair = mt_rand(1, 100) < 30; | |
} | |
public function isFunctional() | |
{ | |
return !$this->underRepair; | |
} | |
// ... lines 28 - 138 | |
} |
But, we all know that the Rebels are really scrappy and they don't have the luxury of letting their ships get broken. Even if they are kinda broken they still fly and make it work. Which is just one more reason why the rebels are awesome.
So I need to set this up so the Rebel ships are never showing as broken which we can do
really easily by overriding isFunctional
inside of RebelShip
. Let's update this to
return true;
which will never show a rebel ship as broken:
// ... lines 1 - 2 | |
class RebelShip extends Ship | |
{ | |
// ... lines 5 - 17 | |
public function isFunctional() | |
// ... line 19 | |
return true; | |
} | |
} |
When we refresh now the Rebel ships always have sunshine, and the Empire ships sometimes have adorable clouds.
By having two classes we are starting to shape the different behaviors and properties of each, while still keeping most things in common and not duplicated.
( ! ) Warning: require(Cache.php): failed to open stream: No such file or directory in index.php on line 3
Call Stack
for the first challenge of this video