命名空间
思考:在php中,函数类和常量都是不允许同名的,一旦同名就会出现冲突。但是在大型项目开发中,团队开发很难避免出现同名结构,此时就会出现同名冲突
解决的方案只能是刻意去控制不同名吗?
引入:从开发角度出发,最好的办法就是保证不同名。这样的效率和效果都是最好的,但是在大型项目中,不同团队负责的模块可能不同,那么此时就很难保证出现不同名了,
因此这个时候就需要引入一种命名空间机制来保证,即使出现了同名结构也不影响整个项目。
命名空间基础【掌握】
定义:命名空间namespace,是指认为将内存进行分割,让不同内存区域的同名结构共存,从而解决在大型项目中可能出现的重名结构问题。
1.基本语法 nameapace 空间名字
<?php namespace my_space; //定义一个叫做my_space的空间
2.命名空间的命名规则
由字母、下划线和数字构成
可以以字母和下划线开头
较少出现多单词空间名,一个使用下划线法
3.命名空间的作用:能够创建同名结构,包含函数,常量和类
<?php namespace my_space; //定义一个叫做my_space的空间 function show(){ echo __METHOD__; } namespace my_space2; $name='30'; class posen{ function show(){ echo '同名的函数,也不报错'; } }
注意,在一个空间中不可以重名。
4.命名空间里面的内容
命名空间里面可以定义同名函数、常量和类(结构),因此类结构不允许同名,这些是命名空间规范的目标(称为空间元素)
命名空间里面可以有其他代码
<?php namespace my_space; //定义一个叫做my_space的空间 function show(){ echo __METHOD__; } namespace my_space2; $name='30'; //变量 echo $name; //变量输出 class posen{ //类 public $name='杜'; //类属性 function show(){ //类成员 echo '同名的函数,也不报错'; } }
5.命名空间注意事项:命名空间的声明(第一次)必须在所有代码之前
<?php namespace my_space; //命名空间之前不能有任何代码
<?php $age=666; namespace my_space; //错误,第一次命名空间之前不能有任何代码
注意:命名空间在一个脚本中只会定义一个(最开始),但是在讲课的时候可能会定义多个
总结
1.命名空间是使用namespace+空间的名称
2.不同命名空间可以定义同名函数、常量和类(同名结构)
3.命名空间里可以书写任意代码
4.命名空间的定义必须在脚本的最前面
5.一个脚本中通常只会定义一个空间
6.命名空间其实就好比是磁盘上划分不同文件夹,用来保存同名文件
思考:命名空间既然是用来划分空间的,那么能否像文件夹层级那样?实现多层级的命名空间呢?
引入:命名空间本身就是建立一种虚拟的“围栏”,用来区分不同位置的同名结构,既然可以在内存中设置一层“围栏”,那么自然也可以设置多层,
这个就叫做子空间
命名空间子空间【掌握】
定义:子空间,既在已有的空间上,再在内部进行空间划分,让每个小空间独立起来
1.命名空间子空间是直接通过namespace+路径符号\ 实现
<?php namespace my_space; //创建一个一级空间 function display(){}; //创建一个子空间 namespace my_space\child; //在my_space空间下创建一个子空间child function displat(){};
2.子空间的创建不一定非要在前面创建了上级空间,即可以直接在某个脚本中创建子空间
namespace space\parent; function display(){};
总结:
1.子空间也是通过namespace实现,用namespace+路径\区分上下级空间名
2.基于一个脚本中通常只有一个空间名,所以子空间的创建可以直接创建(不用一定先创建一级空间)、
3.子空间理论上可以创建无限层级,但是实际层级根据项目需求确定(一般不超过四层)
思考:有了命名空间后,可以在同一个文件里定义不同空间,然后出现同名结构,那如何进行访问呢?
引入:其实空间就像文件夹一样,同一个文件里不能有同名文件,但是不同文件夹下肯定可以出现同名文件的,而
如果进行访问的话,就需要进入到不同的空间进行访问。
空间元素访问【掌握】
定义:命名空间访问,是指访问不同空间里的结构元素,如果空间里有除了函数、常量和类的其他代码,会自动执行
只有空间元素本身(函数、常量和类)是需要通过空间进行访问的,在php命名空间中,提供了三种空间元素的访问方式:
非限定名称,限定名称和完全限定名称。
1.非限定名称访问:即直接访问空间元素的名字,此类访问的是当前代码所属空间内的元素
<?php namespace my_space; function show(){ echo __FUNCTION__; } namespace my_space3; function show(){ echo __FUNCTION__; } //访问空间元素:非限定名称(直接使用结构名字) show(); //显示的是my_space3 show 调用show函数是在my_space3空间下
注意:非限定名称访问就好比是访问当前自己文件夹下的所有文件
2.限定名称访问,即在访问元素的前面使用相应的空间名字,非限定名称的访问时基于子空间来实现的
<?php //定义子空间 namespace my_space\files; function show(){ echo __FUNCTION__; } //定义子空间 namespace my_space\files1; function show(){ echo "我是files1子空间"; } //定义父空间 namespace my_space; function show(){ echo "我是父空间"; } show(); //父空间访问 files\show(); //子空间files 实际为当前空间my_space+files\show()
注意:限定名称访问好比访问当前文件夹下的子文件夹内容
3.完全限定名称访问,即从根鲁姆(全局)开始访问,使用\作为全局空间开始符号
<?php //定义子空间 namespace files; function show(){ echo __FUNCTION__; } //定义子空间 namespace files1; function show(){ echo "我是files1子空间"; } //定义父空间 namespace my_space; function show(){ echo "我是父空间"; } //在房钱my_space空间下 使用全局限定来访问files中的show结构 \files\show(); //使用 \开始符号 全局限定 返回files show
注意:完全限定名称访问好比从磁盘根目录访问对应路径下的内容(绝对路径)
总结:
1.命名空间的访问分为三种模式
非限定名称访问:直接访问元素本身,代表当前所属空间(当前目录)
限定名称访问:使用空间名+元素,代表访问当前空间子空间(当前目录子目录)
完全限定名称访问:使用全局空间开始,代表从全局开始进行访问(根目录)
思考:是不是有了命名空间,所有的文件都必须指定空间,如果不指定会怎么样?
引入:并非所有情况下都需要使用命名空间,命名空间时针对有些可能出现重名的内容时,才会使用的
另外,如果不使用命名空间,本质系统也认为使用了空间,这就是全局空间
全局空间【掌握】
定义:全局空间,即空间元素在没有定义空间的情况下所属的空间,也是所有定义的空间的顶级空间,(即所有空间都是从全局空间分离出来的)
1.没有指定空间的元素所属空间属于全局空间
<?php function show(){ echo __NAMESPACE__; } show(); //输出无 全局空间没有名字
2.所有空间本质都是在全局空间下划分的
<?php namespace space; function show(){ echo __NAMESPACE__; } show(); //space空间属于从全局空间划分一部分用于space空间管理
3.全局空间元素访问,使用完全限定名称访问
<?php function show(){ echo __NAMESPACE__; } show(); //非限定名称访问:本身当前就是全局空间内,所以可以访问 \show(); //完全新丁名称访问,全局符号\+全局空间元素
4.一旦命名空间出现,那么空间元素(类,常量和函数)的访问就被限定在空间内,如果使用非限定名称访问,那么系统会以下解析(限定名称或者完全限定名称是直接按路径准确找)
首先,一定是在自己的空间内查找
如果找不到元素,不同空间元素的处理不同
系统常量,系统函数如果找不到,会自动去全局空间找(也就是能找到)
系统类是不会自动去全局空间找的(报错,提示当前所属空间元素找不到)
<?php namespace space; //访问空间元素 常量 echo PHP_VERSION; //输出7.0.10 为什么能输出,我当前没有定义这个常量,它会去全局空间找 //空间元素——函数访问 echo count(array(1,2,3,4)); //返回4,现在当前空间下找,找不到去找全局空间 //访问空间类 $conn=new mysqli('localhost','root','root','senven',3306); //报错 非限定类访问不允许 //如果想访问需要使用全局限定名称 $conn=new \mysqli('localhost','root','root','senven',3306);
5.同样的,如果一个文件有空间,包含了一个没有空间的文件,那么要访问文件中的内容,需要使用全局空间
<?php //space01.php文件 //属于全局空间 function show(){ echo __FILE__; }
<?php namespace sppace; //包含无空间文件 include 'space01.php'; show(); //可以访问 访问是sppace空间下的show函数
<?php namespace sppace; include 'space01.php'; show(); //可以访问 访问space下的空间show函数 \show(); //正确,访问全局空间下的show函数 //注意:如果space空间没有show的话,直接访问show函数也是正确的,因为系统会自动寻找全局空间
总结:
1.全局空间就是没有使用namespace定义的空间(所有空间本质都是在全局空间下划分)
2.全局空间的元素访问使用完全限定名称访问
3.系统内置的函数,常量和类都属于全局空间
系统 函数,常量在空间内访问的时候系统会自动在自己空间找,如果找不到会去全局空间找
系统类必须使用全局空间访问:\类名
思考:既然前面说过一个脚本中通常只会定义一个空间,那么怎么会出现这么多种访问方式呢?
引入:上述案例只是为了知识本身的规则,在实际应用中一个脚本只会有一个空间,因为一个脚本中通常只有一个类或者一些函数(功能函数)
但是因为开发的结构性,不同文档所属的功能是不同的,因此也是存放在不同的文件夹的,因此在实现业务的时候会进行文件包含,也就会产生空间包含的问题
所有就会需要多种访问方式来进行访问。
命名空间应用【掌握】
定义:命名空间应用是模拟真实的开发环境,来运用命名空间的规则
1.创建文件夹:模拟项目不同文件php文件放到不同文件夹下
--|root -------根目录
--|--|controller ------业务模块
--|--|model ----数据模块
--|--|core ------核心工具
2.业务说明
root根目录:存放用户可以直接访问的文件,文件都是请求controller里的文件
controller目录:存放业务逻辑文件,所有业务都是类文件,业务要操作数据库,请求model里的文件,属于controller空间
model目录:存放数据库操作的类文件,一张表一个类文件,属于model空间
core目录:核心工具的存放,属于core空间
注意:层层相关,层级结构概念,首先写一个用户操作相关的,需要调用core中的数据库查询(只是个工具),在model数据模型中来想数据库操作(select* from user ),
在业务逻辑中对model中查询出来的数据进行操作。。。。。。。
3.创建3个文件:分别代表root目录里下(不需要空间),controller目录下,controller空间,model目录下的model空间
//core
core/DB_class.php <?php //属于核心空间 namespace core; class DB{ public function __construct(){ echo '实现了数据的初始化操作<br>'; } public function query($sql){ echo '能够实现数据的查询<br>'.$sql; } }
//model
model/User_class.php <?php //属于数据模块空间 namespace model; //使用core下的操作数据库的类 include_once 'D:\wamp\www\root\core\DB_class.php'; class User{ public function getAllUser(){ $sql='select * from user'; //查询所有的访问 // $user =new DB(); //非限定名称,在model下面找,找不到 错误 // $user=new core\DB(); //限定名称在model下找core找db 找不大 错误 $user=new \core\DB(); return $user->query($sql); } }
//controller
control/User_class.php <?php //定义空间 namespace controller; //调用模型目录下的user类实现数据库操作:使用完全限定名称来访问 include_once 'D:\wamp\www\root\model\User_class.php'; //业务逻辑模块 //显示用户数据 class User{ public function index(){ //获取用户表的数据 $user=new \model\User(); $s=$user->getAllUser(); echo '实现了用户的业务操作<hr>'.$s; } }
//入口文件
root/index.php <?php //入口文件 //找到controller中对应的User_class.php include_once 'controller/User_class.php'; $u=new controller\User(); $u->index(); //返回了数据 //实现了数据的初始化 //能够实现数据的查询 //select * from user 实现了用户的业务操作
代码说明:
index.php在root目录下没有定义空间,内部元素属于全局空间,index.php包含了子目录controller下的User_class.php,而User类属于controller空间,所以在index.php中访问User类的时候,
可以使用限定名称(全局的i空间controller\空间元素),或者完全限定名称(\controller\空间元素)
controller/User_class.php在root\controller文件夹下,定义了空间controller,所以文件里面所有访问,默认都在controller下找,controller/User类中用到了model\User类,所以需要使用完全限定名称访问
(同级别不同空间)\model\User
model/User_class.php在root\model文件夹下,定义了model空间,所以文件里面所有访问,默认都在model下面找,model/User类中用到了core\DB类,所以需要使用全局限定名称访问\core\DB
core\DB_calss.php在root/core文件夹下,定义了空间core
总结:
空间的实际应用是以文件为单位定义空间的
空间的划分是按业务对应的脚本进行划分的,如业务controller,数据model等
文件的包含和空间的包含没有联系,二者都是独立的,文件是在加载文件时,而空间在进入内存后
空间应用,通常是采用非限定名称(自己空间里)和完全限定名称访问(其他空间)
思考:在实际应该开发中,几乎所有文件都有空间,在进行访问的时候每次都需要使用完全限定名称太麻烦了,有没有什么好的方式呢?
引入:实际开发中,一般都会进行优化,不会直接使用完全限定名称访问的,并且考虑到继承之类,会出现各种文件包含和空间交互,因此
为了能够简单的时候,可以采用空间元素引入
命名空间引入【掌握】
定义:命名空间引入其实就是将另外一个空间的元素(类,函数和常量)引入到当前空间来,当作当前空空间元素访问,从而可以减少复杂的完全限定名称访问,取而代之的是非限定名称
访问的方式
1.空间引入的方式:use关键字
<?php namespace space1; class man{ public $name="小伟"; public function show(){ echo $this->name; } } namespace space2; //使用完全限定名称方式访问太过麻烦 // $obj=new \space1\man(); // $obj->show(); //使用use关键字引入空间元素 use space1\man; $obj=new man(); $obj->show();
注意:use进行空间包含的时候,默认是从全局空间开始构建空间路径的(不是自己空间的相对路径)所以上述的代码等价于下面的代码
namespace space2; //使用完全限定名称方式访问太过麻烦 // $obj=new \space1\man(); // $obj->show(); //使用use关键字引入空间元素 use \space1\man; $obj=new man(); $obj->show();
2.空间引入的元素默认是类,如果要引入其他元素,就必须使用相应的关键字:function和const
<?php namespace space1; //空间方法 function add(){ echo "我是空间add方法"; } //空间常量 const SEX='女'; //空间类 class man{ public $name="小伟"; public function show(){ echo $this->name; } } namespace space2; //引入空间元素类 use space1\man; //引入空间元素方法 use function space1\add; //引入空间元素常量 use const space1\SEX; //访问space2空间中的函数 add(); //常量 echo SEX;
3.如果被引用的元素在当前空间已经存在,则会出现重名,解决方案是使用别名 as alias
<?php namespace space1; //空间方法 function add(){ echo "我是空间add方法"; } //空间常量 const SEX='女'; //空间类 class man{ public $name="小伟"; public function show(){ echo $this->name; } } namespace space2; //此空间add function add(){ echo __METHOD__; } //由于空间space1中和space2中有同名方法 需要在引入元素的时候为方法起个别名 use function space1\add as s; s(); add();
注意:一旦引入的时候使用了别名,那么在使用的时候就直接通过别名使用
5.如果一个空间有多个元素要引入,那么可以进行一次引入多个使用逗号,分割即可
<?php namespace space1; //空间方法 function add(){ echo "我是空间add方法"; } function show(){ } //空间常量 const SEX='女'; //空间类 class man{ public $name="小伟"; public function show(){ echo $this->name; } } class wuman{ } namespace space2; //一次引入多个空间元素,如class function const 必须分开写 use space1\man,space1\wuman; //一次引用2个类 use function space1\add,space\show; //一次引入2个函数
注意:以上方式都是在引入同一种元素,如果要引入多个不同元素,可以如下使用
<?php namespace space1; //空间方法 function add(){ echo "我是空间add方法"; } function show(){ echo __METHOD__; } //空间常量 const SEX='女'; //空间类 class man{ public $name="小伟"; public function show(){ echo $this->name; } }; class wuman{ } namespace space2; //一次引入space1的类,函数和常量 use space1\{ man, function add, function show, const SEX }; //注意这个分号是必须的,表示一行结束。 show();
6.如果说确定一个空间的所有元素都需要引入进来,也可以直接引入空间
<?php namespace space1; //空间方法 function add(){ echo "我是空间add方法"; } function show(){ echo __METHOD__; } //空间常量 const SEX='女'; //空间类 class man{ public $name="小伟"; public function show(){ echo $this->name; } }; class wuman{ } namespace space2; //引入空间 use spcace1;
注意:如果直接进行空间引入,那么被引入的空间属于当前空间的一个元素,要访问引入空间的其他元素,得从引入空间开始,即引入的空间最后一级空间名字+元素(引入空间当作当前的空间子空间)
<?php namespace space1; //空间方法 function add(){ echo "我是空间add方法"; } function show(){ echo __METHOD__; } //空间常量 const SEX='女'; //空间类 class man{ public $name="小伟"; public function show(){ echo $this->name; } }; class wuman{ } namespace space2; //引入空间 use space1; //访问被引入空间中的元素 space1\add();
总结:
1.空间引入是解决访问时的麻烦,有完全限定名称变成非限定名称访问
2.空间元素都可以引入,但是引入方式有区别
类直接引入
函数需要在use之后添加关键字function
常量需要在use之后添加关键字const
3.空间引入过程中如果出现重名,需要使用别名来处理,引入后在空间里可以直接访问别名
4.可以一次性引入一个空间内的多个元素
5.如果必须的情况下,也可以直接使用空间引入,但是注意被引入空间的元素不允许直接使用非限定名称访问
必须使用被引入空间的最后一级空间+元素访问(不常使用,引入方便但是使用不方便)
引入名称空间的类、方法、常量
//引入命名空间的类、方法和常量 use \China\student; use const China\PI; use function China\show; show(); echo "<br>"; echo PI;
给引入的方法 类 常量去别名
//引入命名空间类,并且把这个类取个别名,防止类的重名 use \China\student as stu; $obj= new stu(); var_dump($obj);