命名空间概念:
具体举个例子就明白了,在windows系统中文件 foo.txt 可以同时在目录/home/greg 和 /home/other 中存在,但在同一个目录中不能存在两个 foo.txt 文件。对比于程序中,一样的概念,同一个脚本中,出现同样的类名,常量名,函数名等,会报致命错误,命名空间解决了这一问题。
当然,我们可以在编写代码时,避免出现重名的问题,但是当使用第三方插件时,则很可能遇到,所以在项目初期还是要规划好命名空间。
命名空间用来解决的问题:
1、用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
2、为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
注意事项:
1、只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits)、接口(interface)、函数和常量。
2、在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。另外,所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。
3、访问任意全局类、函数或常量,都可以使用完全限定名称,例如 \strlen() 或 \Exception 或 \INI_ALL。这样可以避免与当前执行脚本方法区分开来。
一、使用命名空间
1、同一个文件中并不提倡使用定义多个命名空间,这里不做介绍,了解可查看官网,http://php.net/manual/zh/language.namespaces.definitionmultiple.php
2、使用命名空间:基础
类名可以通过三种方式引用:
方式 | 描述 | 不包含命名空间PHP解析 | 包含命名空间PHP解析 |
---|---|---|---|
非限定名称 | 不包含前缀的名称eg: $a=new foo(); 或 foo::test(); | foo 会被解析为foo | 如果当前命名空间是 Search,foo 将被解析为 Search\foo, 如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称 |
限定名称 | 包含前缀的名称eg:$a = new user\foo(); 或 user\foo::test(); | foo 会被解析为user\foo | 如果当前的命名空间是 Search,则 foo 会被解析为 Search\user\foo |
完全限定名称 | 包含了全局前缀操作符的名称eg:$a = new \user\foo(); 或 \user\foo::test(); | foo 总是被解析为user\foo | foo 总是被解析为user\foo |
eg:
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
foo::staticmethod(); // 解析为类 Foo\Bar\foo的静态方法staticmethod。
echo FOO; // 解析为 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
3、__NAMESPACE__
常量__NAMESPACE__
的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
二、命名空间和动态语言特征
所谓命名空间的动态,就是一个变量接收路径,例如$a = '\namespacename\classname';
。
动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,全部被解析成完全限定名称,因此其前导的反斜杠是不必要的。
eg:
文件1.php
<?php
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "global";
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
文件2.php
<?php
namespace namespacename;
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "namespaced";
include '1.php';
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
$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
三、使用命名空间:别名/导入
这里的导入/别名指的是导入/别名"命名空间",三种别名或导入方式:
1、为类名称使用别名
2、为接口使用别名
3、为命名空间名称使用别名。
注意事项:
1、PHP 5.6开始允许导入函数或常量或者为它们设置别名。
2、前导的反斜杠是不必要的也不推荐的,因为导入的名称必须是完全限定的,不会根据当前的命名空间作相对解析。
导入用use ...
,导入+别名用 use ... as
eg:
test1.php文件
<?php
namespace Demo2;
require('test2.php');
use Demo1;
use function Demo1\test as test1;
function test(){
echo 5;
}
class test{
function test(){
echo 4;
}
}
test1();//输出1
echo '<hr>';
echo namespace\test();//输出5
echo '<hr>';
$test = new Demo1\test();//输出2
test2.php文件
<?php
namespace Demo1;
function test(){
echo 1;
}
class test{
function __construct(){
echo 2;
}
public function test(){
echo 3;
}
}