compoesr 解析流程

composer加载文件

autoload.php

<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitc8e7e2ff9618f4a7666639dbd0c65a25::getLoader();

autoload.php 文件中通过 require_once 引入autoload_real.php文件, 在调用 ComposerAutoloaderInitc8e7e2ff9618f4a7666639dbd0c65a25::getLoader();获取加载器

autoload_real.php

getLoader 方法

  • 判断是否加载器是否已经存在, 加载器存在就返回
if (null !== self::$loader) {
  return self::$loader;
}
  • 通过 spl_autoload_register调用自身 loadClassLoader方法
spl_autoload_register(array('ComposerAutoloaderInitc8e7e2ff9618f4a7666639dbd0c65a25', 'loadClassLoader'), true, true);
  • loadClassLoader 方法中验证传递 $class 变量是否等于 Composer\Autoload\ClassLoader , 相等的话使用 require 引入 ClassLoader
public static function loadClassLoader($class)
{
  if ('Composer\Autoload\ClassLoader' === $class) {
    require __DIR__ . '/ClassLoader.php';
  }
}
  • 通过 loadClassLoader 方法中引入的 ClassLoader类来创建加载器
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
  • 通过 spl_autoload_unregister 注销已经引入的类
spl_autoload_unregister(array('ComposerAutoloaderInitc8e7e2ff9618f4a7666639dbd0c65a25', 'loadClassLoader'));
  • 判断当前 php 版本和运许环境
PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
  1. 使用 PHP_VERSION_ID 判断当前 php 版本
  2. 使用HHVM_VERSION判断是否已经定义, 存在代表是当前运行环境是 HHVM
  3. 判断 zend_loader_file_encoded方法是否存在, 存在调用该方法在取反
  • 根据 $useStaticLoader状态判断
  1. $useStaticLoadertrue

引入 autoload_static.php文件, 调用 ComposerStaticInitc8e7e2ff9618f4a7666639dbd0c65a25 类中 getInitializer静态方法获取闭包函数, 在使用 call_user_func 调用闭包方法

require_once __DIR__ . '/autoload_static.php';

call_user_func(\Composer\Autoload\ComposerStaticInitc8e7e2ff9618f4a7666639dbd0c65a25::getInitializer($loader));

getInitializer 方法中注册了, 命名空间($prefixLengthsPsr4), 命名空间路径($prefixDirsPsr4), $prefixesPsr0, 类文件映射($classMap)

public static function getInitializer(ClassLoader $loader)
{
    return \Closure::bind(function () use ($loader) {
        $loader->prefixLengthsPsr4 = ComposerStaticInitc8e7e2ff9618f4a7666639dbd0c65a25::$prefixLengthsPsr4;
        $loader->prefixDirsPsr4 = ComposerStaticInitc8e7e2ff9618f4a7666639dbd0c65a25::$prefixDirsPsr4;
        $loader->prefixesPsr0 = ComposerStaticInitc8e7e2ff9618f4a7666639dbd0c65a25::$prefixesPsr0;
        $loader->classMap = ComposerStaticInitc8e7e2ff9618f4a7666639dbd0c65a25::$classMap;

    }, null, ClassLoader::class);
}
  1. $useStaticLoaderfalse

手动引入文件和注册

$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);
}
  • 调用加载器的 register方法
$loader->register(true);

register 方法这个放在后面说, 放在这里会影响内容

  • 引入自动加载文件
if ($useStaticLoader) {
    $includeFiles = Composer\Autoload\ComposerStaticInitc8e7e2ff9618f4a7666639dbd0c65a25::$files;
} else {
    $includeFiles = require __DIR__ . '/autoload_files.php';
}

判断 $useStaticLoader的状态来选择文件加载方式

  • 注册加载文件到 $GLOBALS 全局变量中
foreach ($includeFiles as $fileIdentifier => $file) {
    composerRequirec8e7e2ff9618f4a7666639dbd0c65a25($fileIdentifier, $file);
}

循环调用 composerRequirec8e7e2ff9618f4a7666639dbd0c65a25 方法

function composerRequirec8e7e2ff9618f4a7666639dbd0c65a25($fileIdentifier, $file)
{
    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
        require $file;

        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
    }
}

composerRequirec8e7e2ff9618f4a7666639dbd0c65a25 方法是否已经引入, 没有引入先入文件在赋值到 $GLOBALS 全局变量中

  • 最后返回加载器

ClassLoader.php

register方法

使用 spl_autoload_register 调用自己 loadClass方法加载类

public function register($prepend = false)
{
    spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}

loadClass方法

通过 findFile 加载 $class 文件路径, 通过 includeFile方法加载文件

public function loadClass($class)
{
  if ($file = $this->findFile($class)) {
    includeFile($file);

    return true;
  }
}

includeFile 方法

使用 include 引入文件

function includeFile($file)
{
    include $file;
}

findFile方法

  1. 使用 classMap 映射返回文件
// class map lookup
if (isset($this->classMap[$class])) {
  return $this->classMap[$class];
}
  1. classMapAuthoritativemissingClasses判断是否返回 false
  • classMapAuthoritative目前也清楚是干嘛的
  • missingClasses判断这个是否为缺失状态
  1. apcuPrefix 不为 null, 使用 apcu_fetch 获取文件
if (null !== $this->apcuPrefix) {
  $file = apcu_fetch($this->apcuPrefix.$class, $hit);
  if ($hit) {
    return $file;
  }
}
  1. 使用 findFileWithExtension 查询文件
  • 查询 .php文件 或者 .hh 文件
$file = $this->findFileWithExtension($class, '.php');

// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
  $file = $this->findFileWithExtension($class, '.hh');
}
  • 如果apcuPrefix不为 null, 使用 apcu_add 把文件添加到缓存中
if (null !== $this->apcuPrefix) {
  apcu_add($this->apcuPrefix.$class, $file);
}
  • 如果文件不存在, 标记为缺失状态
if (false === $file) {
  // Remember that this class does not exist.
  $this->missingClasses[$class] = true;
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!