Something that is not immediately obvious, particular with PHP 5.3, is that namespace resolutions within an import are not resolved recursively. i.e.: if you alias an import and then use that alias in another import then this latter import will not be fully resolved with the former import.
For example:
use \Controllers as C;
use C\First;
use C\Last;
Both the First and Last namespaces are NOT resolved as \Controllers\First or \Controllers\Last as one might intend.
Using namespaces: Aliasing/Importing
The ability to refer to an external fully qualified name with an alias, or importing, is an important feature of namespaces. This is similar to the ability of unix-based filesystems to create symbolic links to a file or to a directory.
PHP namespaces support two kinds of aliasing or importing: aliasing a class name, and aliasing a namespace name. Note that importing a function or constant is not supported.
In PHP, aliasing is accomplished with the use operator. Here is an example showing all 3 kinds of importing:
Example #1 importing/aliasing with the use operator
<?php
namespace foo;
use My\Full\Classname as Another;
// this is the same as use My\Full\NSname as NSname
use My\Full\NSname;
// importing a global class
use \ArrayObject;
$obj = new namespace\Another; // instantiates object of class foo\Another
$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // instantiates object of class ArrayObject
// without the "use \ArrayObject" we would instantiate an object of class foo\ArrayObject
?>
PHP additionally supports a convenience shortcut to place multiple use statements on the same line
Example #2 importing/aliasing with the use operator, multiple use statements combined
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
?>
Importing is performed at compile-time, and so does not affect dynamic class, function or constant names.
Example #3 Importing and dynamic names
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
$a = 'Another';
$obj = new $a; // instantiates object of class Another
?>
In addition, importing only affects unqualified and qualified names. Fully qualified names are absolute, and unaffected by imports.
Example #4 Importing and fully qualified names
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>
You are allowed to "use" the same resource multiple times as long as it is imported under a different alias at each invocation.
For example:
<?php
use Lend;
use Lend\l1;
use Lend\l1 as l3;
use Lend\l2;
use Lend\l1\Keller;
use Lend\l1\Keller as Stellar;
use Lend\l1\Keller as Zellar;
use Lend\l2\Keller as Dellar;
...
?>
In the above example, "Keller", "Stellar", and "Zellar" are all references to "\Lend\l1\Keller", as are "Lend\l1\Keller", "l1\Keller", and "l3\Keller".
Note that you can not alias global namespace:
use \ as test;
echo test\strlen('');
won't work.
The "use" keyword can not be declared inside the function or method. It should be declared as global, after the "namespace" as:
<?php
namespace mydir;
// works perfectly
use mydir/subdir/Class1 as Class1;
function fun1()
{
// Parse error: syntax error, unexpected T_USE
use mydir/subdir/Class1 as Class1;
}
class Class2
{
public function fun2()
{
// Parse error: syntax error, unexpected T_USE
use mydir/subdir/Class1 as Class1;
}
}
?>
If you are testing your code at the CLI, note that namespace aliases do not work!
(Before I go on, all the backslashes in this example are changed to percent signs because I cannot get sensible results to display in the posting preview otherwise. Please mentally translate all percent signs henceforth as backslashes.)
Suppose you have a class you want to test in myclass.php:
<?php
namespace my%space;
class myclass {
// ...
}
?>
and you then go into the CLI to test it. You would like to think that this would work, as you type it line by line:
require 'myclass.php';
use my%space%myclass; // should set 'myclass' as alias for 'my%space%myclass'
$x = new myclass; // FATAL ERROR
I believe that this is because aliases are only resolved at compile time, whereas the CLI simply evaluates statements; so use statements are ineffective in the CLI.
If you put your test code into test.php:
<?php
require 'myclass.php';
use my%space%myclass;
$x = new myclass;
//...
?>
it will work fine.
I hope this reduces the number of prematurely bald people.
(All the backslashes in namespaces are slashes because I can't figure out how to post backslashes here.)
You can have the same "use" for a class and a namespace. For example, if you have these files:
<?php
// foo/bar.php
namespace foo;
class bar
{
public function __toString ()
{
return 'foo\bar\__toString()';
}
}
?>
<?php
// foo/bar/MyClass.php
namespace foo/bar;
class MyClass
{
public function __toString ()
{
return 'foo\bar\MyClass\__toString()';
}
}
?>
In another namespace, you can do:
<?php
namespace another;
require_once 'foo/bar.php';
require_once 'foo/bar/MyClass.php';
use foo/bar;
$bar = new bar();
echo $bar."\n";
$class = new bar/MyClass();
echo $class."\n";
?>
And it will makes the following output:
foo\bar\__toString()
foo\bar\MyClass\__toString()
The last example on this page shows a possibly incorrect attempt of aliasing, but it is totally correct to import a trait \Languages\Languages\Danish.
Because imports happen at compile time, there's no polymorphism potential by embedding the use keyword in a conditonal.
e.g.:
<?php
if ($objType == 'canine') {
use Animal\Canine as Beast;
}
if ($objType == 'bovine') {
use Animal\Bovine as Beast;
}
$oBeast = new Beast;
$oBeast->feed();
?>
