1.先来介绍一下PSR规范

PHP-FIG,它的网站是:www.php-fig.org。就是这个联盟组织发明和创造了PSR规范,其中自动加载涉及其中两个规范,一个是PSR0,一个是PSR4, PSR0规范已经过时了,官方有提示,现在主要是用PSR4规范定义自动加载标准。

2.PRS4简介

这个 PSR 描述的是通过文件路径自动载入类的指南;它作为对 PSR-0 的补充;根据这个 指导如何规范存放文件来自动载入;

术语「类」是一个泛称;它包含类,接口,traits 以及其他类似的结构;

完全限定类名应该类似如下范例:

()*

完全限定类名必须有一个顶级命名空间(Vendor Name);

完全限定类名可以有多个子命名空间;

完全限定类名应该有一个终止类名;

下划线在完全限定类名中是没有特殊含义的;

字母在完全限定类名中可以是任何大小写的组合;

所有类名必须以大小写敏感的方式引用;

当从完全限定类名载入文件时:

在完全限定类名中,连续的一个或几个子命名空间构成的命名空间前缀(不包括顶级命名空间的分隔符),至少对应着至少一个基础目录。

在「命名空间前缀」后的连续子命名空间名称对应一个「基础目录」下的子目录,其中的命名 空间分隔符表示目录分隔符。子目录名称必须和子命名空间名大小写匹配;

终止类名对应一个以 .php 结尾的文件。文件名必须和终止类名大小写匹配;

自动载入器的实现不可抛出任何异常,不可引发任何等级的错误;也不应返回值;

完全限定类名 命名空间前缀 基础路径 完全路径
\Acme\Log\Writer\File_Writer Acme\Log\Write ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php
\Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php
\Symfony\Core\Request Symfony\Core ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php
\Zend\Acl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php

大家注意看第二列和第四列,命名空间前缀对应基础路径,命名空间前缀之后的子命名空间必须对应代码目录(类名必须是PHP文件)

3.优化自动加载方法

上一节中封装自动加载的方法比较简单,无法自动加载带命名空间的类

spl_autoload_register(function ($class) {

    // 命名空间前缀
$prefix = 'Foo\\Bar\\'; // 命名空间前缀对应的基础目录
$base_dir = __DIR__ . '/src/'; // 检查new的类是否有命名空间前缀
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
} // 获取去掉命名空间前缀后的类名
$relative_class = substr($class, $len); // 将命名空间的中的分隔符替换为目录分隔符,再加上基础目录和.php后缀,最终拼接成
// 文件路径
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php'; // 如果文件存在则require
if (file_exists($file)) {
require $file;
}
});

但是上面的方法只能适用固定的命名空间前缀,不能通用。

4、再次优化通用自动加载方法

<?php
namespace Example; /**
* 下面这个例子实现了一个命名空间前缀对应多个基础目录
*
* 现在我们的目录结构是下面这样:
*
* /demo/autoload/
* controller/
* DemoController.php # Foo\Bar\DemoController
* Admin/
* AdminController.php # Foo\Bar\Admin\AdminController
* model/
* DemoModel.php # Foo\Bar\DemoModel
* Admin/
* AdminModel.php # Foo\Bar\Admin\AdminModel
*
* Foo\Bar分别对应基础路径 /demo/autoload/controller 和 /demo/autoload/model
*/
class Psr4AutoloaderClass
{
/**
* 一个数组,key为命名空间前缀,值为基础路径
*
* @var array
*/
protected $prefixes = array(); /**
* 封装自动加载函数
*
* @return void
*/
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
} /**
*
* 添加一个基础路径对应一个命名空间前缀
*
* @param string $prefix 命名空间前缀.
* @param string $base_dir 命名空间类文件的基础路径
* @param bool true为往数组头部添加元素,false为往数组尾部添加元素
* @return void
*/
public function addNamespace($prefix, $base_dir, $prepend = false)
{
// 去掉左边的\
$prefix = trim($prefix, '\\') . '\\'; // 规范基础路径
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/'; // 初始化数组
if (isset($this->prefixes[$prefix]) === false) {
$this->prefixes[$prefix] = array();
} // 将命名空间前缀和基础路径存入数组
if ($prepend) {
array_unshift($this->prefixes[$prefix], $base_dir);
} else {
array_push($this->prefixes[$prefix], $base_dir);
}
} /**
* 真正包含文件方法,将给到类名文件包含进来
*
* @param string $class 全限定类名(包含命名空间).
* @return 成功将返回文件路径,失败则返回false
*/
public function loadClass($class)
{
$prefix = $class;
//查找$prefix最后一个\的位置,看看最后一个\之前的字符串是否在$this->prefixes中
//如果不存在则继续查询上一个\的位置,获取上一个\之前的字符串是否在$this->prefixes中
//如果循环结束还是没有找到则返回false
while (false !== $pos = strrpos($prefix, '\\')) {
$prefix = substr($class, 0, $pos + 1); $relative_class = substr($class, $pos + 1); $mapped_file = $this->loadMappedFile($prefix, $relative_class);
if ($mapped_file) {
return $mapped_file;
} //去掉右边的\
$prefix = rtrim($prefix, '\\');
} return false;
} /**
* 如果参数中的$prefix在$this->prefixes中存在,那么将循环$this->prefixes[$prefix]里的value(基础路径)
* 之后拼接文件路径,如果文件存在将文件包含进来
*
* @param string $prefix 命名空间前缀.
* @param string $relative_class 真正的类名(不包含命名空间路径的类名).
* @return mixed 包含成功返回文件路径,否则返回false
*/
protected function loadMappedFile($prefix, $relative_class)
{
// 检查数组中是否有$prefix这个key
if (isset($this->prefixes[$prefix]) === false) {
return false;
} // 将数组中所有的基础路径中的文件包含进来
foreach ($this->prefixes[$prefix] as $base_dir) { // 拼接文件绝对路径
$file = $base_dir
. str_replace('\\', '/', $relative_class)
. '.php'; // 如果文件存在则包含进来
if ($this->requireFile($file)) {
// 返回文件路径
return $file;
}
} // 没有找到文件
return false;
} /**
*如果文件存在则包含进来.
*
* @param string $file 文件路径.
* @return bool
*/
protected function requireFile($file)
{
if (file_exists($file)) {
require $file;
return true;
}
return false;
}
}

