PHP面向对象:命名空间

转载于:黑马程序员武汉中心

命名空间

学习目标:理解命名空间的概念,掌握命名空间存在的价值以及解决的实际问题,利用命名空间实现复杂项目开发

  • 命名空间基础
  • 子空间
  • 命名空间访问
  • 全局空间
  • 命名空间引入

概念

命名空间:namespace,指人为的将内存进行分隔,让不同内存区域的同名结构共存,从而解决在大型项目中可能出现的重名结构问题

  • PHP中,同一脚本运行周期内不允许出现同名结构
    • 常量
    • 函数
    • 类(接口)
  • 在大型项目中,除了使用复杂的命名方式,很难避免团队间使用同名结构
  • 命名空间可以通过给各类命名增加路径来实现不同名字的“本质不同”,从而允许同名存在

示例

在Windows系统下:同一个磁盘上不允许出现同名文件,但是可以通过路径的方式(文件夹)实现同名文件存

index.php
index(1).php			# 系统不允许同名,所以会重命名

但是我们可以通过不同的路径和逻辑分区来实现同名文件共同存在

C:/index.php
D:/index.php
D:/server/web/index.php	# 可以同时存在:路径本身可以理解为文件的名字(三个都不同)
  • 命名空间就是类似上述的操作,在同一块内存里进行逻辑分区实现同名结构的同时存在

小结

1、命名空间是为了解决结构同名问题而出现的一种解决方案

2、命名空间本质是在内存中进行逻辑划分,让相同的名字分到不同的区域,从而实现不同名

1、命名空间基础

目标:了解命名空间的基本语法,掌握命名空间的限制逻辑和基本应用

概念

命名空间基础:命名空间的基本语法和作用

  • 命名空间使用namespace关键字定义空间
namespace 命名空间名字;
  • 命名空间必须定义在所有代码之前(前面不能有任何代码性的内容,注释除外)
  • 命名空间后可以写任意内容,但是只有命名空间元素真正受空间限制
  • 命名空间元素是结构性内容(不允许重复的内容),有三类:
    • 常量
    • 函数
    • 类(接口)

步骤

1、确定使用命名空间:有一些结构性的内容可能与其他开发者冲突(重名)

2、在一开始定义命名空间

示例

1、基本语法:namespace 空间名字;

# 定义空间
namespace my_space;			# 定义一个叫做my_space的空间

2、命名空间的命名规则

  • 由字母、下划线和数字构成
  • 可以以字母和下划线开头
  • 较少出现多单词空间名,一般使用下划线法

3、命名空间的作用:能够创建同名结构,包含函数、常量和类

namespace space1;
function display(){
    echo __NAMESPACE__,'<br/>';
}
const PI = 3;
class Human{}

namespace space2;
function display(){
    echo __NAMESPACE__,'<br/>';
}
const PI = 3.14;
class Human{}

4、命名空间里的内容

  • 命名空间里可以定义同名的函数、常量和类(结构):因为此类结构不允许同名,这些是命名空间规范的目标(称为空间元素)
  • 命名空间里可以有其他代码
namespace space;
class Human{}
function display(){}
const PI = 3.14;
$a = 100;
echo $a;

5、命名空间注意事项:命名空间的声明(第一次)必须在所有代码之前

# 命名空间之前不能有任何代码
namespace space1;				# 正确
echo 'test';
namespace space1;				# 错误:第一次命名空间之前不能有任何其他代码

注意:命名空间在一个脚本中只会定义一个(最开始),但是在讲课的时候可能会定义多个

小结

1、命名空间是使用namespace + 空间名字定义

2、不同命名空间里可以定义同名的函数、常量和类(同名结构)

3、命名空间里可以书写任意代码

4、命名空间的定义必须在脚本的最前面

5、一个脚本中通常只会定义一个空间

6、命名空间其实就好比是磁盘上划分的不同文件夹,用来保存同名文件

2、命名空间子空间

目标:理解子空间的概念,掌握子空间的创建规范

