Composer自动加载(一)

Composer是PHP的基于项目的依赖管理工具,它本身集成一个autoloader,支持PSR-4,PSR-0,classmap,files 四种自动加载方式。

首先介绍一下PSR-4与PSR-0。

介绍这两种自动加载规范之前必须先交代一下什么是PSR:
PSR
是制定的代码规范,简称PSR,是代码开发的事实标准。

PSR共有6个规范,分别是:
1 基础编码规范 PSR-1
2 编码风格规范 PSR-2
3 日志接口规范 PSR-3
4 自动加载规范 PSR-4
4 缓存接口规范 PSR-6
6 HTTP 消息接口规范 PSR-7
还有一个被废弃的规范:自动加载规范 PSR-0。
PSR-0和PSR-4同样是自动加载规范,看起来重复了,但事实上PSR-2和PSR-4是随着PHP版本演变而发展的,在PHP5.3之前,没有命名空间的概念,为了兼容第三方包,都是以下划线来区分类,为了兼容这种情况,PSR-0中会将类名中的下划线解析成目录分隔符,获取相应的目录层级和命名空间,比如加载含有名为Acme_Util_ClassName的类的文件ClassName.php的写法:

{
  "name": "acme/util",
  "auto" : {
    "psr-0": {
      "Acme\\Util\\": "src/"
    }
  }
}

实际目录结构是:

vendor/
  acme/
    util/
      composer.json
      src/
        Acme/
          Util/
            ClassName.php

PSR-4与PSR-0的主要区别是前者去掉了对下划线的解析,由于PHP5.2版本已经被抛弃了,就犯不着再将下划线解析成目录分隔符了,同样是ClassName.php:

{
  "name": "acme/util",
  "auto" : {
    "psr-4": {
      "Acme\\Util\\": "src/"
    }
  }
}

实际目录结构是:

vendor/
  acme/
    util/
      composer.json
      src/
        ClassName.php

还有classmap方式和file方式

classmap
自动加载的最简单形式,有完整的命名空间和文件目录的映射,即将所有的 class 的 namespace + classname 生成成一个 key => value 的 php 数组:

<?php
return [ 
  'App\\Console\\Kernel' => $baseDir . '/app/Console/Kernel.php'
];
?>

file
用于加载全局函数的文件,存放各个全局函数所在的文件路径名,加载helper functions函数库:

{
  "files": [
    "path/to/file.php"
  ]
}

接下来看看自动加载的具体实现:

首先是autoload.php:

#引入autoload_real.php文件
require_once __DIR__ . '/composer/autoload_real.php';

/*使用autoload_real.hph中的全局类ComposerAutoloaderInit444e163ae7f2491afbac6c694d5fc5b6 调用静态方法getLoader()
*/
return ComposerAutoloaderInit444e163ae7f2491afbac6c694d5fc5b6::getLoader();

打开autoload_real.php文件看看:

<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit444e163ae7f2491afbac6c694d5fc5b6
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInit444e163ae7f2491afbac6c694d5fc5b6', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit444e163ae7f2491afbac6c694d5fc5b6', 'loadClassLoader'));

        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require_once __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInit444e163ae7f2491afbac6c694d5fc5b6::getInitializer($loader));
        } else {
            $map = require __DIR__ . '/autoload_namespaces.php';
            foreach ($map as $namespace => $path) {
                $loader->set($namespace, $path);
            }

            $map = require __DIR__ . '/autoload_psr4.php';
            foreach ($map as $namespace => $path) {
                $loader->setPsr4($namespace, $path);
            }

            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        $loader->register(true);

        return $loader;
    }
}

找到getLoader函数,可以看到有一次spl_autoload_register调用,加载了核心类ClassLoader,并通过核心类的实例初始化与注册初始化顶级命名空间映射。

扫描二维码关注公众号,回复: 2787322 查看本文章

猜你喜欢

转载自blog.csdn.net/hhhzua/article/details/81565066