The most obvious time you should create a class is when you are passing around
an associative array of data. Check out the battle() function: it returns
an associatve array - with winning_ship, losing_ship and used_jedi_powers
keys:

Ah man, I hate this kind of stuff. It's not obvious at all what's inside
this $outcome variable or whether the keys it has now might be missing or
different in the future. When you see questionable code like this, you need to be thinking:
this is perfect for a class.

Look at Ship: our other model-type class that holds data. There are two
ways we can set the data. One way is by making a __construct() function.
Here, we're saying: "Hey, when you create a new Ship object, you need to
pass in the name as an argument":

Both ways are fine - but I like to use the `__construct()` strategy for
any properties that are required. You must give your ship a name - it doesn't
make sense to have a nameless Ship fighting battles. How will they know who to
write songs about?

A BattleResult only makes sense with all of this information - that's
perfect for setting via the constructor! Create a new public function __construct()
with $usedJediPowers, $winningShip and $losingShip. These argument
names don't need to match the properties, it's just nice. Now, assign each
property to that variable: $this->usedJediPowers = $usedJediPowers,
$this->winningShip = $winningShip and $this->losingShip = $losingShip:

But we do need to get the winning ship from the BattleResult object.
Is that possible right now? No - the $winningShip property is private.
If we want to access it from outside the class, we need a public function
that returns it for us. We did this same thing in Ship with methods like
getName().

But before we add some methods - think about the 3 arguments. What are they?
Well, $usedJediPowers is a boolean and the other two are Ship objects.
And whenever you have an argument that is an object, you can choose to
type-hint it by putting the name of the class in front of it:

But this doesn't change any behavior - it just means that if you pass something
that's not a Ship object on accident, you'll get a really nice error.
And there's one other benefit - auto-completion in your editor! PhpStorm
now knows what these variables are.

Ok, back to what we were doing. We need to access the private properties
from outside this class. To do that, we'll create some public functions.
Start with public function getWinningShip(). This will just return $this->winningship:

We'll do this for each property. But actually, I can make PhpStorm write
these methods for me! Suckers! Delete getWinningShip(), then right-click, go to
"Generate" and select "Getters". Select all 3 properties, say abracadabra, and let it work
its magic.

It even added some PHPDoc above each with an @return mixed - which basically
is PhpStorms' way of saying "I don't know what this method returns". So let's
help it - the first returns a boolean and the other two return a Ship
object:

Check out the first method - getUsedJediPowers(). Is it clear what the
method returns? It's kind of bad English, and that's a shame. This method
will return whether or not Jedi powers were used to win this battle. Let's
give it a name that says that - how about wereJediPowersUsed()?

Ok, now PhpStorm is acting friendly - the angry highightling on the method
is gone. Now update the other spots: $battleResult->getWinningShip()->getName():
thank you auto-complete. Use that same method once more, and in the if
statement, use that nice wereJediPowersUsed() method. Finish with
$battleResult->getLosingShip():

Leave a comment!

That's just a way to reference to a method of a class, like in some sort of documentation file but that is not actual code.

Cheers!

2018-09-21Serge Boyko

"And gone are the days of needing to use weird associative arrays: BattleManager::battle() returns a nice BattleResult object." Unless I missed something, you can't call `battle()` as a static function, because it doesn't have a `static` keyword.