概念

子空间:subspace,即在已有空间之上,再在内部进行空间划分,让每个小空间独立起来。

  • 子空间其实就是路径的分层
  • 子空间可以基于已有空间创建,也可以直接创建,使用反斜杠分隔\
# 基于已有父空间
namespace father;
namespace father\son;

# 直接创建子空间
namespace mother\daughter;

示例

1、命名空间子空间是直接通过namespace+路径符号\实现

namespace space;		# 创建一个一级空间
function display(){}

# 创建子空间
namespace space\space1;	# 在space空间下创建一个叫做space1的子空间
function display(){}

2、子空间的创建不一定非要在前面创建了上级空间,即可以直接在某个脚本中创建子空间

# 脚本最上面
namespace space\space2;
function display(){}

小结

1、子空间也是通过namespace实现,用namespace+\区分上下级空间名

2、基于一个脚本中通常只有一个空间名,所以子空间的创建可以直接创建

  • 不用一定先创建一级空间
  • 但是一般是存在上级空间的,而不是凭空创建子空间

3、子空间理论上可以创建无限多层,但是实际层次根据项目需求确定(一般不超过四层)

3、命名空间访问

目标:掌握命名空间的元素调用方式,能够用合适的方式调用空间元素

概念

命名空间访问:是指访问不同空间里的结构元素

  • 空间里有除了函数、常量和类的其他代码,会自动执行,只有空间元素本身(函数、常量和类)是需要通过空间进行访问的
  • 在PHP命名空间中,提供了三种空间元素的访问方式
    • 非限定名称:直接访问元素名,系统自动匹配当前空间(向上找到的第一个空间)
    • 限定名称:带空间名字,而且是基于当前空间的子空间(相对路径,在当前空间下,找到向下的空间的)
    • 完全限定名称:从全局空间(根目录)开始访问(绝对路径)

示例

1、非限定名称访问:即直接访问空间元素的名字,此类访问访问的是当前代码所属空间内的元素

namespace space1;
function display(){
    echo 'space1';
}

namespace space2;
function display(){
    echo 'space2';
}

# 非限定名称访问
display();				# 输出space2,因为当前display函数调用所属空间为space2

注意:非限定名称访问就好比是访问当前自己文件夹下的所有文件

2、限定名称访问,即在访问元素的前面使用相应的空间名字,非限定名称的访问是基于子空间来实现的

# 定义子空间
namespace space\space1;
function display(){
    echo 'space\space1<br/>';
}

# 定义子空间
namespace space\space2;
function display(){
    echo 'space\space2<br/>';
}

# 所属父空间
namespace space;
function display(){
    echo 'space<br/>';
}

# 非限定名称访问
display();					 # space:当前向上所属空间
space1\display();			 # space\space1:实际为当前空间space + space1\display()

注意:限定名称访问好比访问当前文件夹下的子文件夹内容(针对当前空间的子空间访问)

3、完全限定名称访问,即从根目录(全局空间)开始访问,使用\作为全局空间开始符号

# 接上述代码

# 完全限定名称访问
\space\display();			# space空间下的display
\space\space1\display();	 # space下space1空间的display

注意:完全限定名称访问好比从磁盘根目录访问对应路径下的内容(绝对路径)

小结

1、命名空间的访问分为三种模式

  • 非限定名称访问,直接访问元素本身,代表当前所属空间(当前目录)
  • 限定名称访问,使用空间名+元素,代表访问当前空间子空间(当前目录子目录)
  • 完全限定名称访问,使用全局空间开始,代表从全局开始进行访问(根目录)

2、空间元素访问方式选择

  • 当前空间内,一般使用非限定名称访问
  • 不在当前空间,一般使用完全限定名称访问
  • 在实际开发中:我们会对项目进行深度封装处理,尽量让开发者可以使用非限定名称访问(开发效率高)

4、全局空间

目标:了解全局空间的概念,掌握全局空间与其他命名空间的关系以及合作模式

概念

