php命名空间与自动加载

来源:转载

命名空间概述

在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:
1、用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
2、为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

定义命名空间

虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits)、接口、函数和常量。
命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间,除了一个以外:declare关键字。

定义子命名空间

与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:
namespace 后面不可直接跟 /,如:namespace /MyProject/Sub/Level;

namespace MyProject/Sub/Level;const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }

在同一个文件中定义多个命名空间

简单组合语法(不建议)

namespace MyProject;const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }namespace AnotherProject;const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }

大括号语法

namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ }}namespace AnotherProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ }}

在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。这种方式的主要用于将多个 PHP 脚本合并在同一个文件中。

将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来,例如:(除了开始的declare语句外,命名空间的括号外不得有任何PHP代码。)

declare(encoding='UTF-8');namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ }}namespace { // global code session_start(); $a = MyProject/connect(); echo MyProject/Connection::start();}

使用命名空间:基础

在讨论如何使用命名空间之前,必须了解 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、非限定名称,或不包含前缀的类名称(Unqualified name, or an unprefixed class name),例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为 currentnamespace/foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。( 如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。类名称总是解析到当前命名空间中的名称。)
2、限定名称,或包含前缀的名称(Qualified name, or a prefixed class name),例如 $a = new subnamespace/foo(); 或 subnamespace/foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace/subnamespace/foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace/foo。
3、完全限定名称,或包含了全局前缀操作符的名称(Fully qualified name, or a prefixed name with global prefix operator),例如, $a = new /currentnamespace/foo(); 或 /currentnamespace/foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name) currentnamespace/foo。

命名空间与自动加载

PHP命名空间与自动装载没有直接联系,只不过通常是使用命令空间与目录文件路径的规则来装载类文件,所以表面上好像有点关系。其实没有任何联系的。命令空间规则只是加载文件的一种方式。自动加载可以使用你自定义的任何方式加载文件,只要能找到这个文件即可。

使用命名空间只是让类名有了前缀,不容易发生冲突,系统仍然不会进行自动导入。
如果不引入文件,系统会在抛出 “Class Not Found” 错误之前触发 自动加载函数,并将限定类名传入作为参数。

PSR-4 是关于由文件路径自动载入对应类的相关规范,规范规定了一个完全限定类名需要具有以下结构:
/<顶级命名空间>(/<子命名空间>)*/<类名>
PSR-4 规范中必须要有一个顶级命名空间,它的意义在于表示某一个特殊的目录(文件基目录)。子命名空间代表的是类文件相对于文件基目录的这一段路径(相对路径),文件基目录可以再在自动加载函数中自行定义,类名则与文件名保持一致(注意大小写的区别)。

自动加载类参考:
http://www.php-fig.org/psr/psr-4/
http://www.php-fig.org/psr/psr-4/examples/
http://www.bubuko.com/infodetail-557809.html

loadClass方法:

【不同插件(composer进来的)的基目录在哪定义?DI(如laravel)是在何处触发autoload的?】

use

允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类 unix 文件系统中可以创建对其它的文件或目录的符号连接。
所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。
PHP 5.6开始允许导入函数或常量或者为它们设置别名。
use并不require文件,而是在某一行使用时(new),触发autoload(如果之前没有定义)。

//use 调用函数,函数需在命名空间下直接定义(不是class的方法)// importing a function (PHP 5.6+)use function My/Full/functionName;// aliasing a function (PHP 5.6+)use function My/Full/functionName as func;NSname/subns/func(); // 调用函数 My/Full/NSname/subns/funcfunc(); // calls function My/Full/functionName

具体见:http://php.net/manual/zh/language.namespaces.importing.php,翻译有个bug:

参考

php.net
PHP命名空间与自动装载
PHP 命名空间与自动加载机制介绍
PHP命名空间及自动加载浅析
php使用命名空间:导入导出之疑问

分享给朋友:
您可能感兴趣的文章:
随机阅读: