在之前的文章中给大家带来了《怎样去搞定PHP类的继承?(总结分享)》,其中详细介绍了在PHP类中有关继承的相关知识,本篇我们继续来看一下PHP命名空间的相关知识,希望对大家有帮助!
命名空间其实是个抽象的概念,举个例子,在我们日常生活中,操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。
那么什么是命名空间呢?其实,命名空间可以理解为封装事物的方法,在PHP中的类、函数、常量是不能够同名的,为了不让他们同名,解决三者的同名问题,所以需要用到命名空间。
在PHP中,命名空间主要用来解决用户编写的代码与PHP内部或者第三方的类、函数、常量之间的命名冲突,文件太多的时候总会有可能命名会重复;还有为很长的标识符名称创建一个很简短的名称,这样的话会提高代码的可读性。
那么命名空间是怎样声明也就是定义和使用的呢?接下来我们来看一下应该如何定义命名空间吧!
定义命名空间
在PHP中任意正确的代码都可以包含在命名空间中,但是只有类、函数、常量等类型的代码才会收到命名空间的影响。
我们通过namespace
关键字来完成命名空间的定义,它的语法格式如下:
namespace 命名空间名;
示例如下:
<?php // 定义代码在 'named' 命名空间中 namespace named; //在这里可以不使用大括号 // ... 代码 ... ?>
-
定义两个命名空间:
<?php namespace MyProject { //这里建议大家使用大括号,这里定义了一个名为MyProject的命名空间 const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace Another { //这里定义了一个名为Another的命名空间 const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } ?>
-
定义子命名空间
PHP中的命名空间与目录和文件的关系是很像的,可以允许指定层次化的命名空间名称。因此,命名空间的名字可以使用分层次的方式来定义,它的语法格式如下:
namespace AppModel; namespace AppControllerHome;
示例如下:
<?php namespace MyProjectSubLevel; //声明分层次的单个命名空间 const CONNECT_OK = 1; class Connection { /* ... */ } function Connect() { /* ... */ } ?>
在上述事例中,创建了常量 MyProjectSubLevelCONNECT_OK,类 MyProjectSubLevelConnection 和函数 MyProjectSubLevelConnect
-
在同一个文件中,定义多个命名空间
我们有两种语法格式可以在一个文件中定义多个命名空间,示例如下:
首先就是简单的语法组合
<?php namespace named; const CONNECT_OK = 1; class className { /* ... */ } namespace names; const CONNECT_OK = 1; class className { /* ... */ } ?>
然后就是大括号{}
<?php namespace named{ const CONNECT_OK = 1; class className { /* ... */ } } namespace names{ const CONNECT_OK = 1; class className { /* ... */ } } ?>
通过上述的介绍,我们已经知道了应该如何定义命名空间,只是定义命名空间还不够,我们在PHP中使用它才是比较重要的,那接下来看一下应该如何使用命名空间。
使用命名空间
在了解应该如何使用命名空间之前,我们应该要了解的是在PHP中是怎么知道要是用哪一个命名空间中的元素的,这时候我们就需要知道PHP中命名空间元素访问的原理了。首先PHP中的我们不太清楚,但是文件系统我们可以总结出访问文件的三种方式:
相对文件名、相对路径名和绝对路径名。
PHP命名空间的元素只用同样的原理,例如命名空间下的类名可以通过三种方式引出:
-
非限定名称,或不包含前缀的类名称,例如
$a = new test()
或者test
,如果当前命名空间是currentnamespace
,那么test将被解析为currentnamespacetest
。如果test的代码是全局的,不包含任何命名空间中的代码,那么test会被解析为test。 -
限定名称,或包含前缀名称,例如
$a = new subnamespacetest()
,如果当前命名空间是currentnamespace
,则 test 会被解析为currentnamespacesubnamespacetest
,如果test的代码是全局的,不包含任何命名空间中的代码,那么test会被解析为subnamespacefoo
。 -
完全限定名称,或包含了全局前缀操作符的名称,例如
$a = new currentnamespacetest()
,这种情况下,test 总是被解析为代码中的文字名currentnamespacetest
。
下面是一个使用这三种方式的实例,我们需要两个 PHP 源文件,分别是 demo.php
和 index.php
,示例代码如下:
<?php namespace TestBarDemo; const FOO = 1; function foo() {} class foo { public function demo() { echo '命名空间为:TestBarDemo'; } } ?>
<?php namespace FooBar; include 'Demo.php'; const FOO = 2; function foo() { echo 'FooBar 命名空间下的 foo 函数<br>'; } class foo { static function demo(){ echo '命名空间为:FooBar<br>'; } } /* 非限定名称 */ foo(); // 解析为 FooBarfoo resolves to function FooBarfoo foo::demo(); // 解析为类 FooBarfoo 的静态方法 staticmethod。 echo FOO.'<br>'; // 解析为常量 FooBarFOO /* 限定名称 */ Demofoo(); // 解析为函数 FooBarDemofoo Demofoo::demo(); // 解析为类 FooBarDemofoo, // 以及类的方法 demo echo DemoFOO.'<br>'; // 解析为常量 FooBarDemoFOO /* 完全限定名称 */ FooBarfoo(); // 解析为函数 FooBarfoo FooBarfoo::demo(); // 解析为类 FooBarfoo, 以及类的方法 demo echo FooBarFOO.'<br>'; // 解析为常量 FooBarFOO ?>
在上述事例中,我们需要注意的是,访问任意全局类、函数或常量,都可以使用完全限定名称,例如 strlen()
或 Exception
等。
别名、导入
PHP 允许通过别名引用或导入的方式来使用外部的命名空间,这是命名空间的一个重要特征。
在PHP中,通过use
关键字和as
配合可以实现命名空间的导入和设置别名。它的语法格式如下:
use 命名空间 as 别名;
示例如下:
<?php namespace foo; use MyFullClassname as Another; // 下面的例子与 use MyFullNSname as NSname 相同 use MyFullNSname; // 导入一个全局类 use ArrayObject; // 导入一个函数 use function MyFullfunctionName; // 导入一个函数并定义别名 use function MyFullfunctionName as func; // 导入一个常量 use const MyFullCONSTANT; $obj = new namespaceAnother; // 实例化 fooAnother 对象 $obj = new Another; // 实例化 MyFullClassname 对象 NSnamesubnsfunc(); // 调用 MyFullNSnamesubnsfunc 函数 $a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象 // 如果不使用 "use ArrayObject" ,则实例化一个 fooArrayObject 对象 func(); // 调用 MyFullfunctionName 函数 echo CONSTANT; // 打印 MyFullCONSTANT 常量 ?>
其中需要注意的是,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
大家如果感兴趣的话,可以点击《PHP视频教程》进行