Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

PHP Namespaces in under 5 Minutes

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

I've an idea! Let's master PHP namespaces... and let's do it in under 5 minutes. Sip some coffee... let's go!

Meet Foo

Meet Foo: a perfectly boring PHP class:

9 lines Foo.php
... lines 1 - 2
class Foo
{
public function doAwesomeThings()
{
}
}

Say hi Foo! Hilarious.

10 lines Foo.php
... lines 1 - 2
class Foo
{
public function doAwesomeThings()
{
echo "Hi Foo!\n";
}
}

To instantiate our favorite new class, I'll move over to a different file and say - drumroll - $foo = new Foo():

... lines 1 - 2
require 'Foo.php';
$foo = new Foo();

Tada! We can even call a method on it: $foo->doAwesomeThings():

... lines 1 - 2
require 'Foo.php';
$foo = new Foo();
$foo->doAwesomeThings();

Will it work? Of course! I can open a terminal and run:

php some-other-file.php

Namespaces: Making Foo more Hipster

Right now, Foo doesn't have a namespace! To make Foo more hipster, let's fix that. Above the class, add, how about, namespace Acme\Tools:

12 lines Foo.php
... lines 1 - 2
namespace Acme\Tools;
class Foo
{
... lines 7 - 10
}

Usually the namespace of a class matches its directory, but that's not technically required. I just invented this one!

Using a Namespaced Class

Congratulations! Our friend Foo now lives in a namespace. Putting a class in a namespace is a lot like putting a file in a directory. To reference it, use the full, long path to the class: Acme\Tools\Foo:

... lines 1 - 2
require 'Foo.php';
$foo = new \Acme\Tools\Foo();
... lines 6 - 8

just like you can use the absolute path to reference a file in your filesystem:

ls /acme/tools/foo

When we try the script now:

php some-other-file.php

It still works!

The Magical & Optional use Statement

And... that's really! Namespaces are basically a way to... make your class names longer! Add the namespace... then refer to the class using the namespace plus the class name. That's it.

But... having these long class names right in the middle of your code is a bummer! To fix that, PHP namespaces have one more special thing: the use statement. At the top of the file, add use Acme\Tools\Foo as SomeFooClass:

... lines 1 - 2
require 'Foo.php';
use Acme\Tools\Foo as SomeFooClass;
... lines 6 - 10

This creates a... sort of... "shortcut". Anywhere else in this file, we can now just type SomeClassFoo:

... lines 1 - 2
require 'Foo.php';
use Acme\Tools\Foo as SomeFooClass;
$foo = new SomeFooClass();
... lines 8 - 10

and PHP will know that we're really referring to the long class name: Acme\Tools\Foo.

php some-other-file.php

Or... if you leave off the as part, PHP will assume you want this alias to be Foo. That's usually how code looks:

... lines 1 - 2
require 'Foo.php';
use Acme\Tools\Foo;
$foo = new Foo();
... lines 8 - 10

So, namespaces make class names longer... and use statements allow us to create shortcuts so we can use the "short" name in our code.

Core PHP Classes

In modern PHP code, pretty much all classes you deal with will live in a namespace... except for core PHP classes. Yep, core PHP classes do not live in a namespace... which kinda means that they live at the "root" namespace - like a file at the root of your filesystem:

ls /some-root-file

Let's play with the core DateTime object: $dt = new DateTime() and then echo $dt->getTimestamp() with a line break:

... lines 1 - 8
$foo->doAwesomeThings();
$dt = new DateTime();
echo $dt->getTimestamp()."\n";

When we run the script:

php some-other-file.php

It works perfectly! But... now move that same code into the doAwsomeThings method inside our friend Foo:

15 lines Foo.php
... lines 1 - 2
namespace Acme\Tools;
class Foo
{
public function doAwesomeThings()
{
echo "Hi Foo!\n";
$dt = new DateTime();
echo $dt->getTimestamp()."\n";
}
}

Now try the code:

php some-other-file.php

Ah! It explodes! And check out that error!

Class Acme\Tools\DateTime not found

The real class name should just be DateTime. So, why does PHP think it's Acme\Tools\DateTime? Because namespaces work like directories! Foo lives in Acme\Tools. When we just say DateTime, it's the same as looking for a DateTime file inside of an Acme/Tools directory:

