Slim研读笔记四之Composer(下)

“Composer是现代php项目的基石,作为一个有梦想的PHPer,不懂可不行哦” ——海盗.娜美

这节是Composer源码分析系列的第二节,我们继续延续上节未完成的工作。上节,我们通过autoload_real.php文件了解self::$loader得到\Composer\Autoload\ClassLoader()对象。然后就将注册到autoload队列的loaderClassLoader自动加载器舍弃。这节,让我们继续composer探险之旅...

在开始之前,我们要了解composer完成了什么工作。

总体来说,composer提供了如下几种加载类型:
  1. classmap
  2. psr-0
  3. psr-4
  4. files
这几种自动加载都会用到,通常,项目代码psr-4自动加载,helper用files自动加载,development相关用classmap自动加载。psr-0已经废弃了,但偶尔也会在项目中看到。
这应该是最最简单的 autoload 模式了。大概的意思就是这样的:
{
    "classmap": ["src/"]
}
composer 在背后就会读取这个文件夹中所有的文件 然后再 vendor/composer/autoload_classmap.php 中怒将所有的class的namespace+classname生成一个key=>value的php数组
return [
  'App\\Console\\Kernel' => $baseDir . '/app/Console/Kernel.php'
];
?>
然后就可以光明正大地用 spl_autoload_register 这个函数来怒做自动加载了。

好吧,上面的例子其实有点 tricky,仅仅是为了帮助我们理解composer,上面这个 autoload 实际上是根据 prs-4 来生成出来的。不过这不重要,了解底层重要点,我们可以看到所有的所谓的 autoloading 其实可以理解为生成了这么一个 classmap,这是 composer dump-autoload -o 做的事儿。不然的话compoesr 会吭哧吭哧地去动态读取 psr-4 和 prs-0 的内容。

实际上每次我们执行composer update操作时,composer会根据.json文件生成autoload_static.php,该文件中包含了命名空间到实际映射的数组(采用psr4或psr0,中间的转化过程暂且不说)。我们只需要按照一定的自动加载器规则对其进行加载就可以引入实际文件路径,然后光明正大地使用组件类文件中的类啦。

废话少说,让我们继续后面的代码
// PHP版本大于5.6且未定义HHVM_VERSION常量,返回True
$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';
    // 将$loader参数传到类的getInitializer方法
    call_user_func(\Composer\Autoload\ComposerStaticInit2b0e34f11c87555a88f83f6bf964b679::getInitializer($loader));
    …
进入该类继续查看
public static function getInitializer(ClassLoader $loader){   
    // 相当于在ClassLoader类里面加了个静态成员方法    
    // 通过该方法可以很方便地将ComposerStaticInit中的成员方法传递给另一个类ClassLoader的成员方法,赞!    
    // 调用getInitializer方法相当于给ClassLoader类增加了成员方法。
    return \Closure::bind(function () use ($loader) {       
    	// 返回命名空间到实际路径基于ps4组成的数组        
    	$loader->prefixLengthsPsr4 = ComposerStaticInit2b0e34f11c87555a88f83f6bf964b679::$prefixLengthsPsr4;              
    	$loader->prefixDirsPsr4 = ComposerStaticInit2b0e34f11c87555a88f83f6bf964b679::$prefixDirsPsr4;        
    	// 返回命名空间到实际路径基于psr0组成的数组    
    	$loader->prefixesPsr0 = ComposerStaticInit2b0e34f11c87555a88f83f6bf964b679::$prefixesPsr0;
    }, null, ClassLoader::class);
}
我们,刚刚在外层也看到使用了如何扩充了ClassLoader类的成员方法。
call_user_func(\Composer\Autoload\ComposerStaticInit2b0e34f11c87555a88f83f6bf964b679::getInitializer($loader));
查看该方法剩下的代码
...
$loader->register(true);
if ($useStaticLoader) {    
    // 返回$files静态数组,该数组存储一段hash到实际文件路径。
    $includeFiles = Composer\Autoload\ComposerStaticInit2b0e34f11c87555a88f83f6bf964b679::$files;
} else {    
    $includeFiles = require __DIR__ . '/autoload_files.php’;
}
foreach ($includeFiles as $fileIdentifier => $file) { 
    composerRequire2b0e34f11c87555a88f83f6bf964b679($fileIdentifier, $file);
}
return $loader;
$loader->reigister(true)有效代码
// 注册自动加载器,并将该自动加载器放在队列首部
public function loadClass($class){    
    // 引入类文件
    if ($file = $this->findFile($class)) {        
        includeFile($file);
        return true;    
    }
}

CoposerRequirexxxx代码

// 这些文件放在$GLOBALS数组(引用全局作用域的全部变量)。
// $file是文件的实际路径,引用该文件
function composerRequire2b0e34f11c87555a88f83f6bf964b679($fileIdentifier, $file){    
    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
        // 引用        
        require $file;
        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;    
    }
}

关于Composer的研读,就到此为止啦,有感兴趣的同学可以深入学习下代码细节。柚子会在下节快速切入到Slim核心框架的研读工作中。


参考:http://blog.hans-lizihan.com/php/2015/06/25/php-composer-autoload.html





你可能感兴趣的:(slim)