使用命名空间:基础
(PHP 5 >= 5.3.0, PHP 7)
在讨论如何使用命名空间之前,必须了解 PHP 是如何知道要使用哪一个命名空间中的元素的。可以将 PHP 命名空间与文件系统作一个简单的类比。在文件系统中访问一个文件有三种方式:
- 相对文件名形式如foo.txt。它会被解析为currentdirectory/foo.txt,其中 currentdirectory 表示当前目录。因此如果当前目录是/home/foo,则该文件名被解析为/home/foo/foo.txt。
- 相对路径名形式如subdirectory/foo.txt。它会被解析为currentdirectory/subdirectory/foo.txt。
- 绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt。
- 非限定名称,或不包含前缀的类名称,例如$a=new foo();或foo::staticmethod();。如果当前命名空间是currentnamespace,foo 将被解析为currentnamespacefoo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。详情参见使用命名空间:后备全局函数名称/常量名称。
- 限定名称,或包含前缀的名称,例如$a = new subnamespacefoo();或subnamespacefoo::staticmethod();。如果当前的命名空间是currentnamespace,则 foo 会被解析为currentnamespacesubnamespacefoo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespacefoo。
- 完全限定名称,或包含了全局前缀操作符的名称,例如,$a = new currentnamespacefoo();或currentnamespacefoo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespacefoo。
下面是一个使用这三种方式的实例:
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 ?>
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
<?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 } ?>
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
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.
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 } ?>
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); ?>