全局空间:即空间元素在没有定义空间的情况下所属的空间,也是所有定义的空间的顶级空间

  • 所有空间都是从全局空间分离出来的
  • 所有不指定空间的元素本质都属于全局空间
  • 全局空间与其他空间存在空间约束关系,在进行文件包含时需要注意到空间关系

示例

1、没有指定空间的元素所属的空间属于全局空间

# 不定义空间
function display(){
    echo __NAMESPACE__,'<br/>';
}

2、所有的空间本质都是在全局空间下的划分

# 定义空间
namespace space;
function display(){
    echo __NAMESPACE__,'<br/>';
}

# space空间属于从全局空间里划分出一部分用于space空间管理

3、全局空间元素的访问:使用完全限定名称访问

# 不定义空间
function display(){
    echo __NAMESPACE__,'<br/>';
}

display();							# 非限定名称访问:本身当前就是全局空间内,所以可以访问
\display();							# 完全限定名称访问:全局符号"\"+全局空间元素

4、一旦命名空间出现,那么空间元素(类、常量和函数)的访问就被限定在空间内,如果使用非限定名称访问,那么系统会以下解析逻辑(限定名称或者完全限定名称是直接按路径准确找)

  • 首先一定是在自己空间内查找
  • 如果找不到元素,不同空间元素的处理不同
    • 系统常量、系统函数如果找不到,会自动去全局空间找(也就是能找到)
    • 系统类是不会自动去全局空间找的(报错,提示当前所属空间内元素找不到)
# 定义空间
namespace space;
function display(){
    echo __FUNCTION__,'<br/>';
}

# 当前所有访问如果使用非限定名称都代表访问当前空间内的元素
display();				# space下的display函数
# 想访问函数
define('PI',3.14);		# 正确:space下没有define函数,但是全局空间有(系统函数属于全局空间)
# 访问系统常量
echo PHP_VERSION;		# 正确:space下没有,但全局空间有
# 想访问类
# $m = new Mysqli('localhost','root','root');
						# 错误:系统提示space\Mysqli不存在

# 正确方案
$m = new \Mysqli('localhost','root','root');

5、同样的,如果一个文件有空间,包含了一个没有空间(全局空间)的文件,那么要访问文件中的内容,需要使用全局空间

# 无空间文件:nospace.php
function display(){				# 属于全局空间
    echo __FUNCTION__;
}
# 有空间文件
namespace space();
function display(){
    echo 'space';
}
# 包含无空间文件
include_once 'nospace.php';
# 访问元素
display();					# 访问的是space空间下的display函数
\display();					# 正确:访问全局空间的display函数

# 注意:如果space空间没有display的话,直接访问display函数也是正确的,因为系统会自动寻找全局空间

小结

1、全局空间就是没有使用namespace定义空间的空间(所有空间本质都是在全局空间下划分)

2、全局空间的元素访问使用完全限定名称访问

3、系统内置的函数、常量和类都属于全局空间(涉及到全局空间被包含到子空间里)

  • 系统函数、常量,在空间内访问的时候系统会自动在自己空间找,如果找不到会去全局空间
  • 系统类必须使用全局空间访问:\类名

5、命名空间应用

目标:根据实际开发需求,设定合适的命名空间进行管理

概念

命名空间应用:模拟真实的开发环境,来运用命名空间的规则

  • 命名空间分层一般是文件夹进行分层(建议使用与文件夹同名空间名)
  • 文件夹的分层是根据业务的需求和项目开发所选的复杂程度来设计

步骤

1、确定项目开发复杂程度

2、实现文件分层管理布局

3、针对文件分层进行命名空间的使用(一个文件只属于一个空间)

示例

1、创建文件夹:模拟项目不同文件PHP文件放到不同文件夹下

–|root --------根目录

–|--|controller --------业务模块

–|--|model --------数据模块

–|--|core --------核心工具

