Buy

I hate needing all these require statements. But thanks to our autoloader, the only thing we need to do is give every class the namespace that matches its directory. This will be a little bit of work because we didn't do it up front - life is much easier when you use namespaces like this from the very beginning. But, we'll learn some other stuff along the way.

The AbstractShip class lives in the Model directory, so give it the namespace Model:

125 lines lib/Model/AbstractShip.php
... lines 1 - 2
namespace Model;
abstract class AbstractShip
... lines 6 - 125

Copy that and do the same thing in BattleResult, BrokenShip, RebelShip, Ship and FriendShip -- just kidding there's none of that in epic code battles:

57 lines lib/Model/BattleResult.php
... lines 1 - 2
namespace Model;
class BattleResult
... lines 6 - 57
22 lines lib/Model/BrokenShip.php
... lines 1 - 2
namespace Model;
class BrokenShip extends AbstractShip
... lines 6 - 22
38 lines lib/Model/RebelShip.php
... lines 1 - 2
namespace Model;
class RebelShip extends AbstractShip
... lines 6 - 38
45 lines lib/Model/Ship.php
... lines 1 - 2
namespace Model;
class Ship extends AbstractShip
... lines 6 - 45

Perfect. BattleManager already has the correct Service namespace:

94 lines lib/Service/BattleManager.php
... lines 1 - 2
namespace Service;
class BattleManager
... lines 6 - 94

In Container, paste that same one:

74 lines lib/Service/Container.php
... lines 1 - 2
namespace Service;
class Container
... lines 6 - 74

Repeat that in JsonFileShipStorage, PdoShipStorage, ShipLoader and ShipStorageInterface:

34 lines lib/Service/JsonFileShipStorage.php
... lines 1 - 2
namespace Service;
class JsonFileShipStorage implements ShipStorageInterface
... lines 6 - 34
35 lines lib/Service/PdoShipStorage.php
... lines 1 - 2
namespace Service;
class PdoShipStorage implements ShipStorageInterface
... lines 6 - 35
63 lines lib/Service/ShipLoader.php
... lines 1 - 2
namespace Service;
class ShipLoader
... lines 6 - 63
27 lines lib/Service/ShipStorageInterface.php
... lines 1 - 2
namespace Service;
interface ShipStorageInterface
... lines 6 - 27

These all live in the Service directory.

Missing use Statements = Common Error

Ok! Let's see what breaks! Go back and refresh. The first error we get is:

Class Container not found in index.php

Ok, you're going to see a lot of class not found errors in your future. When you see them, read the error very closely: it always contains a hint. This says class Container is not found. Well, we don't have a class called Container: our class is called Service\Container. This tells me that in index.php on line 6, we're referencing the class name without the namespace. Sure enough, we have new Container:

143 lines index.php
... lines 1 - 6
$container = new Container($configuration);
... lines 8 - 143

To fix this, we could say Service\Container here or we can add a use statement for Service\Container. Let's do that:

145 lines index.php
... lines 1 - 3
use Service\Container;
... lines 5 - 8
$container = new Container($configuration);
... lines 10 - 145

And I can already see that we'll have the same problem down below with BrokenShip: PhpStorm is trying to warn me! Add a use Model\BrokenShip to take care of that:

145 lines index.php
... lines 1 - 4
use Model\BrokenShip;
... lines 6 - 13
$brokenShip = new BrokenShip('Just a hunk of metal');
... lines 15 - 145

We'll probably have the same problem in battle.php - so open that up. Yep, add use Service\Container:

112 lines battle.php
... line 1
use Service\Container;
... lines 3 - 5
$container = new Container($configuration);
... lines 7 - 112

Looking good!

Reading the Error Messages... Closely

Try it again! Ok:

Class Service\RebelShip not found in ShipLoader.

Remember what I just said about reading the error messages closely? This one has a clue: it's looking for Service\RebelShip. But we don't have a class called Service\RebelShip - our class is called Model\RebelShip:

38 lines lib/Model/RebelShip.php
... lines 1 - 2
namespace Model;
class RebelShip extends AbstractShip
... lines 6 - 38

The problem exists where we're referencing this class - so in ShipLoader at line 43.

This is the most common mistake with namespaces: we have new RebelShip, but we don't have a use statement on top for this:

63 lines lib/Service/ShipLoader.php
... lines 1 - 2
namespace Service;
class ShipLoader
{
... lines 7 - 40
private function createShipFromData(array $shipData)
{
if ($shipData['team'] == 'rebel') {
$ship = new RebelShip($shipData['name']);
} else {
$ship = new Ship($shipData['name']);
... line 47
}
... lines 49 - 54
}
... lines 56 - 60
}