cd /acme/tools
ls DateTime    # /acme/tools/DateTime

There are two ways to fix this. The first is to use the "fully qualified" class name. So, \DateTime:

15 lines Foo.php
... lines 1 - 2
namespace Acme\Tools;
class Foo
{
public function doAwesomeThings()
{
... lines 9 - 10
$dt = new \DateTime();
... line 12
}
}

Yep... that works just like a filesystem.

php some-other-file.php

Or... you can use DateTime... then remove the \ below:

17 lines Foo.php
... lines 1 - 2
namespace Acme\Tools;
use DateTime;
class Foo
{
public function doAwesomeThings()
{
... lines 11 - 12
$dt = new DateTime();
... line 14
}
}

That's really the same thing: there's no \ at the beginning of a use statement, but you should pretend there is. This aliases DateTime to \DateTime.

And... we're done! Namespaces make your class names longer, use statements allow you to create "shortcuts" so you can use short names in your code and the whole system works exactly like files inside directories.

Have fun!

Leave a comment!

12
Login or Register to join the conversation
Coaching T. Avatar
Coaching T. Avatar Coaching T. | posted 2 years ago | edited

I miss the hint, that with the help of namespaces, you can have multiple classes with the same name, but in different namespaces and are able to reference them accordingly with the help of use statements and aliases, even on the same file:


namespace App;

use App\Domain\Foo;
use App\Utils\Foo as UtilsFoo;

class Bar {

  public function foobar() {
    $foo = new Foo();
    $utilFoo = new UtilsFoo();

   $foo->doStuff();
   $utilFoo->doStuff();
  }

}
2 Reply

Hey Ole,

Probably it was not so obvious. Yes, it's the way to avoid collisions with same class names. Thank you for sharing this tip with others!

Cheers!

Reply
Herman Avatar

It's very similar to packages in Java

Reply

Hey Herman,

Yep, exactly... the concept is not unique, and it's used in many programming languages actually :)

Cheers!

Reply
Terrence Avatar
Terrence Avatar Terrence | posted 6 months ago | edited

I'm not sure why I keep having error issues with some challenges. Its random. I tried 2 computers, 2 different browsers and I get this error for exercise 5 on this php namespace tutorial. Class Pizza and eat.php are locked and can't be edited. I've come across an error below like this before on another challenge.

Error! This PHP error is coming from your code. Read it carefully to debug!
( ! ) Fatal error: Uncaught Error: Class 'Pizza' not found in eat.php on line 5
>( ! ) Error: Class 'Pizza' not found in eat.php on line 5
Call Stack
#TimeMemoryFunctionLocation
... See the Browser below for the full output.

Reply

Hey Terrence,

As I already answered to your other comments, you just need to wait when the challenge is shut down, refresh the page so that the system create a new challenge instance for you and try again. It happens sometimes, though it depends on how you're using the system. Are you trying to open a few challenges at the same time in different tabs? Are you trying to solve it first or after the page is loaded you hit the Check button to see the error instead of trying to solve it? Please, share more details with us about how exactly you're using challenges and I'll be happy to check it further.

Cheers!

Reply
Terrence Avatar

There were a couple times I tried hitting check to see if any errors show but the server kept crashing, so I stop doing that. I don't have challenges opened in more than 1 tab, so only working 1 challenge at a time.

What I have been doing now is try to solve it, then hit check and make updates if needed. Sometimes I have the answer exactly correct the first try and it shows the error. I verify its correct in the show answer section but it will still throw the error that doesn't make sense.

Reply

Hey Terrence,

I see... Thank you for sharing more information about how you're using the challenge system. We will try to take a look to improve it. I can only suggest you wait until the challenge instance is shut down and restart the page to recreate a new challenge instance from scratch - it should work the 2nd time. Sorry for the inconvenience!

Cheers!

Reply
Eduard Avatar

So it is the equivalent to packages in Java?

Reply

Hey Eduard

Yeah something like this :)

Cheers!

Reply
Default user avatar
Default user avatar Dan Marshall | posted 4 years ago

Thanks for the tutorial, great! Could you elaborate on the backslashes, though? Should it be 'use \...' or 'use ...' from inside a namespace?

Reply
Default user avatar
Default user avatar C Silkey | posted 4 years ago

Thanks, kept your 120 second promise :)

Reply
Cat in space

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

userVoice