How to Use PHP Namespaces, Part 2: Importing, Aliases, and Name Resolution

Tweet

PHP namespacesIn part 1, we discussed why PHP namespaces are useful and the namespace keyword. In this article, we examine the use command and the way PHP resolves namespace names.

For the purposes of this example, we will define two almost identical code blocks; the only difference is their namespace:

lib1.php:


<?php
// application library 1
namespace App\Lib1;

const MYCONST = 'App\Lib1\MYCONST';

function MyFunction() {
	return __FUNCTION__;
}

class MyClass {
	static function WhoAmI() {
		return __METHOD__;
	}
}
?>

lib2.php:


<?php
// application library 2
namespace App\Lib2;

const MYCONST = 'App\Lib2\MYCONST';

function MyFunction() {
	return __FUNCTION__;
}

class MyClass {
	static function WhoAmI() {
		return __METHOD__;
	}
}
?>

There is a little PHP terminology to understand before we begin…

Fully-qualified name
Any PHP code can refer to a fully-qualified name — an identifier starting with the namespace backslash separator, e.g. AppLib1MYCONST, AppLib2MyFunction(), etc.

Fully-qualified names have no ambiguity. The initial backslash operates in a similar way to a file path; it signifies the ‘root’ global space. If we implemented a different MyFunction() in our global space, it could be called from lib1.php or lib2.php using MyFunction().

Fully-qualified names are useful for one-off function calls or object initialization. However, they can become impractical when you are making lots of calls. As we will discover below, PHP offers other options to save us from namespace typing cramps.

Qualified name
An identifier with at least one namespace separator, e.g. Lib1MyFunction().

Unqualified name
An identifier without a namespace separator, e.g. MyFunction().

Working Within the Same Namespace

Consider the following code:

myapp1.php:


<?php
namespace App\Lib1;

require_once('lib1.php');
require_once('lib2.php');

header('Content-type: text/plain');
echo MYCONST . "\n";
echo MyFunction() . "\n";
echo MyClass::WhoAmI() . "\n";
?>

Although we include both lib1.php and lib2.php, the identifiers MYCONST, MyFunction, and MyClass will only reference code in lib1.php. This occurs because the myapp1.php code is within the same AppLib1 namespace:

result:


App\Lib1\MYCONST
App\Lib1\MyFunction
App\Lib1\MyClass::WhoAmI

Namespace Importing

Namespaces can be imported with the use operator, e.g.

myapp2.php:


<?php
use App\Lib2;

require_once('lib1.php');
require_once('lib2.php');

header('Content-type: text/plain');
echo Lib2\MYCONST . "\n";
echo Lib2\MyFunction() . "\n";
echo Lib2\MyClass::WhoAmI() . "\n";
?>

Any number of use statements can be defined or you can separate individual namespaces with a comma. In this example we have imported the AppLib2 namespace. We still cannot refer directly to MYCONST, MyFunction or MyClass because our code is in the global space and PHP will look for them there. However, if we add a prefix of ‘Lib2′, they become qualified names; PHP will search through the imported namespaces until it finds a match.

result:


App\Lib1\MYCONST
App\Lib2\MyFunction
App\Lib2\MyClass::WhoAmI

Namespace Aliases

Namespace aliases are perhaps the most useful construct. Aliases allow us to reference long namespaces using a shorter name.

myapp3.php:


<?php
use App\Lib1 as L;
use App\Lib2\MyClass as Obj;

header('Content-type: text/plain');
require_once('lib1.php');
require_once('lib2.php');

echo L\MYCONST . "\n";
echo L\MyFunction() . "\n";
echo L\MyClass::WhoAmI() . "\n";
echo Obj::WhoAmI() . "\n";
?>

The first use statement defines AppLib1 as ‘L’. Any qualified names using ‘L’ will be translated to ‘AppLib1′ at compile-time. We can therefore refer to LMYCONST and LMyFunction rather than the fully-qualified name.

The second use statement is more interesting. It defines ‘Obj’ as an alias for the class ‘MyClass’ within the AppLib2 namespace. This is only possible for classes — not constants or functions. We can now use new Obj() or run static methods as shown above.

result:


App\Lib1\MYCONST
App\Lib1\MyFunction
App\Lib1\MyClass::WhoAmI
App\Lib2\MyClass::WhoAmI

PHP Name Resolution Rules

PHP identifier names are resolved using the following namespace rules. Refer to the PHP manual for more information.

1. Calls to fully-qualified functions, classes or constants are resolved at compile-time.

2. Unqualified and qualified names are translated according to the import rules, e.g. if the namespace ABC is imported as C, a call to CDe() is translated to ABCDe().

3. Inside a namespace, all qualified names not already translated according to import rules have the current namespace prepended, e.g. if a call to CDe() is performed within namespace AB, it is translated to ABCDe().

