命名空间的作用与适用对象
require 'inc/funciton.php';
function func1($a,$b){
return $a.' + '.$b.' = '.($a+$b);
}
// 直接调用会出现函数未定义错误
echo fun1(10, 20);
echo '<hr>';
// 如果想访问外部加载的函数func1,就要带上命名空间
echo \my\func1(10, 20); // 做的乘法
echo '<hr>';
// 而如果还想访问在当前脚本中定义的函数func1,也要用命名空间访问
echo \func1(10,20); // 加法
// 命名空间解决了什么问题呢?
// php 全局成员的命名冲突的问题
// 全局成员, 是指在当前脚本中,并不受使用域的限制,总是可以访问的
// php 中哪些是全局成员呢? 类, 函数, 常量
// 因为这三个成员, 不受作用域的限制, 所以无法像变量那样,用作用域对他们的可见性进行区隔
// 所以对于全局成员, 我们之前是通过一个很长的名称来进行区分, 例如: my_func1, 难写难记
// 使用命名空间, 可以防止命名恐惧症, 在开发中可以使用相同名称的全局成员,只要放在不同的空间中即可
// 例如, 合肥有条长江路, 上海也有一条长江路, 在合肥提到长江路, 不会有人想到这是上海的长江路,这是因
// 为我们用城市名称, 做了区隔, 因为这二条路有不同的命名空间, 分别是合肥和上海
// 类似电脑中的文件, 例如有二个index.php文件,只要他们不在同一个目录下,就不会有命名冲突
// admin/index.php 和 home/index.php , 尽管文件同名,但用户不会认为这是同一个文件
// 引用的时候,必须带上他们所在的路径即可
funciton.php示例 // 使用较长的命名来进行区分 function my_func1($a, $b){ return $a.' * '.$b.' = '.($a*$b); } // 使用命名空间, 不改变原来的函数名称 namespace my; function func1($a, $b){ return $a.' * '.$b.' = '.($a*$b); }
namespace: 创建命名空间, 必须是脚本的第一行代码// 定义空间one namespace one; // 在one空间中定义三个全局成员 class Pig {} function hello(){ return 'Hello 欧阳克'; } const SITE = 'php.cn'; // 访问成员 echo Pig::class . '<br>'; // 完整类名 echo hello() . '<br>'; echo SITE . '<hr>'; /*************************************************/ // 定义命名空间: two namespace two; class Pig {} function hello(){ return 'Hello 黄蓉'; } const SITE = 'php中文网'; echo Pig::class . '<br>'; // 完整类名 echo hello() . '<br>'; echo SITE . '<br>'; // 如果要在当前空间下面, 访问其它空间的成员, 例如one空间 // 与文件系统类似,从根空间开始,根空间: "\" echo '<br>'; echo \one\Pig::class . '<br>'; // 完整类名 echo \one\hello() . '<br>'; echo \one\SITE . '<hr>'; // 尽管可以在一个脚本中, 可以声明多个命名空间,但并不推荐这样去做 // 使用本例的方法, 在同一个脚本中声明多个空间,但无法自定义根空间成员,只能调用 // 如何才能在一个脚本中, 既可以自定义命名空间, 也可以自定义根空间成员呢? // 使用下个案例的大括号可以解决
namespace {}: 命名多个命名空间namespace one{ class Pig {} function hello(){ return 'Hello 朱老师'; } const SITE = 'php.cn'; // 访问成员 echo Pig::class . '<br>'; // 完整类名 echo hello() . '<br>'; echo SITE . '<hr>'; } namespace two{ class Pig {} function hello(){ return 'Hello 猪哥'; } const SITE = 'php中文网'; echo Pig::class . '<br>'; // 完整类名 echo hello() . '<br>'; echo SITE . '<br>'; // 在空间two中访问one空间 echo '<br>'; echo \one\Pig::class . '<br>'; // 完整类名 echo \one\hello() . '<br>'; echo \one\SITE . '<hr>'; } // 定义全局空间, 空间名称为空,表示全局空间 namespace{ class Pig {} function hello(){ return 'Hello 灭绝师太'; } const SITE = '学习交流分享的平台'; } namespace three{ // 调用全局成员 echo \Pig::class . '<br>'; // 完整类名 echo \hello() . '<br>'; echo \SITE; }
namespace: 引用当前命名空间__NAMESPACE__: 当前空间名称字符串(魔术常量)one\two\three\...\ClassName: 类空间的分层管理namespace think; class Dog {} echo Dog::class . '<hr>'; // 双下划线开头的魔方常量, 所谓魔术是指,尽管是常量,但可以随作用域发生变化 echo __NAMESPACE__ . '<br>'; namespace think\admin; echo __NAMESPACE__ . '<br>'; class Dog {} echo Dog::class . '<hr>'; // 如果我想访问空间:think\admin\model\Dog类 // 可以将当前空间看成当前目录,用关键字namespace来引用当前空间 echo namespace\model\Dog::class . '<hr>'; namespace think\admin\model; echo __NAMESPACE__ . '<br>'; class Dog {} echo Dog::class . '<hr>'; // "\"是命名空间分隔符, 将空间分层有什么卵用呢? // 作用非常大, 现代PHP编程中的类的自动加载技术就靠它撑着呢,框架没有它, 难以想像 // 多层级的命名空间,非常像多层级的目录结构,如果类名称中的空间部分与类文件的绝对路径一致,就可以实现 // 类文件的全自动加载,并且不会千万命名冲突,因为类名本身仍是带有命名空间的
class1示例
namespace code\inc;
class Class1{
}
class2示例
namespace code\inc;
class Class2{
}
传统方式
require 'inc/class1.php';
require 'inc/class2.php';
$obj1 = new \code\inc\Class1();
$obj2 = new \code\inc\Class2();
echo get_class($obj1) . '<br>'; //code\inc\Class1
echo get_class($obj2) . '<br>'; //code\inc\Class2
echo '<hr>';
str_replace(): 字符串替换函数,将空间分隔符替换成路径分隔符DIRECTORY_SEPARATOR: 路径分隔符常量spl_autoload_register(): 自动加载函数$path = str_replace('\\', '/', 'code\inc\Class1'); echo $path . '<br>'; $path = __DIR__ . '/../' . $path . '.php'; echo $path . '<br>'; echo '<hr>'; spl_autoload_register(function ($class){ // 这里将"\"替换成路径分隔符, 推荐使用常量:DIRECTORY_SEPARATOR,而不是"/",可苑跨平台支持 $path = str_replace('\\', DIRECTORY_SEPARATOR, $class); // 相对路径 // $path = $path . '.php'; // 绝对路径 $path = __DIR__ . '/' . $path . '.php'; // 不是文件或文件不存在,则抛出异常 if (!(is_file($path) && file_exists($path))) { throw new \Exception('不是文件或文件不存在'); } require $path; }); $obj1 = new inc\Class1(); $obj2 = new inc\Class2(); echo get_class($obj1) . '<br>'; //code\inc\Class1 echo get_class($obj2) . '<br>'; //code\inc\Class2
use namespace/className: 通过use关键字导入空间别名
为较长的类名提供一种简化方案
导入空间别名默认从全局空间开始
导入空间别名, 不能代替外部文件的加载
注意很多框架采用了自动加载技术,会导致一些同学误以后use可以加载类
use: 解决类名过长的问题
as: 解决导入的类别名与当前空间类重名问题
允许通过别名引用或导入外部的完全限定名称
index.php示例 namespace current; include 'inc/class1.php'; // 如果要使用Class1类,需要先实例化 $obj = new \inc\class1(); $obj = use \inc\Class1 AS C1; // 别名,解决重名 echo get_class($obj) . '<br>'; echo '<hr>';