PHP类的自动加载和命名空间
浅析PHP类的自动加载和命名空间
php是使用require(require_once)和include(include_once)关键字加载类文件。但是在实际的开发工程中我们基本上不会去使用这些关键字去加载类。 因为这样做会使得代码的维护相当的困难。实际的开发中我们会在文件的开始位置用use关键字使用类,然后直接new这个类就可以了. 至于类是怎么加载的,一般都是框架或者composer去实现的。
<?php
use IlluminateContainerContainer;
$container = new Container();
自动加载
我们可以通过一段伪代码来模拟一下在类的实例化工程中类是如何工作的
function instance($class)
{
// 如果类已加载则返回其实例 if (class_exists($class, false)) { return new $class(); } // 查看 autoload 函数是否被用户定义 if (function_exists('__autoload')) { __autoload($class); // 最后一次加载类的机会 } // 再次检查类是否存在 if (class_exists($class, false)) { return new $class(); } else { // 系统:我实在没辙了 throw new Exception('Class Not Found'); }
}
php在语言层面提供了__autoload 魔术方法给用户来实现自己的自动加载逻辑。当用户去new一个类的时候,如果该类没有被加载,php会在抛出错误前调用__autoload方法去加载类。下面的例子中的__autoload方法只是简单的输出要加载类的名称, 并没有去实际的加载对应的类, 所以会抛出错误。
<?php
use IlluminateContainerContainer;
$container = new Container();
function __autoload($class)
{
/* 具体处理逻辑 */ echo $class;// 简单的输出要加载类的名称
}
/**
*
运行结果
IlluminateContainerContainer
Fatal error: Uncaught Error: Class 'IlluminateContainerContainer' not found in D:projectphplaravel_for_ci_cdtestClassLoader.php:5
Stack trace:
0 {main}
thrown in D:projectphplaravel_for_ci_cdtestClassLoader.php on line 5
*/
明白了 __autoload 函数的工作原理之后,我们来用它去实现一个最简单自动加载。我们会有index.php和Person.php两个文件在同一个目录下。
//index.php
<?php
function __autoload($class)
{
// 根据类名确定文件名 $file = './'.$class . '.php'; if (file_exists($file)) { include $file; // 引入PHP文件 }
}
new Person();
/---------------------分割线-------------------------------------/
//Person.php
class Person
{
// 对象实例化时输出当前类名 function __construct() { echo '<h1>' . __CLASS__ . '</h1>'; }
}
/**运行结果
- 输出
Person
*/
命名空间
命名空间并不是什么新鲜的事务,很多语言都早就支持了这个特性(只是叫法不相同),它主要解决的一个问题就是命名冲突! 就好像日常生活中很多人都会重名,我们必须要通过一些标识来区分他们的不同。比如说现在我们要用php介绍一个叫张三的人 ,他在财务部门工作。我们可以这样描述。
namespace 财务部门;
class 张三
{
function __construct() { echo '财务部门的张三'; }
}
这就是张三的基本资料 , namespace是他的部门标识,class是他的名称. 这样大家就可以知道他是财务部门的张三而不是工程部门的张三。
非限定名称,限定名称和完全限定名称
1.非限定名称,或不包含前缀的类名称,例如 $comment = new Comment(); 如果当前命名空间是BlogArticle,Comment将被解析为、BlogArticleComment。如果使用Comment的代码不包含在任何命名空间中的代码(全局空间中),则Comment会被解析为Comment。
注意: 如果文件的开头有使用use关键字 use onetwoComment; 则Comment会被解析为 onetwoComment。
2.限定名称,或包含前缀的名称,例如 $comment = new ArticleComment(); 如果当前的命名空间是Blog,则Comment会被解析为BlogArticleComment。如果使用Comment的代码不包含在任何命名空间中的代码(全局空间中),则Comment会被解析为ArticleComment。
3.完全限定名称,或包含了全局前缀操作符的名称,例如 $comment = new ArticleComment(); 在这种情况下,Comment总是被解析为ArticleComment。
spl_autoload
接下来让我们要在含有命名空间的情况下去实现类的自动加载。我们使用 spl_autoload_register() 函数来实现,这需要你的 PHP 版本号大于 5.12。spl_autoload_register函数的功能就是把传入的函数(参数可以为回调函数或函数名称形式)注册到 SPL __autoload 函数队列中,并移除系统默认的 __autoload() 函数。一旦调用 spl_autoload_register() 函数,当调用未定义类时,系统就会按顺序调用注册到 spl_autoload_register() 函数的所有函数,而不是自动调用 __autoload() 函数。
现在, 我们来创建一个 Linux 类,它使用 os 作为它的命名空间(建议文件名与类名保持一致):
<?php
namespace os; // 命名空间
class Linux // 类名
{
function __construct() { echo '<h1>' . __CLASS__ . '</h1>'; }
}
接着,在同一个目录下新建一个 index.php文件,使用 spl_autoload_register 以函数回调的方式实现自动加载:
<?php
spl_autoload_register(function ($class) { // class = osLinux
/* 限定类名路径映射 */ $class_map = array( // 限定类名 => 文件路径 'os\\Linux' => './Linux.php', ); /* 根据类名确定文件路径 */ $file = $class_map[$class]; /* 引入相关文件 */ if (file_exists($file)) { include $file; }
});
new osLinux();
这里我们使用了一个数组去保存类名与文件路径的关系,这样当类名传入时,自动加载器就知道该引入哪个文件去加载这个类了。但是一旦文件多起来的话,映射数组会变得很长,这样的话维护起来会相当麻烦。如果命名能遵守统一的约定,就可以让自动加载器自动解析判断类文件所在的路径。接下来要介绍的PSR-4 就是一种被广泛采用的约定方式
PSR-4规范
PSR-4 是关于由文件路径自动载入对应类的相关规范,规范规定了一个完全限定类名需要具有以下结构:
<顶级命名空间>(<子命名空间>)*<类名>
PSR-4 规范中必须要有一个顶级命名空间,它的意义在于表示某一个特殊的目录(文件基目录)。子命名空间代表的是类文件相对于文件基目录的这一段路径(相对路径),类名则与文件名保持一致(注意大小写的区别)。
举个例子:在全限定类名 appviewnewsIndex 中,如果 app 代表 C:Baidu,那么这个类的路径则是 C:BaiduviewnewsIndex.php.我们就以解析 appviewnewsIndex 为例,编写一个简单的 Demo:
<?php
$class = 'appviewnewsIndex';
/ 顶级命名空间路径映射 /
$vendor_map = array(
'app' => 'C:\Baidu',
);
/ 解析类名为文件路径 /
$vendor = substr($class, 0, strpos($class, '\')); // 取出顶级命名空间[app]
$vendor_dir = $vendor_map[$vendor]; // 文件基目录[C:Baidu]
$rel_path = dirname(substr($class, strlen($vendor))); // 相对路径[/view/news]
$file_name = basename($class) . '.php'; // 文件名[Index.php]
/ 输出文件所在路径 /
echo $vendor_dir . $rel_path . DIRECTORY_SEPARATOR . $file_name;
原文地址https://www.cnblogs.com/php-learning-road/p/12196077.html
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Asp.Net Core 学习教程1、初始.Net Core与VS Code 第一个web程序
Asp.Net Core 学习教程1、初始.Net Core与VS Code 第一个web程序 1、.Net Core介绍.NETCore是.NETFramework的新一代版本,是微软开发的第一个具有跨平台(Windows、Macosx、Linux)能力的应用程序开发框架,未来也将会支持FreeBSD与Alpine平台,是微软在一开始发展时就开源的软件平台,它也经常被拿来和现有的开源NET平台Mono比较。由于.NETCore的开发目标是跨平台的.NET平台,因此.NETCore会包含.NETFramework的类库。与.NETFramework不同的是,.NETCore采用包化(Packages) 的管理方式,应用程序只需获取需要的组件即可。与.NETFramework大包式安装的做法截然不同,并且各包亦有独立的版本线,不再硬性要求应用程序跟随主线版本。 2、.Net Core跨平台.Net Core 拥有跨平台能力,并支持多种系统,让我们开大的程序可以在多个系统中运行。.Net支持的操作系统:Windows 客户端、Windows 服务端、Debian、Red Hat Enter...
- 下一篇
为何我们用 Go 而非 Python 编写机器学习基础设施平台?
云栖号:https://yqh.aliyun.com第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策! 作者 | Caleb Kaiser 译者 | 刘志勇 AI 前线导读:Go 又称 Golang,是 Google 开发的一种静态强类型、编译型、并发型且具有垃圾回收功能的编程语言。Go 语言于 2009 年 11 月正式宣布推出并开放源代码,开始在 Linux 及 Mac OS X 平台上进行了实现,后追加 Windows 系统下的实现。大部分用过 Go 语言的人都认可其是一种非常不错的生产力工具,有人总结其优点如下:部署简单、并发性好、语言设计良好、执行性能好。Cortex Labs 介绍了团队为何用 Go 而非 Python 编写机器学习基础设施。 Python 是机器学习项目中最流行的语言,就这点而言,应该不会有人提出异议。尽管 R、C++ 和 Julia 之类的语言都有自己的拥趸和用例,但 Python 仍然是 最受欢迎的 编程语言,在每个主流的机器学习框架中都能见到它的身影。 最近,我们构建了一个将机器学习模型部署为 API...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- CentOS6,CentOS7官方镜像安装Oracle11G
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- 设置Eclipse缩进为4个空格,增强代码规范
- Mario游戏-低调大师作品
- MySQL8.0.19开启GTID主从同步CentOS8
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8编译安装MySQL8.0.19
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池