4. Unqualified class names are translated according to current import rules and the full name is substituted for short imported name, e.g. if class C in namespace AB is imported as X, new X() is translated to new ABC().

5. Unqualified function calls within a namespace are resolved at run-time. For example, if MyFunction() is called within namespace AB, PHP first looks for the function ABMyFunction(). If that is not found, it looks for MyFunction() in the global space.

6. Calls to unqualified or qualified class names are resolved at run-time. For example, if we call new C() within namespace AB, PHP will look for the class ABC. If that is not found, it will attempt to autoload ABC.

See also:

In tomorrow’s final article we will cover autoloading and other advanced options.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • harald

    sorry … i still think the is the ugliest character they could have chosen for namespaces. i hate reading source-code with all these and it, also it’s not the easiest character to type on an osx keyboard. but i also know, that the core-dev team was _and_ is not open for any discussion on this topic — too bad.

  • http://xavisys.com aaroncampbell

    Can you check if a function exists in the global namespace from within a namespace (For example to allow overriding a function)?

    Something like:

    <?php
    // application library 1
    namespace AppLib1;

    const MYCONST = 'AppLib1MYCONST';

    if ( !function_exists('MyFunction') ) {
    function MyFunction() {
    return __FUNCTION__;
    }
    } else {
    function MyFunction() {
    return MyFunction();
    }
    }
    ?>

    Basically, can you check if a user has defined a global version of the function?

  • http://www.optimalworks.net/ Craig Buckler

    @aaroncampbell
    I’ve not tested it, but I would be amazed if function_exists() was not namespace-aware.

    However, your example wouldn’t need to do that. If you define MyFunction() in AppLib1, it will be executed. If not, MyFunction() will be executed.

  • Leo

    Nice written.
    Give me the third part NAU!

  • Tom

    Why does it not look in the global namespace if it can’t find a class in the current namespace?


    namespace test;
    ...
    throw new Exception("some error");

    I have to do:

    namespace test;
    ...
    throw new Exception("some error");

    or

    namespace test;
    use Exception;
    ...
    throw new Exception("some error");

  • gaurav_ch

    I am a web designer looking to expand my skills into web development. PHP is my obvious choice but I am somewhat not too happy with the way php syntax for namespaces. Why can’t we write use App.Lib1 as L; or use App->Lib1 as L; or something more like C#. It is most easy to read without a . When I was going through the code my eyes started hurting.

  • harald

    @gaurav_ch:

    because ‘.’ is the operator for concatenating strings in PHP, and ‘->’ is the operater for accesing object-properties and methods. so these symbols would have not been possible to use. but they could have used ‘::’ — it even _was_ ‘::’ before they decided, they had to choose a different character — hell, even ‘:::’ had been a better choice than what they did … nevermind: we, at my company, developing inhouse-software decided to not use namespaces for our projects. it would have been a nice-to-have feature, but the PHP way is definitly not the way to go.

  • http://www.cybergeeksoftware.com/ CGSS-CyberGeek

    @Harald: (regarding last comment)

    Do you know if there was any logical reason other then the core developers perhaps being idiotic on why they used the backslash () instead of the double colon like almost every other language (or the majority of the C derived languages)?

  • http://www.cemerson.co.uk Stormrider

    Does it matter which character is used? Why all the hate for ?

  • http://www.lunadesign.org awasson

    “Does it matter which character is used? Why all the hate for ?”

    Perhaps it is because it’s just one more character to trip over when transitioning from one C-like language to another.

    The reason I’m having a bit of trouble with it, is because the “” is supposed to be an escape character. Things get a bit messy and hard to read if you use any escape characters in close proximity to use of a qualified name…. It’s a little messy and hard to read at a glance I suppose.

    Time will tell.

  • http://logicearth.wordpress.com logic_earth

    “…the “” is supposed to be an escape character.”

    Only an escape character in the context of a string. A single character can have multiple roles in a language. To be honest it does not matter what character is used as long as it works. And in the case of the backlash character nothing else was using it, that alone frees the parser from ambiguity. (i.e., less overhead)

  • http://www.cemerson.co.uk Stormrider

    ‘Different languages use different syntax’ shocker!

    There are several characters that change meaning depending on their context, I don’t see why this is any different really.

  • OtengiM

    Also we are going to drop the namespace feature for our projects because is an idiotic solution because the syntax. The code looks so verbose and messy with the new dumb namespace syntax.

  • http://logicearth.wordpress.com logic_earth

    That is just silly, @OtengiM. I hope you realize that.

  • http://xavisys.com aaroncampbell

    I agree. If you don’t use great functionality just because of the character it uses, you just look like a 3 year old throwing a fit because they wanted the red one and the gumball machine gave them blue.