1 命名空间
1.1 概述
<?php
namespace my\name;
class MyClass {}
function myfunction() {}
const MYCONST = 1;
namespace other\name
{
//...
}
$a = new MyClass;
$c = new \my\name\MyClass;
$a = strlen('hi');
$d = namespace\MYCONST;
$d = __NAMESPACE__ . '\MYCONST';
echo constant($d);
?>
上面展示了命名空间相关的概念,下面详细介绍每个点。
命名空间的定义比较简单,1 种方式为在页面的第一行定义 namespace name。若一页有多个命令空间则推荐使用C++语法的命名空间定义。
层次化命名空间的定义采用路径格式 level1\level2\level3
1.2 命名空间的使用
假定当前的命名空间为A,则当前空间中出现的名称在查找时,都从A\中开始查找,因此若当前命名空间中定义了与全局空间重名的变量,要访问全局空间的内容,需要\开始。除非当前命名空间中未定义,从而可以不需要从/开始。
对于没有定义于全局命名空间的东西,都存在于全局命名空间中。
对于动态使用命名空间的方法如下:
<?php
namespace namespacename;
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "namespaced";
include 'global.php';
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
/* note that if using double quotes, "\\namespacename\\classname" must be used */
$a = '\namespacename\classname';
$obj = new $a; // prints namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // also prints namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // prints namespacename\funcname
$b = '\namespacename\funcname';
$b(); // also prints namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // prints namespaced
echo constant('namespacename\constname'), "\n"; // also prints namespaced
?>
PHP使用__NAMESPCE__魔术变量及namespace\来保存当前命名空间的字符串,全局命名空间的字符串为空。
1.3 命名空间的导入
类似于C++,PHP使用use导入命名空间,同时支持以as的方式为长的命名空间起一个别名,为了简化,也支持一行导入多个命名空间。
<?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 对象
?>
1.4 命名解析
PHP对于不同的名字有不同的解析查找策略。
对于类而言,仅仅查找当前命名空间中类的命名,若要访问全局命名的类,则需要按完全限定的方式从根\声明。
对于函数和常量而言,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。
1.5 名称解析规则
- 对完全限定名称的函数,类和常量的调用在编译时解析。例如 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。
- 在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。
- 尝试自动装载类 A\B\D\E。
2 异常
PHP中引入了类似JAVA等的异常,使用都大同小异,若用户未捕获异常,代码会产生一个异常未捕获的错误,用户可以定义set_exception_handler()方法来处理这些异常。
用户定义的异常最好能初始化内置异常。
class MyException extends Exception
{
// 重定义构造器使 message 变为必须被指定的属性
public function __construct($message, $code = 0) {
// 自定义的代码
// 确保所有变量都被正确赋值
parent::__construct($message, $code);
}
// 自定义字符串输出的样式
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "A Custom function for this type of exception\n";
}
}