Buy

Welcome back for Episode 3 of our Object Oriented Series! We're ready to get serious about Inheritance. And not just from that rich uncle of yours. I'm talking about extending classes, abstract classes, interfaces, stuff that really makes object oriented code nice but doesn't always look easy at first.

Don't worry this will all start to feel really familiar in a suprisingly small amount of time!

I'm already in the project that we've been working on through this series. If you don't have this yet download the code and use what's in the 'start' directory.

In my terminal I've also started the built in web server with php -S localhost:8000. Be careful to do that in the start directory of the project.

Creating a new RebelShip class

So far in our project we have just this one lonely ship object. We query things from the database and we load this ship. But exciting things are happening and we have a new problem! We want to model two different types of ships. We have normal ships from the empire and since those are kinda evil we also now want rebel ships to set them straight!

In the browser you can see we have two rebel ships in here coming from the database.

I would really like rebel ships to fundamentally work differently. For example, they break down less often and have higher jedi powers. Let me show you what I mean.

Create a new PHP class called RebelShip:

7 lines lib/Model/RebelShip.php
... lines 1 - 2
class RebelShip
{
}

Easy! Since rebel ships aren't exactly like boring old Empire ships let's create a new class or blueprint that models how these work.

Head on into bootstrap.php and require the RebelShip file there:

15 lines bootstrap.php
... lines 1 - 10
require_once __DIR__.'/lib/Model/RebelShip.php';
... lines 12 - 15

We don't have an autoloader yet so we still have to worry about these require statements.

Rebel ships are different than Empire ones but they do share about 99% of their attributes. For example, they both have wings, fire power, defense power, etc.

Class Inheritance with extends

My first instinct should be to go into Ship.php and copy all of the contents and paste that into RebelShip.php since most of it will probably apply. But I shouldn't need to remind you that this would be a silly amount of duplication in our code which would make everyone sad. This is our chance to let classes help us not be sad by using the extends keyword.

By saying class RebelShip extends Ship everything that's in the Ship class is automatically inside of RebelShip:

7 lines lib/Model/RebelShip.php
... lines 1 - 2
class RebelShip extends Ship
{
}

It's as if all the properties and methods of Ship are now a part of the RebelShip blueprint.

In index.php we can say $rebelShip = new RebelShip('My new rebel ship'); and we can just add this to the $ships array:

124 lines index.php
... lines 1 - 6
$ships = $shipLoader->getShips();
$rebelShip = new RebelShip('My new rebel ship');
$ships[] = $rebelShip;
... lines 11 - 124

Remember, down here we iterate over the ships and call things like getName(), getWeaponPower() and getJediFactor() which don't actually live inside of RebelShip:

124 lines index.php
... lines 1 - 72
<?php foreach ($ships as $ship): ?>
<tr>
<td><?php echo $ship->getName(); ?></td>
<td><?php echo $ship->getWeaponPower(); ?></td>
... lines 77 - 85
</tr>
<?php endforeach; ?>
... lines 88 - 124

But when we refresh, it works perfectly!

Lesson number 1: when you have one class that extends another, it inherits (you'll hear that word a lot) all of the stuff inside that parent class. So we can call methods like getName() or getNameAndSpecs() on RebelShip because it inherits that from Ship.

Adding new Methods?

Really, RebelShip works just like a normal class. If you want to, you can add completely new functions. Let's do that with public function getFavoriteJedi() that has an array of some cool Jedis. Then use array_rand to select one of those:

13 lines lib/Model/RebelShip.php
... lines 1 - 2
class RebelShip extends Ship
{
public function getFavoriteJedi()
{
$coolJedis = array('Yoda', 'Ben Kenobi');
$key = array_rand($coolJedis);
return $coolJedis[$key];
}
}

Since this was all done on RebelShip, head over to index.php and call that method. var_dump($rebelShip->getFavoriteJedi() and you can see with my autocomplete it's showing me all of my public functions on both Ship and RebelShip:

126 lines index.php
... lines 1 - 8
$rebelShip = new RebelShip('My new rebel ship');
... lines 10 - 11
var_dump($rebelShip->getFavoriteJedi());die;
... lines 13 - 126

You can even see that the RebelShip methods are displayed bolder and methods from the parent class are lighter.

When we refresh, we see our favorite random Jedi, it works perfectly! Extending classes is great for reusing code without the sad duplication.

Leave a comment!

  • 2016-08-09 Victor Bocharsky

    Hey Aistis,

    Haha, that's amazing! We really glad you like it.

    P.S. Not so long ago, we have released the 4th episode of this series: OOP (course 4): Static methods, Namespaces, Exceptions & Traits! Woh!. More cool PHP stuff and even more challenges! Don't forget to check it out!

    Cheers!

  • 2016-08-09 Aistis Cekanauskis

    Guys i have to say, OO Courses 1 and 2 were good, but 3 is just amazing because of the tasks after every single video. I LOVE IT !!! now i watch a video and couple minutes later i can test if i understood correctly :)