- 虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits)、接口、函数和常量。
在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。另外,所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前:
<html>
<?php
namespace MyProject; // 命名空间前出现了“<html>” 会致命错误
- 命名空间必须是程序脚本的第一条语句
?>
- 允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类 unix 文件系统中可以创建对其它的文件或目录的符号连接。
所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。在PHP中,别名是通过操作符 use 来实现的.
- 使用命名空间:别名/导入
PHP 命名空间支持 有两种使用别名或导入方式:为类名称使用别名,或为命名空间名称使用别名。
在PHP中,别名是通过操作符 use 来实现的. 下面是一个使用所有可能的三种导入方式的例子:
1、使用use操作符导入/使用别名
<?php
namespace foo;
use
My\Full\Classname as Another;
// 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname;
// 导入一个全局类
use \ArrayObject;
$obj = new namespace\Another; // 实例化 foo\Another 对象
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); //
实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
?>
- 全局空间
如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。
在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。
使用全局空间说明
<?php
namespace A\B\C;
/* 这个函数是 A\B\C\fopen */
function fopen() {
/* ...
*/
$f = \fopen(...); //
调用全局的fopen函数
return $f;
}
?>
- 使用命名空间:后备全局函数/常量
在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。
类名称总是解析到当前命名空间中的名称。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称,例如:
1、在命名空间中访问全局类
<?php
namespace A\B\C;
class
Exception extends \Exception {}
$a
= new Exception(‘hi‘); // $a 是类 A\B\C\Exception 的一个对象
$b = new
\Exception(‘hi‘); //
$b 是类 Exception 的一个对象
$c
= new ArrayObject; // 致命错误, 找不到
A\B\C\ArrayObject 类
?>
对于函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。
2、 命名空间中后备的全局函数/常量
<?php
namespace A\B\C;
const E_ERROR = 45;
function strlen($str)
{
return \strlen($str) - 1;
}
echo
E_ERROR, "\n"; // 输出 "45"
echo INI_ALL, "\n"; // 输出 "7" - 使用全局常量 INI_ALL
echo
strlen(‘hi‘), "\n"; // 输出 "1"
if
(is_array(‘hi‘)) { // 输出 "is not array"
echo "is array\n";
}
else {
echo "is not array\n";
}
?>
- 名称解析遵循下列规则:
- 对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。
- 所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。
- 在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。
- 非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。
- 在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的:
- 在当前命名空间中查找名为 A\B\foo() 的函数
- 尝试查找并调用 全局(global) 空间中的函数 foo()。
- 在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用 new C() 及 new D\E() 的解析过程: new C()的解析:
- 在当前命名空间中查找A\B\C类。
- 尝试自动装载类A\B\C。
new D\E()的解析:
- 在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。
- 尝试自动装载类 A\B\D\E。
为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。
- 子命名空间
与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:
<?php
namespace MyProject\Sub\Level;
//声明分层次的单个命名空间
const CONNECT_OK =
1;
class Connection { /* ... */ }
function Connect() { /* ... */ }
?>
上面的例子创建了常量 MyProject\Sub\Level\CONNECT_OK,类 MyProject\Sub\Level\Connection 和函数 MyProject\Sub\Level\Connect。
Static 关键字
声明类属性或方法为 static(静态),就可以不实例化类而直接访问。
静态属性不能通过一个类已实例化的对象来访问,
(但静态方法可以)。
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
就我们以往的经验来说,类中的方法往往都是由已实例化的对象来调用的,因此常常用伪变量$this表示调用此方法的已实例化的对象。
用$this->var或者$this->function的形式来访问该对象的方法或属性。
那么这里
声明类属性或方法为 static(静态),就可以不实例化类而直接访问。
public static function staticimage($center)
public function map(){
return \Map::staticimage(‘北京昌平沙河地铁‘);
}
就像这里可以直接在Index/map中直接调用extend/Map.php中的静态方法。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
<?php
class Foo {
public static $my_static = ‘foo‘;
public function staticValue() {
return self::$my_static;
}
}
print Foo::$my_static . PHP_EOL;
$foo = new Foo();
print $foo->staticValue() .
PHP_EOL;
?>
执行以上程序,输出结果为:
foo
foo