博客列表 >PHP命名空间笔记-2019年3月6日

PHP命名空间笔记-2019年3月6日

的博客
的博客原创
2019年03月24日 00:10:24723浏览

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\Class2


5. 空间别名 

   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>";
}

运行实例 »

点击 "运行实例" 按钮查看在线实例


声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议