This is the same problem we just solved in index.php, but with a small difference. Unlike index.php and battle.php, this file lives in a namespace called Service. That causes PHP to assume that RebelShip also lives in that namespace -- you know like roommates.

Here's how it works: when PHP parses this file, it sees the RebelShip class on line 43. Next, it looks up at the top of the file to see if there are any use statements that end in RebelShip. Since there aren't, it assumes that RebelShip also lives in the Service namespace, so Service\RebelShip.

Think about it: this is just like directories on your filesystem. If you are inside of a directory called Service and you say ls RebelShip, it's going to look for RebelShip inside of the Service directory.

But in index.php - since this doesn't hold a class - we didn't give this file a namespace. If you forget a use statement for BrokenShip here, this is equivalent to saying ls BrokenShip from the root of your file system, instead of from inside some directory.

In both cases the solution is the same: add the missing use statement: use Model\RebelShip:

67 lines lib/Service/ShipLoader.php
... lines 1 - 2
namespace Service;
use Model\RebelShip;
... lines 6 - 8
class ShipLoader
... lines 10 - 67

Now PhpStorm stops highlighting this as an error. Much better.

We have the same problem below for Ship: add use Model\Ship:

67 lines lib/Service/ShipLoader.php
... lines 1 - 2
namespace Service;
use Model\RebelShip;
use Model\Ship;
... lines 7 - 8
class ShipLoader
... lines 10 - 67

Finally, there's one more spot in the PHP documentation itself. Because we don't have a use statement in this file yet for AbstractShip, PhpStorm assumes that this class is Service\AbstractShip. To fix that, add use Model\AbstractShip:

67 lines lib/Service/ShipLoader.php
... lines 1 - 2
namespace Service;
use Model\RebelShip;
use Model\Ship;
use Model\AbstractShip;
class ShipLoader
{
... lines 11 - 17
/**
* @return AbstractShip[]
*/
public function getShips()
{
... lines 23 - 31
}
/**
* @param $id
* @return AbstractShip
*/
public function findOneById($id)
{
... lines 40 - 42
}
... lines 44 - 64
}

Now, everything looks happy!

The moral of the story is this: whenever you reference a class, don't forget to put a use statement for it. Now, there is one exception to this rule. If you reference a class that happens to be in the same namespace as the file you're in - like ShipStorageInterface - then you don't need a use statement:

67 lines lib/Service/ShipLoader.php
... lines 1 - 8
class ShipLoader
{
... lines 11 - 12
public function __construct(ShipStorageInterface $shipStorage)
{
... line 15
}
... lines 17 - 64
}

PHP correctly assumes that ShipStorageInterface lives in the Service namespace. But you don't get lucky like this too often.

I already know we need to fix one more spot in BattleManager. Add a use statement for Model\BattleResults and another for Model\AbstractShip:

97 lines lib/Service/BattleManager.php
... lines 1 - 2
namespace Service;
use Model\BattleResult;
use Model\AbstractShip;
class BattleManager
... lines 9 - 97

Phew! I promise, this is all a lot easier if you just use namespaces from the beginning! Let's refresh the page. Our app is back to life, and the require statements are gone!

Leave a comment!

  • 2016-11-10 Hakim Ch

    Super!!! challenge done! your the best :D

  • 2016-11-10 weaverryan

    Yo Hakim Ch! Try it again - I saw that (once) the server you were using shutdown (it does that for security after about 20 minutes). Or there may have been some other connection problem. Anyways, sorry about any issues - I can see the problem in the logs, but it looks temporary.

    Cheers!

  • 2016-11-10 Hakim Ch

    I can't check the challenge, no response from the server

  • 2016-10-24 Max

    And you are right again... :D Actually a quite useful feature, if you know about it :) Thanks!

  • 2016-10-24 weaverryan

    Yo Max!

    You're playing close attention :). PHPstorm highlights the files in different colors based on their storage status in git. Behind the scenes. this project is being stored in git, and between the chapters, I actually commit all of my changes. You'll notice that the tree at the end of one chapter has different colors than the start of the next chapter because of this (nobody has ever noticed that before!). I believe blue is a modified file and red is a new file.

    Cheers!

  • 2016-10-23 Max

    What is the purpose of the coloring of the files in the document tree on the left side? It changes during the process of adding namespaces and in my own code I saw at some point also red coloring for instance.