1. 命名空间的作用
解决全局成员的命名冲突问题
全局成员: 类 / 函数 / 常量
demo1.php
<?php
// 命名空间的作用与适用对象
require 'inc/funciton.php';
function func1($a, $b)
{
return $a.' + '.$b.' = '.($a+$b);
}
// 直接调用会出现函数未定义错误
//echo fun1(10, 20);
// 如果想访问外部加载的函数func1,就要带上命名空间
echo \my\func1(10, 20); // 做的乘法
echo '<hr>';
// 而如果还想访问在当前脚本中定义的函数func1,也要用命名空间访问
echo \func1(10,20); // 加法inc/funciton.php
<?php
// 使用命名空间, 不改变原来的函数名称
namespace my;
function func1($a, $b)
{
return $a.' * '.$b.' = '.($a*$b);
}2.命名空间的定义
namespace: 创建命名空间, 必须是脚本的第一行代码
在一个脚本中定义多个命名空间与成员(除全局空间)
<?php
// 定义空间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>';
}
// 尽管可以在一个脚本中, 可以声明多个命名空间,但并不推荐这样去做
// 使用本例的方法, 在同一个脚本中声明多个空间,但无法自定义根空间成员,只能调用
//还能使用namespaace{}命名多个命名空间3.子命名空间
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>';
// "\"是命名空间分隔符, 将空间分层有什么卵用呢?
// 作用非常大, 现代PHP编程中的类的自动加载技术就靠它撑着呢,框架没有它, 难以想像
// 多层级的命名空间,非常像多层级的目录结构,如果类名称中的空间部分与类文件的绝对路径一致,就可以实现
// 类文件的全自动加载,并且不会千万命名冲突,因为类名本身仍是带有命名空间的4.带空间的类文件自动加载技术
str_replace(): 字符串替换函数,将空间分隔符替换成路径分隔符
DIRECTORY_SEPARATOR: 路径分隔符常量
spl_autoload_register(): 自动加载函数
<?php
// 传统方式
//require 'inc/Class122.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>';
/**********************************************************************/
// 由于类空间名称与类文件所在路径一致
// 可以通过解析类空间名称实现自动加载
// 测试
$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 = __DIR__ . '/../' . $path . '.php';
// 不是文件或文件不存在,则抛出异常
if (!(is_file($path) && file_exists($path))) {
throw new \Exception('不是文件或文件不存在');
}
require $path;
});
$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\Class25. 空间别名
use namespace/className: 通过use关键字导入空间别名
为较长的类名提供一种简化方案
导入空间别名默认从全局空间开始
导入空间别名, 不能代替外部文件的加载
注意很多框架采用了自动加载技术,会导致一些同学误以为use可以加载类
use: 解决类名过长的问题
as: 解决导入的类别名与当前空间类重名问题
<?php
// 允许通过别名引用或导入外部的完全限定名称
namespace current;
include 'inc/Class1.php';
// 如果要使用Class1类,需要先实例化
$obj = new \code\inc\Class1();
echo get_class($obj) . '<br>';
echo '<hr>';
// 你会发现,这样的类名有点长了, 实际开发过程中, 比这个长的多的是
// 如果来简化呢? 使用别名导入
//use \code\inc\Class1 AS C1;
// 现在就简单多了,其实使用use导入类别名时, 默认就是根空间(全局)开始
// 所以 "\"可以省略, 实际上也不推荐加上
//use \code\inc\Class1 AS C1;
// 如果当前脚本中没有与导入的类名冲突的类, 就没必要用AS 起一个别名了
//class Class1{},
// 此时的类的默认别名, 就是原来的名字: Class1
use code\inc\Class1;
//$obj = new C1();
$obj = new Class1();
echo get_class($obj) . '<br>';
echo '<hr>';案例:
<?php
// 命名空间实战
namespace db;
// 连接数据库: 目前在空间中写代码, PDO类中全局中, 建议加上"\"
$pdo = new \PDO('mysql:host=localhost;dbname=php','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>";
}点击 "运行实例" 按钮查看在线实例
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号