2、业务说明

  • root根目录,存放用户可以直接访问的文件,文件都是请求controller里的文件
  • controller目录,存放业务逻辑文件,所有业务都是类文件,业务要操作数据库,请求model里的文件,属于controller空间
  • model目录,存放数据库操作的类文件,一张表一个类文件,属于model空间
  • core目录,核心工具的存放,属于core空间

3、创建3个文件:分表代表root目录下(不需要空间),controller目录下,controller空间,model目录下的model空间

# root目录下:index.php
# 啥都不用做,直接包含controller文件
include_once 'controller/User.php';
# $u = new User();							# 错误:当前空间没有User类
$u = new controller\User();					 # 限定名称访问:因为controller空间属于全局空间
$u->display();
# root/core目录下:DB.php
namespace core;
class DB{
    private $link;
    public function __construct(){
        # 数据库初始化
    }
    
    # 简单效果:查询全部数据
    public function getAll($sql){
        
        return '数据查询结果<br>';
    }
}
# root/model目录下:User.php
namespace model;
# 加载DB类
include_once '../DB.php';	# 建议使用绝对路径:../和./都会因为嵌套包含而错误
class User{
    public function getAllUsers(){
        # 假设数据库连接、数据库、表都已经存在
        $sql = "select * from user";
        # 调用更高级的操作类实现SQL执行并返回结果:DB属于Core空间,使用完全限定名称访问
        $db = new \Core\DB();
        return $db->getAll($sql);
    }
}
# root/controller目录下:User.php
namespace controller;
class User{
    public function display(){
        # 调用模型目录下的user类实现数据库操作:使用完全限定名称访问
        include_once '../Model/User.php';	# 建议使用绝对路径:../和./都会因为嵌套包含而错误
        $u = new \Model\User();
        $users = $u->getAllUsers();
        var_dump($users);
    }
}

4、代码说明

  • index.php在root目录下,没有定义空间,内部元素属于全局空间:index.php包含了子目录controller下的User.php,而User类属于controller空间,所以在index.php中访问User类的使用,可以使用限定名称(全局空间的子空间controller\空间元素),或者完全限定名称(\子空间\空间元素)
  • controller/User.php在root/controller文件夹下,定义了空间controller,所以文件里面所有的访问,默认都是在controller下找。controller/User类中用到了model/User类,所以需要使用完全限定名称访问(同级别不同空间)\model\User
  • model/User.php在root/model文件夹下,定义了空间model,所以文件里所有的访问,默认都是在model下找。model/User类中用到了core/DB类,所以需要使用完全限定名称访问\core\DB
  • core/DB.php在root/core文件夹下,定义了空间core

小结

1、空间的实际应用是以文件为单位定义空间的

2、空间的划分是按业务对应的脚本进行划分的,如业务controller,数据model之类

3、文件的包含和空间的包含没有联系,二者是独立的:文件是在加载文件时,而空间是在进入内存后

4、空间应用,通常是采用非限定名称(自己空间里)和完全限定名称访问(其他空间),实际上我们建议将完全限定名称转换成非限定名称

6、命名空间引入

目标:理解空间引入的逻辑和优势,掌握空间引入

概念

命名空间引入:是将另外一个空间的元素引入到当前空间来,当做当前空间的元素访问

  • 空间元素引入可以减少复杂的完全限定名称访问,取而代之的是非限定名称访问
  • 可以快速的实现将当前需要使用的空间元素引入到当前文件
  • 空间引入语法:use关键字
    • 元素关键字:默认是类,可以有function(函数)和const(常量)
use [元素关键字] [\]空间名\元素名;	# 空间名是一级空间
  • 别名:引入的元素与当前空间已有元素重名或者想换成其他合适的名字
    • 使用别名后,原来的名字在当前就不可用,只能使用别名
use [元素关键字] 空间名\元素名 as 别名;
  • 空间引入:可以一次性引入一个空间的所有元素,或者某个空间指定类型的多个元素
    • 空间引入是将被引入的空间的最后一级空间,当做当前空间的子空间
    • 类引入不需要class关键字(默认就是class)
