使用命名空间:基础

(PHP 5 >= 5.3.0, PHP 7)

在讨论如何使用命名空间之前,必须了解 PHP 是如何知道要使用哪一个命名空间中的元素的。可以将 PHP 命名空间与文件系统作一个简单的类比。在文件系统中访问一个文件有三种方式:

  1. 相对文件名形式如foo.txt。它会被解析为 currentdirectory/foo.txt,其中 currentdirectory 表示当前目录。因此如果当前目录是 /home/foo,则该文件名被解析为/home/foo/foo.txt
  2. 相对路径名形式如subdirectory/foo.txt。它会被解析为 currentdirectory/subdirectory/foo.txt
  3. 绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt
PHP 命名空间中的元素使用同样的原理。例如,类名可以通过三种方式引用:
  1. 非限定名称,或不包含前缀的类名称,例如 $a=new foo();foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。详情参见 使用命名空间:后备全局函数名称/常量名称
  2. 限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo();subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo
  3. 完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo();\currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo

下面是一个使用这三种方式的实例:

file1.php

<?php
namespace Foo\Bar\subnamespace;

const 
FOO 1;
function 
foo() {}
class 
foo
{
    static function 
staticmethod() {}
}
?>

file2.php

<?php
namespace Foo\Bar;
include 
'file1.php';

const 
FOO 2;
function 
foo() {}
class 
foo
{
    static function 
staticmethod() {}
}

/* 非限定名称 */
foo(); // 解析为 Foo\Bar\foo resolves to function Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo的静态方法staticmethod。resolves to class Foo\Bar\foo, method staticmethod
echo FOO// resolves to constant Foo\Bar\FOO

/* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
                                  // 以及类的方法 staticmethod
echo subnamespace\FOO// 解析为常量 Foo\Bar\subnamespace\FOO
                                  
/* 完全限定名称 */
\Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO// 解析为常量 Foo\Bar\FOO
?>

注意访问任意全局类、函数或常量,都可以使用完全限定名称,例如 \strlen()\Exception\INI_ALL

Example #1 在命名空间内部访问全局类、函数和常量

<?php
namespace Foo;

function 
strlen() {}
const 
INI_ALL 3;
class 
Exception {}

$a = \strlen('hi'); // 调用全局函数strlen
$b = \INI_ALL// 访问全局常量 INI_ALL
$c = new \Exception('error'); // 实例化全局类 Exception
?>

User Contributed Notes

Anonymous 27-Oct-2014 10:08
<?php

namespace Foo;

try {
   
// Something awful here
    // That will throw a new exception from SPL
}
catch (
Exception as $ex) {
   
// We will never get here
    // This is because we are catchin Foo\Exception
}
?>

Instead use fully qualified name for the exception to catch it

<?php

namespace Foo;

try {
   
// something awful here
    // That will throw a new exception from SPL
}
catch (\
Exception as $ex) {
   
// Now we can get here at last
}
?>
tom at tomwardrop dot com 26-Feb-2012 07:06
It seems the file system analogy only goes so far. One thing that's missing that would be very useful is relative navigation up the namespace chain, e.g.

<?php
namespace MyProject {
   class
Person {}
}

namespace
MyProject\People {
    class
Adult extends ..\Person {}
}
?>

That would be really nice, especially if you had really deep namespaces. It would save you having to type out the full namespace just to reference a resource one level up.
Lukas Z 06-Dec-2011 12:25
Well variables inside namespaces do not override others since variables are never affected by namespace but always global:
"Although any valid PHP code can be contained within a namespace, only four types of code are affected by namespaces: classes, interfaces, functions and constants. "

Source: "Defining Namespaces"
http://www.php.net/manual/en/language.namespaces.definition.php
philip dot preisser at arcor dot de 14-Jun-2011 11:34
Working with variables can overwrite equal variables in other namespaces

<?php // php5 - package-version : 5.3.5-1ubuntu7.2

   
namespace
   
main
   
{}

    namespace
   
main\sub1
   
{
       
$data = 1;
    }

    namespace
   
main\sub2
   
{
        echo
$data;// 1
       
$data = 2;
    }

    namespace
   
main\sub1
   
{
        echo
$data;// 2
       
$data = 1;
    }

    namespace
    {
        echo
$data;// 1
   
}

?>
Franois Vespa 22-Dec-2010 02:42
It seems you cannot nest a constant declaration within a if statement

<?php

namespace FOO;

if(eval)
const
BAR=true;

// will throw the following error:
// PHP Parse error:  syntax error, unexpected T_CONST

// instead use:

if(eval)
define('FOO\BAR',true);

?>
richard at richard-sumilang dot com 27-Mar-2008 10:36
Syntax for extending classes in namespaces is still the same.

Lets call this Object.php:

<?php

namespace com\rsumilang\common;

class
Object{
  
// ... code ...
}

?>

And now lets create a class called String that extends object in String.php:

<?php

class String extends com\rsumilang\common\Object{
  
// ... code ...
}

?>

Now if you class String was defined in the same namespace as Object then you don't have to specify a full namespace path:

<?php

namespace com\rsumilang\common;

class
String extends Object
{
  
// ... code ...
}

?>

Lastly, you can also alias a namespace name to use a shorter name for the class you are extending incase your class is in seperate namespace:

<?php

namespace com\rsumilang\util;
use
com\rsumlang\common as Common;

class
String extends Common\Object
{
  
// ... code ...
}

?>

- Richard Sumilang