PHP自动加载下——PSR4的更多相关文章

  1. php自动加载规范 PSR4 (Thinkphp)

    PSR4是一种自动加载规范,老版本是PSR0,尽管thinkPHP支持PSR4和PSR0的自动加载方式,但是默认也是优先进行PSR4加载,如果失败,再进行PSR0的加载.本篇文章只会讨论PSR4的加载 ...

  2. PHP 自动加载规范PSR-4

    .note-content { font-family: "Helvetica Neue", Arial, "Hiragino Sans GB", STHeit ...

  3. ASP.NET MVC搭建项目后台UI框架—11、自动加载下拉框查询

    ASP.NET MVC搭建项目后台UI框架—1.后台主框架 需求:在查询记录的时候,输入第一个字,就自动把以这个字开头的相关记录查找出来,输入2个字就过滤以这两个子开头的记录,依次类推. 突然要用到这 ...

  4. 移动端上拉加载下拉刷新插件-mescroll.js插件

    官网地址是:http://www.mescroll.com // 初始化mescroll function initMeScroll() { //创建MeScroll对象,内部已默认开启下拉刷新,自动 ...

  5. Python3从零开始爬取今日头条的新闻【三、滚动到底自动加载】

    Python3从零开始爬取今日头条的新闻[一.开发环境搭建] Python3从零开始爬取今日头条的新闻[二.首页热点新闻抓取] Python3从零开始爬取今日头条的新闻[三.滚动到底自动加载] Pyt ...

  6. PHP 自动加载

    回顾 开始的时候, 如果想在一个php文件中使用其它文件的类或方法, 需要通过include/require方法将文件包含进来. 这种方法的缺点也很明显: 如果需要引入很多文件, 就需要很多的incl ...

  7. 如何实现一个php框架系列文章【3】支持psr4的自动加载类

    psr4自动加载规范https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-4-autoloader-cn.md 我们把第三方使用psr规范的类库放在v ...

  8. 遵循PSR-4的自动加载

    一.简介 首先这里要了解PSR,Proposing a Standards Recommendation(提出标准建议)的缩写,就是一种PHP开发规范,让我们研发出来的代码更合理.更好维护.可读性更高 ...

  9. PSR-4 自动加载器

    div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,cod ...

随机推荐

  1. jquery ajax的再次封装,简化操作

    1.封装的ajax var funUrl=""   // 每个请求地址相同的部分 function queryData(url,params,success,error){ url ...

  2. 日志生成控制文件syslog.conf

    1: syslog.conf的介绍 对于不同类型的Unix,标准UnixLog系统的设置,实际上除了一些关键词的不同,系统的syslog.conf格式是相同的.syslog采用可配置的.统一的系统登记 ...

  3. 远程连接 mysql 数据库连接不上的解决方案

    今天用Navicat访问虚拟机上的mysql,无法访问报cannot connect(10038). 首先看是否可以telnet,本机cmd,telnet 10.10.10.10 3306,结果是连接 ...

  4. 458. Poor Pigs

    There are 1000 buckets, one and only one of them contains poison, the rest are filled with water. Th ...

  5. IEEEXtreme 10.0 - Ellipse Art

    这是 meelo 原创的 IEEEXtreme极限编程大赛题解 Xtreme 10.0 - Ellipse Art 题目来源 第10届IEEE极限编程大赛 https://www.hackerrank ...

  6. 使用亚马逊云服务器EC2做深度学习(一)申请竞价实例

    这是<使用亚马逊云服务器EC2做深度学习>系列的第一篇文章. (一)申请竞价实例  (二)配置Jupyter Notebook服务器  (三)配置TensorFlow  (四)配置好的系统 ...

  7. python操作json数据格式--基础

    非常基础的json库的用法,后续添加数据格式.编码等内容 参考文章 json进阶 Python的json模块提供了一种很简单的方式来编码和解码JSON数据. 其中两个主要的函数是 json.dumps ...

  8. Python全栈开发之6、正则表达式

    转载请注明出处http://www.cnblogs.com/Wxtrkbc/p/5498162.html 正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串,在文本处理方面功能非常强大 ...

  9. bzoj 1818 主席树

    思路:主席树搞一搞. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #de ...

  10. cocos2dx各个版本下载地址

    https://code.google.com/archive/p/cocos2d-x/downloads?page=1 各种工具包括 NDK 8 https://github.com/fusijie ...