# 引入多个元素
use [元素关键字] 空间名\元素名1 [as 别名],空间名\元素名2 ...;	# 空间名可以不同,但是元素类型必须相同

# 引入空间(全部元素)
use 空间名;		# 将当前引入的空间(最后一级)当前当前所在空间的子空间

示例

1、空间引入方式:use关键字

namespace space;
class Man{}

namespace space1;
# 引入空间元素
use space\Man;

new Man();

注意:use进行空间包含的时候,默认是从全局空间开始构建空间路径的(不是自己空间的相对路径),所以上述代码等价于以下代码

namespace space;
class Man{}

namespace space1;
# 引入空间元素
use \space\Man;

2、空间引入的元素默认是类,如果要引入其他元素,就必须使用相应关键字:function和const

namespace space;
function display(){}
class Man{}
const PI = 3.14;

namespace space1;
# 引入空间元素
use function space\display;		 # 引入函数
use space\Man;					# 引入类
use const space\PI;				# 引入常量

display();						
new Man();
echo PI;							

3、如果被引入的元素在当前空间已经存在,则会出现重名,解决方案是使用别名 as alias

namespace space;
function display(){}
class Man{}
const PI = 3.14;

namespace space1;
class Man{}
# 引入空间元素
# use space\Man;				# 错误:当前空间已经存在Man
use space\Man as M;
use function space\display as dis;
use const space\PI as D;

4、一旦引入的时候使用了别名,那么在使用的时候就直接通过别名使用

namespace space;
function display(){}
class Man{}

namespace space1;
class Man{}
# 引入空间元素
use space\Man as M;

new M();				# 使用别名

5、如果一个空间有多个元素要引入,那么可以进行一次引入多个,使用逗号,分隔即可

namespace space;
function display(){}
class Man{}
class Woman{}

namespace space1;
class Man{}

# 一次引入多个
use space\Man as M,space\Woman;		# 虽然可以批量引入(不同空间也行),但是每个元素都需要带上空间
# 引入了一个Man类别名为M,Woman类没有定义别名

6、如果说确定一个空间里的所有元素都需要引入进来,也可以直接引入空间

namespace space;
class Man{}

namespace space1;
# 引入空间
use space;

7、如果是直接进行空间引入,非限定名称的访问访问的只会是当前自己空间而非引入的空间,要访问引入空间,得使用限定名称访问:即引入的空间最后一级空间名字+元素(引入空间当做当前空间的子空间)

namespace space\space1\space2;
class Man{}

namespace space3;
class Man{}
# 引入空间
use space\space1\space2;

new Man();						# 访问的是space3\Man
new space2\Man();				# 使用引入空间的最后一级空间访问

小结

1、空间引入是解决访问时的麻烦:由完全限定名称(限定名称)变成非限定名称访问

2、空间元素都可以引入,但是引入方式有区别

  • 类直接引入
  • 函数需要在use之后跟关键字function
  • 常量需要在use之后跟关键字const

3、空间引入过程中如果出现重名,需要使用别名来处理,引入后在空间里可以直接访问别名

4、可以一次性引入多个空间内的多个元素(类型相同:每个元素必须在前面加上空间路径)

5、如果必要的情况下,也可以直接使用空间引入,但是注意被引入空间的元素不允许直接使用非限定名称访问,必须使用被引入空间的最后一级空间+元素访问(不常使用,引入方便但是使用不方便)

7、总结

1、命名空间namespace不是PHP特有的,是很多编程语言都有的用来解决结构同名的方案

2、命名空间一般只针对某个具体的结构(类和函数,较少针对常量)

3、命名空间的存在会让元素的访问变得不那么直接,我们需要选择合适的方式来调用

  • 非限定名称访问
  • 限定名称访问
  • 完全限定名称访问

4、成熟的大中型项目都会使用命名空间,命名空间的命名规范通常与项目的文件夹名字同名

  • 方便后期内部加工处理:根据空间来选择文件所在路径(自动加载)
  • 方便维护:根据空间来找到文件进行维护
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值