PHP自动加载下——PSR4
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的更多相关文章
- php自动加载规范  PSR4 (Thinkphp)
		PSR4是一种自动加载规范,老版本是PSR0,尽管thinkPHP支持PSR4和PSR0的自动加载方式,但是默认也是优先进行PSR4加载,如果失败,再进行PSR0的加载.本篇文章只会讨论PSR4的加载 ... 
- PHP 自动加载规范PSR-4
		.note-content { font-family: "Helvetica Neue", Arial, "Hiragino Sans GB", STHeit ... 
- ASP.NET MVC搭建项目后台UI框架—11、自动加载下拉框查询
		ASP.NET MVC搭建项目后台UI框架—1.后台主框架 需求:在查询记录的时候,输入第一个字,就自动把以这个字开头的相关记录查找出来,输入2个字就过滤以这两个子开头的记录,依次类推. 突然要用到这 ... 
- 移动端上拉加载下拉刷新插件-mescroll.js插件
		官网地址是:http://www.mescroll.com // 初始化mescroll function initMeScroll() { //创建MeScroll对象,内部已默认开启下拉刷新,自动 ... 
- Python3从零开始爬取今日头条的新闻【三、滚动到底自动加载】
		Python3从零开始爬取今日头条的新闻[一.开发环境搭建] Python3从零开始爬取今日头条的新闻[二.首页热点新闻抓取] Python3从零开始爬取今日头条的新闻[三.滚动到底自动加载] Pyt ... 
- PHP 自动加载
		回顾 开始的时候, 如果想在一个php文件中使用其它文件的类或方法, 需要通过include/require方法将文件包含进来. 这种方法的缺点也很明显: 如果需要引入很多文件, 就需要很多的incl ... 
- 如何实现一个php框架系列文章【3】支持psr4的自动加载类
		psr4自动加载规范https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-4-autoloader-cn.md 我们把第三方使用psr规范的类库放在v ... 
- 遵循PSR-4的自动加载
		一.简介 首先这里要了解PSR,Proposing a Standards Recommendation(提出标准建议)的缩写,就是一种PHP开发规范,让我们研发出来的代码更合理.更好维护.可读性更高 ... 
- PSR-4 自动加载器
		div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,cod ... 
随机推荐
- MGR Switch single-Primary to Muti_primary
			MGR single_primary 切换 Muti-Primary 模式 root@localhost [(none)]>select * from performance_schema.re ... 
- C#:Excel上传服务器后导入数据库
- [转载]Windows服务编写原理及探讨(2)
			(二)对服务的深入讨论之上 上一章其实只是概括性的介绍,下面开始才是真正的细节所在.在进入点函数里面要完成ServiceMain的初始化,准确点说是初始化一个 SERVICE_TABLE_ENTRY结 ... 
- Webcollector应用(二)
			先吐槽一句哀家的人品,总在写好代码之后,网站默默的升级,没有一点点防备... 一.加代理 爬取一个网站的时候,爬了不到一半,IP被封了,整个内部局域网的所有电脑都不能访问网站了. public cla ... 
- 自定义事件的触发dispatchEvent
			1. 对于标准浏览器,其提供了可供元素触发的方法:element.dispatchEvent(). 不过,在使用该方法之前,我们还需要做其他两件事,及创建和初始化.因此,总结说来就是: documen ... 
- sad 关于一些html5新属性还需要用https才能支持
			像我昨天在搞一个录音的小东西 在本地正常录音正常播放 但是放到线上环境http环境上就出现了如上的错误 功能都不能正常使用 然后就改成https线上环境 然后就正常了 如上 大家有什么赐教的欢迎留言 ... 
- Zabbix定义报警机制
			1. 修改zabbix配置文件 #取消注释或添加一行 cat -n /etc/zabbix/zabbix_server.conf |grep --color=auto "AlertScrip ... 
- Adding Completion to (interactive)
			Adding Completion to (interactive) Author: Tubo Question: Is there any way to add my own completio ... 
- 用Redis Desktop Manager连接Redis(CentOS)
			Redis Desktop Manager是Redis图形化管理工具,方便管理人员更方便直观地管理Redis数据. 然而在使用Redis Desktop Manager之前,有几个要素需要注意: 一. ... 
- python动态获取对象的属性和方法 (转)
			转自未知,纯个人笔记使用 首先通过一个例子来看一下本文中可能用到的对象和相关概念. #coding:utf-8 import sys def foo():pass class Cat(object): ... 
