Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

More Fun with use Statements

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

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:

... 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:

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

Perfect. BattleManager already has the correct Service namespace:

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

In Container, paste that same one:

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

Repeat that in JsonFileShipStorage, PdoShipStorage, ShipLoader and ShipStorageInterface:

... lines 1 - 2
namespace Service;
class JsonFileShipStorage implements ShipStorageInterface
... lines 6 - 34
... lines 1 - 2
namespace Service;
class PdoShipStorage implements ShipStorageInterface
... lines 6 - 35
... lines 1 - 2
namespace Service;
class ShipLoader
... lines 6 - 63
... 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('I am so broken');
... 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:

... 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:

... 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:

... 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:

... 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:

... 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:

... 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:

... 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!

12
Login or Register to join the conversation
Patrick L. Avatar
Patrick L. Avatar Patrick L. | posted 2 years ago

Hi there I am getting a Fatal Error saying "Uncaught Error: Class 'Service\PDO' not found in C:\Users\PatrickLye\github\PHP\oiii\lib\Service\Container.php on line 28"
line 28 has this on it
"$this->pdo = new PDO(
$this->configuration['db_dsn'],
$this->configuration['db_user'],
$this->configuration['db_pass']
);"
Any suggestions?

Reply

Hey Patrick Lye

Seems like you forgot to add the PDO class import. Can you double-check the imports at the top of your file?

Cheers!

Reply
Patrick L. Avatar

The top part of my first comment is missing this:

namespace Service;

class Container

{
private $configuration;

private $pdo;

private $shipLoader;

private $battleManager;

private $shipStorage;

public function __construct(array $configuration)
{
not enteriely sure why it got removed

Reply
Patrick L. Avatar

Okay I haven't a clue how I fixed it, but I did my code went from this:
configuration = $configuration;
}

/**
* @return PDO
*/
public function getPDO()
{
if ($this->pdo === null) {
$this->pdo = new PDO(
$this->configuration['db_dsn'],
$this->configuration['db_user'],
$this->configuration['db_pass']
);

$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}

return $this->pdo;
}

/**
* @return ShipLoader
*/
public function getShipLoader()
{
if ($this->shipLoader === null) {
$this->shipLoader = new ShipLoader($this->getShipStorage());
}

return $this->shipLoader;
}

public function getShipStorage()
{
if ($this->shipStorage === null) {
//$this->shipStorage = new PdoShipStorage($this->getPDO());
$this->shipStorage = new JsonFileShipStorage(__DIR__.'/../../resources/ships.json');
}

return $this->shipStorage;
}

/**
* @return BattleManager
*/

public function getBattleManager()
{
if ($this->battleManager === null) {
$this->battleManager = new BattleManager();
}

return $this->battleManager;
}
}

to this:

configuration = $configuration;
}
/**
* @return PDO
*/
public function getPDO()
{
if ($this->pdo === null) {
$this->pdo = new PDO(
$this->configuration['db_dsn'],
$this->configuration['db_user'],
$this->configuration['db_pass']
);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return $this->pdo;
}
/**
* @return ShipLoader
*/
public function getShipLoader()
{
if ($this->shipLoader === null) {
$this->shipLoader = new ShipLoader($this->getShipStorage());
}
return $this->shipLoader;
}
public function getShipStorage()
{
if ($this->shipStorage === null) {
//$this->shipStorage = new PdoShipStorage($this->getPDO());
$this->shipStorage = new JsonFileShipStorage(__DIR__.'/../../resources/ships.json');
}
return $this->shipStorage;
}
/**
* @return BattleManager
*/
public function getBattleManager()
{
if ($this->battleManager === null) {
$this->battleManager = new BattleManager();
}
return $this->battleManager;
}
}

Reply
Si Y. Avatar

I'm getting errors around mcrypt_module_self_test()::TYPE_NO_JEDI in BattleManager.php. They've only just started, I'm on PHP v 7.2 and this function is deprecated. I'm not really sure as to why it's being used, could someone please enlighten me? Many thanks . Si.

Reply

Hey simon young

This tutorial was coded on PHP5 that's why you will probably find some deprecated functions being used (but it should be nothing to worry about). Can you show me what error you got?

Cheers!

Reply
Default user avatar
Default user avatar Hakim Ch | posted 4 years ago

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

Reply

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!

Reply
Default user avatar

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

Reply
Max S. Avatar

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.

Reply

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!

Reply
Max S. Avatar

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

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!