Buy

A really important thing just happened: for the first time ever, we referred to something on our class by using its class name. To use the constant, we said BattleManager::TYPE_NO_JEDI:

80 lines lib/Service/BattleManager.php
... lines 1 - 2
class BattleManager
{
... lines 5 - 13
public function battle(AbstractShip $ship1, $ship1Quantity, AbstractShip $ship2, $ship2Quantity, $battleType)
{
... lines 16 - 21
while ($ship1Health > 0 && $ship2Health > 0) {
// first, see if we have a rare Jedi hero event!
if ($battleType != BattleManager::TYPE_NO_JEDI && $this->didJediDestroyShipUsingTheForce($ship1)) {
... lines 25 - 28
}
... lines 30 - 48
}
... lines 50 - 70
}
... lines 72 - 78
}

That makes sense, but notice: it's completely different than how we've referred to class properties and methods so far. Normally, we create a new object by saying new BattleManager():

72 lines lib/Service/Container.php
... lines 1 - 2
class Container
{
... lines 5 - 62
public function getBattleManager()
{
if ($this->battleManager === null) {
$this->battleManager = new BattleManager();
}
return $this->battleManager;
}
}

For us, this lives inside the Container. But here's the important part: to reference a method or property, we use the object by saying $battleManager-> followed by the method name:

110 lines battle.php
... lines 1 - 34
$battleResult = $battleManager->battle($ship1, $ship1Quantity, $ship2, $ship2Quantity, $battleType);
... lines 36 - 110

For constants, it's totally different. We don't ever need to instantiate an object. Instead, at any point, you can just say the class name ::TYPE_NO_JEDI:

80 lines lib/Service/BattleManager.php
... lines 1 - 2
class BattleManager
{
... lines 5 - 13
public function battle(AbstractShip $ship1, $ship1Quantity, AbstractShip $ship2, $ship2Quantity, $battleType)
{
... lines 16 - 21
while ($ship1Health > 0 && $ship2Health > 0) {
// first, see if we have a rare Jedi hero event!
if ($battleType != BattleManager::TYPE_NO_JEDI && $this->didJediDestroyShipUsingTheForce($ship1)) {
... lines 25 - 28
}
... lines 30 - 48
}
... lines 50 - 70
}
... lines 72 - 78
}

So sometimes, we need to create an object and reference that object. But other times, we don't need an object: we just use the class name. What's going on?

Static versus Non Static

Here's the deal: constants are static, and so far, all of our properties and methods are non-static.

You see, whenever you add something to a class - like a property or a method - you can choose to attach it to an individual instance of the object or to the class itself. When you choose to attach something to a class, it's said to be "static".

Let's look at a real example. In AbstractShip, the properties id, name, weaponPower and strength are not static:

123 lines lib/Model/AbstractShip.php
... lines 1 - 2
abstract class AbstractShip
{
private $id;
private $name;
private $weaponPower = 0;
private $strength = 0;
... lines 12 - 121
}

That means that if you have two Ship objects, each has a different id, name, weaponPower and strength. If you change the name in one Ship it does not affect any other ship objects.

But, if we were to change these properties to static - which is something you can do - then suddenly the name property would be global to all ships, meaning two ship objects could not have different names. This would be the one name for all AbstractShip.

Remember - a class is like a blueprint for a ship, and an object is like a real, physical ship. Since each real ship has a different name, it makes sense to make the $name property non-static. This attaches the name to each individual object.

But other times, it may make sense to attach a property to the blueprint itself, meaning to the class. For example, suppose that the very design of the ships guarantees that each should have a minimum strength of 100. Since that is a property of ships in general, we might add a new private static property called $minimumStrength and use that to prevent individual ships from setting their specific $strength lower than this.

Class Constants are Static

So, with properties or methods, you can choose static or non-static. But constants, well, they're static by their very nature. And that makes sense: the TYPE constants in BattleManager are global to the BattleMangaer class in general - it wouldn't make sense for them to be different for different objects.

When you reference something statically, you always reference it by saying the class name, ::, and then whatever you're referencing.

The Special Self Keyword

Before we try an example, there's another special property of static things. Notice that we're inside BattleManager and we're referencing the BattleManager class. If you want to, you can change this to, self::TYPE_NO_JEDI:

83 lines lib/Service/BattleManager.php
... lines 1 - 2
class BattleManager
{
... lines 5 - 16
public function battle(AbstractShip $ship1, $ship1Quantity, AbstractShip $ship2, $ship2Quantity, $battleType)
{
... lines 19 - 24
while ($ship1Health > 0 && $ship2Health > 0) {
// first, see if we have a rare Jedi hero event!
if ($battleType != self::TYPE_NO_JEDI && $this->didJediDestroyShipUsingTheForce($ship1)) {
... lines 28 - 31
}
if ($battleType != self::TYPE_NO_JEDI && $this->didJediDestroyShipUsingTheForce($ship2)) {
... lines 34 - 37
}
// now battle them normally
if ($battleType != self::TYPE_ONLY_JEDI) {
... lines 42 - 43
}
... lines 45 - 51
}
... lines 53 - 73
}
... lines 75 - 81
}

In the same way that $this refers to the current object, self refers to the class that we're inside of. So this didn't change our behavior: it's just a nice shortcut.

Now, let's see a real-life static method in action.

Leave a comment!

  • 2016-10-24 weaverryan

    Yo again Max!

    Ah, *really* good question, and something we should clarify I think! It's very common when you're *talking* about PHP code to say GasPlanet::getHexColor() to refer to the getHexColor method that lives in the GasPlanet class. We're using :: here... but we're not actually trying to say that getHexColor is static or non-static - it's just a lazy syntax when talking about functions (there's not a great alternative, since obviously GasPlanet->getHexColor() is closer, but is just completely nonsense code!).

    When you're learning about static vs non-static... this is confusing. But hopefully now you can understand it when you see it other places!

    Cheers!

  • 2016-10-23 Max

    In the second exercise it says:
    Update the GasPlanet::getHexColor() method to use self to reference the constants.
    As the method is not static can you actually write that? Wouldn't GasPlanet->getHexColor() be correct in this context? Thanks!