# :-: 一、命名空间的作用
* 解决全局成员的命名冲突问题
* 全局成员: 类 / 函数 / 常量
```php
// 命名空间的作用与适用对象
require 'funciton.php';
function func($a, $b){
return $a.' + '.$b.' = '.($a+$b);
}
// 直接调用会出现函数未定义错误
echo func(10, 20);
// 如果想访问外部加载的函数func,就要带上命名空间
echo \my\func(10, 20);
// 而如果还想访问在当前脚本中定义的函数func,也要用命名空间访问
echo \func(10,20);
```
```php
// 1、使用较长的命名来进行区分
function my_func($a, $b)
{
return $a.' * '.$b.' = '.($a*$b);
}
// 2、使用命名空间, 不改变原来的函数名称
namespace my;
function func($a, $b)
{
return $a.' * '.$b.' = '.($a*$b);
}
```
* 命名空间解决了什么问题呢?
* php 全局成员的命名冲突的问题
* 全局成员, 是指在当前脚本中,并不受使用域的限制,总是可以访问的
* php 中哪些是全局成员呢? 类, 函数, 常量
* 因为这三个成员, 不受作用域的限制, 所以无法像变量那样,用作用域对他们的可见性进行区隔
* 所以对于全局成员, 我们之前是通过一个很长的名称来进行区分, 例如: my_func, 难写难记
* 使用命名空间, 可以防止命名恐惧症, 在开发中可以使用相同名称的全局成员,只要放在不同的空间中即可
*****
# :-: 二、命名空间的定义
* `namespace`: 创建命名空间, 必须是脚本的第一行代码
* 在一个脚本中定义多个命名空间与成员(除全局空间)
```php
namespace one;
// 在one空间中定义三个全局成员
class Pig {}
function hello(){ return 'Hello 欧阳克'; }
const SITE = '白驼山庄';
// 访问成员
echo Pig::class . '<br>'; // 完整类名
echo hello() . '<br>';
echo SITE . '<hr>';
```
> 两个命名空间
```php
namespace one;
// 在one空间中定义三个全局成员
class Pig {}
function hello(){ return 'Hello 欧阳克'; }
const SITE = '白驼山庄';
// 访问成员
echo Pig::class . '<br>'; // 完整类名
echo hello() . '<br>';
echo SITE . '<hr>';
namespace two;
class Pig {}
function hello(){ return 'Hello 黄蓉'; }
const SITE = '桃花岛';
echo Pig::class . '<br>'; // 完整类名
echo hello() . '<br>';
echo SITE . '<br>';
```
> 访问另一个域名空间
```php
// 如果要在当前空间下面, 访问其它空间的成员, 例如one空间
// 与文件系统类似,从根空间开始,根空间: "\"
echo '<br>';
echo \one\Pig::class . '<br>'; // 完整类名
echo \one\hello() . '<br>';
echo \one\SITE . '<hr>';
```
* 尽管可以在一个脚本中, 可以声明多个命名空间,但并不推荐这样去做
* 使用本例的方法, 在同一个脚本中声明多个空间,但无法自定义根空间成员,只能调用
*****
# :-: 三、同时定义多个空间
* `namespace {}`: 用大括号在一个脚本中声明多个命名空间
```php
namespace one{
class Pig {}
function hello(){ return 'Hello 欧阳克'; }
const SITE = '白驼山庄';
// 访问成员
echo Pig::class . '<br>'; // 完整类名
echo hello() . '<br>';
echo SITE . '<hr>';
}
namespace two{
class Pig {}
function hello(){ return 'Hello 黄蓉'; }
const SITE = '桃花岛';
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`: 类空间的分层管理,命名空间是可以分层管理的
```php
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>';
```
*****
# :-: 五、空间的类文件自动加载技术
* `str_replace()`: 字符串替换函数,将空间分隔符替换成路径分隔符
* `DIRECTORY_SEPARATOR`: 路径分隔符常量
* `spl_autoload_register()`: 自动加载函数
```php
// 传统方式
require 'inc/Class1.php';
require 'inc/Class2.php';
$obj1 = new inc\Class1();
$obj2 = new inc\Class2();
echo get_class($obj1) . '<br>';
echo get_class($obj2) . '<br>';
echo '<hr>';
```
> Class1.php
```php
<?php
namespace inc;
class Class1
{
}
```
> Class2.php
```php
<?php
namespace inc;
class Class2
{
}
```
> 自动加载技术
```php
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>';
echo get_class($obj2) . '<br>';
```
*****
# :-: 六、空间别名
* `use namespace/className`: 通过`use`关键字导入空间别名
* 为较长的类名提供一种简化方案
* 导入空间别名默认从全局空间开始
* 导入空间别名, 不能代替外部文件的加载
* 注意很多框架采用了自动加载技术,会导致一些同学误以后use可以加载类
* `as`: 解决导入的类别名与当前空间类重名问题
```php
namespace current;
include 'inc/Class1.php';
// 如果要使用Class1类,需要先实例化
$obj = new \inc\Class1();
echo get_class($obj) . '<br>';
echo '<hr>';
# 你会发现,这样的类名有点长了, 实际开发过程中, 比这个长的多的是
# 如何来简化呢? 使用别名导入
use \inc\Class1 AS C1;
// 现在就简单多了,其实使用use导入类别名时, 默认就是根空间(全局)开始
// 所以 "\"可以省略, 实际上也不推荐加上
// use \inc\Class1 AS C1;
// 如果当前脚本中没有与导入的类名冲突的类, 就没必要用AS 起一个别名了
class Class1{};
// 此时的类的默认别名, 就是原来的名字: Class1
// use \inc\Class1;
// $obj = new C1();
$obj = new Class1();
echo get_class($obj) . '<br>';
```
*****
# :-: 七、命名空间实战
```php
namespace db;
// 连接数据库: 目前在空间中写代码, PDO类中全局中, 建议加上"\"
$pdo = new \PDO('mysql:host=localhost;dbname=ouyangke','root','root');
// 如果PDO类前不加"\"也不会报错, 因为系统在当前空间中没有找到,会自动转到全局中查找, 为提升查询效率,强烈建议加上
//查询点数据展示出来,以测试数据库操作正确
$stmt = $pdo->prepare('SELECT `id`,`name`,`position` FROM `staff` LIMIT :offset, :num');
$stmt->bindValue('offset',0, \PDO::PARAM_INT);
$stmt->bindValue('num',5, \PDO::PARAM_INT);
$stmt->execute();
// 将结果集中的列绑定到变量
$stmt->bindColumn('id', $id);
$stmt->bindColumn('name', $name);
$stmt->bindColumn('position', $position);
// 遍历
while ($stmt->fetch(\PDO::FETCH_BOUND)) {
echo "<li>{$id}. {$name} : {$position}</li>";
}
```
- 序言
- PHP基础
- 认识PHP
- 环境安装
- PHP语法
- 流程控制
- PHP数组
- PHP函数
- PHP类与对象
- PHP命名空间
- PHP7新特性
- PHP方法库
- PHP交互
- 前后端交互
- 项目常规开发流程
- MySQL数据库
- 会话控制
- Ajax分页技术
- 细说函数
- 类与对象
- 对象进阶
- 类与对象进阶
- OOP面向对象
- 设计模式
- 路由与模板引擎
- 异常类
- PHP爬虫
- PHP抓取函数
- PHP匹配函数
- 正则表达式
- PHP字符串函数
- 抓取实战
- PHP接口
- 了解接口
- PHP插件
- PHPSpreadsheet
- ThinkPHP6
- 安装
- 架构
- 数据库
- 数据库操作
- 视图
- 模版
- 模型
- 杂项
- 命令行
- 交互
- 微信小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- 百度小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- Linux
- 服务器上线流程
- 安装svn
- MySQL
- 认识MySQL
- MySQL函数
- 杂项
- composer依赖管理工具