Symfony2.8 源码分析之类的加载

󰃭 2016-07-17

今天来写写Symfony2.8 这个框架的类加载机制

版本

Symfony 2.8

原理

在项目启动时,Symfony 通过spl_autoload_register 注册了要使用的类的自动加载处理方法, 在类第一次被使用的时候, 类文件通过该方法被引入, 然后类才得以使用

源码分析

1.在symfony的入口文件, 我们找到

#web/app_dev.php or web/app.php
$loader = require __DIR__.'/../app/autoload.php'

2.我们随着这个路径,我们找打了这个autoload.php, 主要内容如下:

# app/autoload.php
$loader = require __DIR__.'/../vendor/autoload.php';
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
return $loader;

其中

$loader = require __DIR__.'/../vendor/autoload.php';

是为了注册symfony的核心类的自动加载方法

AnnotationRegistry::registerLoader(array($loader, 'loadClass'));

这个应该是为了用户配置自定义的类的自动加载配置,暂时不看

3.我们再根据$loader 找到对应的autoload.php

# vendor/autoload.php
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit447e0408cbcbbdf0d6df9a85eb1d2ead::getLoader();

这里的getLoader()函数就是在autoload_real.php定义的,我们继续深入这个文件

4.找到autoload_real.php

# vendor/composer/autoload_real.php

我们找打getLoader 函数, 在这里, 我加入了一些代注释, 方便理解

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

        //这里注册的自动加载处理函数仅仅是为了能加载 \Composer\Autoload\ClassLoader
    spl_autoload_register(array('ComposerAutoloaderInit447e0408cbcbbdf0d6df9a85eb1d2ead', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        //$loader 才是实际的要加载的自动加载处理类
//得到自动加载处理类后\Composer\Autoload\ClassLoader就不需要了
spl_autoload_unregister(array('ComposerAutoloaderInit447e0408cbcbbdf0d6df9a85eb1d2ead', 'loadClassLoader'));

        //以下是注册 命名空间与命名空间下的类文件的目录的映射关系
        //或者注册类名与类文件的路径的映射关系
        $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);
        }

        //该函数真正执行了`spl_autoload_register`
        $loader->register(true);

        //处理composer 的类加载
        $includeFiles = require __DIR__ . '/autoload_files.php';
        foreach ($includeFiles as $fileIdentifier => $file) {
            composerRequire447e0408cbcbbdf0d6df9a85eb1d2ead($fileIdentifier, $file);
        }

        return $loader;
    }

打开autoload_namespaces.php,autoload_psr4.php,autoload_classmap.php, 我们可以看到的是其中保存的是命名空间与命名空间下的类文件存储的目录的映射关系,或者是类名称与类文件路径的映射关系

实际上, 这种映射关系为后面的类文件定位提供直接的查询帮助,ClassLoader 注册(记录)了这种映射关系, 再将其loadClass 注册为自动加载处理函数(执行$loader->register(true);时), 最后,我们再使用到类的时候, 根据类名或者类的命名空间,到已经注册了的映射关系可以直接定位到类文件, 将其include 我们就实现了所谓的自动加载

总结

以上就是Symfony2.8 的内核类的自动加载的处理

这是第一次写框架源码分析, 比较粗糙, 如果各位有疑问, 请及时指出

另外, 这个分析只能作为大家研究symfony源码的参考,一定要对着源码一块看才能理解,切忌仅仅通过直接阅读本文就能理解