Composer自动加载机制源码剖析

来源:互联网 发布:linux less 向上查找 编辑:程序博客网 时间:2024/05/16 12:37

1、autoload.php
要使用Composer的自动加载,首先需要引入该文件

<?php// autoload.php @generated by Composer// 引入autoload_real.phprequire_once __DIR__ . '/composer' . '/autoload_real.php';// 下面一大长串是在我们安装composer时由Composer自动生成的,我们需要关注的是它调用的autoload_real.php里的静态方法 getLoader()return ComposerAutoloaderInit85b4dbf6b714d62ec745fcf3dd1a5041::getLoader();

2、autoload_real.php

<?php// autoload_real.php @generated by Composerclass ComposerAutoloaderInit85b4dbf6b714d62ec745fcf3dd1a5041{    private static $loader;    // 在实例化ClassLoader时调用该函数    public static function loadClassLoader($class)    {       // 该函数在getLoader方法里被注册为__autoload的实现,在实例化类时,如果类不存在,会自动调用该方法    // 如果实例化的函数是Composer\Autoload\ClassLoader 则引入该类        if ('Composer\Autoload\ClassLoader' === $class) {            require __DIR__ . '/ClassLoader.php';        }    }    public static function getLoader()    {        if (null !== self::$loader) {            return self::$loader;        }// 注册 loadClassLoader函数作为 __autoload 的实现   spl_autoload_register(array('ComposerAutoloaderInit85b4dbf6b714d62ec745fcf3dd1a5041', 'loadClassLoader'), true, true);        // 实例化该方法时会自动调用上述方法注册的函数,        // loadClassLoader函数里引入 ClassLoader类    self::$loader = $loader = new \Composer\Autoload\ClassLoader();        spl_autoload_unregister(array('ComposerAutoloaderInit85b4dbf6b714d62ec745fcf3dd1a5041', 'loadClassLoader'));        // PSR-0 的规则        $map = require __DIR__ . '/autoload_namespaces.php';        foreach ($map as $namespace => $path) {            $loader->set($namespace, $path);        }    // PSR-4 的规则        $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);        }    // 注册给定的函数作为 __autoload 的实现,具体参考下文        // Class-Map部分        $loader->register(true);    // Files方式 直接加载需要访问的文件        $includeFiles = require __DIR__ . '/autoload_files.php';        foreach ($includeFiles as $fileIdentifier => $file) {            composerRequire85b4dbf6b714d62ec745fcf3dd1a5041($fileIdentifier, $file);        }        return $loader;    }}function composerRequire85b4dbf6b714d62ec745fcf3dd1a5041($fileIdentifier, $file){    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {        // 加载需要调用的文件        require $file;        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;    }}

3、ClassLoader.php (部分核心代码)

① PSR-0 规则

     /**     * Registers a set of PSR-0 directories for a given prefix,     * replacing any others previously set for this prefix.     *     * @param string       $prefix The prefix     * @param array|string $paths  The PSR-0 base directories     */    // $prefix、$paths分别相当于autoload_namespaces.php里返回数组的key和value值    public function set($prefix, $paths)    {           if (!$prefix) {            $this->fallbackDirsPsr0 = (array) $paths;        } else {        // $prefix[0]取得是首个字符            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;        }    }

② PSR-4规则

    /**     * Registers a set of PSR-4 directories for a given namespace,     * replacing any others previously set for this namespace.     *     * @param string       $prefix The prefix/namespace, with trailing '\\'     * @param array|string $paths  The PSR-4 base directories     *     * @throws \InvalidArgumentException     */    public function setPsr4($prefix, $paths)    {        if (!$prefix) {            $this->fallbackDirsPsr4 = (array) $paths;        } else {            $length = strlen($prefix);            // PSR-4 命名空间以 \ 结尾,如果不是,则不符合规则            if ('\\' !== $prefix[$length - 1]) {                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");            }            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;            $this->prefixDirsPsr4[$prefix] = (array) $paths;        }    }

③ Class-map方式

    /**     * @param array $classMap Class to filename map     */    public function addClassMap(array $classMap)    {        if ($this->classMap) {            $this->classMap = array_merge($this->classMap, $classMap);        } else {            $this->classMap = $classMap;        }    } /**     * Registers this instance as an autoloader.     *     * @param bool $prepend Whether to prepend the autoloader or not     */    public function register($prepend = false)    {   // $prepend为true时,spl_autoload_register() 会添加函数到队列之首,而不是队列尾部。 (具体请参考php文档)         spl_autoload_register(array($this, 'loadClass'), true, $prepend);    }    /**     * Loads the given class or interface.     *     * @param  string    $class The name of the class     * @return bool|null True if loaded, null otherwise     */    public function loadClass($class)    {           if ($file = $this->findFile($class)) {            includeFile($file);            return true;        }    }

什么时候才会去调用上述注册的loadClass函数呢?举例来说

<?php require './vendor/autoload.php';// 当我们实例化TestController的时候,就会自动调用spl_autoload_register注册的函数loadClass,在loadClass中又会去调用findFile方法去查找类文件所在的位置,然后require引入$test = new TestController;echo $test->show();

至此Composer自动加载流程已讲述完毕。具体的代码还需各位自己去研究。不得不惊叹,有了Composer真是太方便了!

0 0
原创粉丝点击