简介

一般在框架中都会用到composer工具,用它来管理依赖。其中composer有类的自动加载机制,可以加载composer下载的库中的所有的类文件。那么composer的自动加载机制是怎么实现的呢?

composer 自动加载原理

以在Laravel框架中为例:

  1. 首先在入口文件(/public/index.php)中引入了autoload.php

    require __DIR__.'/../vendor/autoload.php';
  2. 我们看看autoload.php的内容

    require_once __DIR__ . '/composer/autoload_real.php';
    return ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273::getLoader();
  3. 我们再看看 autoload_real.php的内容

    <?php
    
    // autoload_real.php @generated by Composer
    
    class ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273
    {
    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('ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273', 'loadClassLoader'), true, true);
    self::$loader = $loader = new \Composer\Autoload\ClassLoader();
    spl_autoload_unregister(array('ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273', '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\ComposerStaticInit1215780529014c2b50a6fca7ce889273::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); if ($useStaticLoader) {
    $includeFiles = Composer\Autoload\ComposerStaticInit1215780529014c2b50a6fca7ce889273::$files;
    } else {
    $includeFiles = require __DIR__ . '/autoload_files.php';
    }
    foreach ($includeFiles as $fileIdentifier => $file) {
    composerRequire1215780529014c2b50a6fca7ce889273($fileIdentifier, $file);
    } return $loader;
    }
    } function composerRequire1215780529014c2b50a6fca7ce889273($fileIdentifier, $file)
    {
    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
    require $file; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
    }
    }

可以看出这一段是composer自动加载的重点,首先在 autoload.php中调用ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273::getLoader()方法,getLoader()首先判断当前\(loader是不是null,如果不为null就直接返回,否则就初始化一个ClassLoader类给赋值给\)loader,接着将autoload_namespaces.php、autoload_psr4.php、autoload_classmap.php文件中的内容加入到$loader中对应的数组中,然后给注册loadClass函数,将autoload_files.php中的所有路径所示的文件都包含进来,当在new一个类的时候如果没有找到相关的类就会触发这个loadClass函数,在loadClass()又调用了findFile()去查找相应的文件,找到相应文件后就会返回该文件,然后loadClass调用includeFile()方法将该文件include进去,否则findFile返回false,这样就完成了自动加载

  1. 下面来看一下 findFile()

     public function findFile($class)
    {
    // class map lookup
    if (isset($this->classMap[$class])) {
    return $this->classMap[$class];
    }
    if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
    return false;
    }
    if (null !== $this->apcuPrefix) {
    $file = apcu_fetch($this->apcuPrefix.$class, $hit);
    if ($hit) {
    return $file;
    }
    } $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');
    } if (null !== $this->apcuPrefix) {
    apcu_add($this->apcuPrefix.$class, $file);
    } if (false === $file) {
    // Remember that this class does not exist.
    $this->missingClasses[$class] = true;
    } return $file;
    } private function findFileWithExtension($class, $ext)
    {
    // PSR-4 lookup
    $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; $first = $class[0];
    if (isset($this->prefixLengthsPsr4[$first])) {
    $subPath = $class;
    while (false !== $lastPos = strrpos($subPath, '\\')) {
    $subPath = substr($subPath, 0, $lastPos);
    $search = $subPath.'\\';
    if (isset($this->prefixDirsPsr4[$search])) {
    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
    foreach ($this->prefixDirsPsr4[$search] as $dir) {
    if (file_exists($file = $dir . $pathEnd)) {
    return $file;
    }
    }
    }
    }
    } // PSR-4 fallback dirs
    foreach ($this->fallbackDirsPsr4 as $dir) {
    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
    return $file;
    }
    } // PSR-0 lookup
    if (false !== $pos = strrpos($class, '\\')) {
    // namespaced class name
    $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
    . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
    } else {
    // PEAR-like class name
    $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
    } if (isset($this->prefixesPsr0[$first])) {
    foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
    if (0 === strpos($class, $prefix)) {
    foreach ($dirs as $dir) {
    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
    return $file;
    }
    }
    }
    }
    } // PSR-0 fallback dirs
    foreach ($this->fallbackDirsPsr0 as $dir) {
    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
    return $file;
    }
    } // PSR-0 include paths.
    if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
    return $file;
    } return false;
    }

    findFile()函数先在classMap中查找,如果找不到的话就会尝试在apcu缓存中查找,如果还是找不到的话就会调用findFileWithExtension()函数查找,如果找到了就会将该文件加到apcu缓存,如果找不到的话就会在missingClasses数组中设一个标记表示识这个类找不到

    findFileWithExtension()方法根据之前通过\(loader->set(\)namespace, \(path)和\)loader->setPsr4($namespace, $path)方法设置的信息找出类文件的路径信息

  2. 在上面有的地方用到了 spl_autoload_registerspl_autoload_unregister函数

    1. spl_autoload_register函数

      spl_autoload_register — 注册给定的函数作为 __autoload 的实现,

      1. bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )

      2. prepend

        如果是 true,spl_autoload_register() 会添加函数到队列之首,而不是队列尾部。

      3. 如果在你的程序中已经实现了__autoload()函数,它必须显式注册到__autoload()队列中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload()函数取代为spl_autoload()或spl_autoload_call()

        例:

        function __autoload($name)
        {
        require 'class/'.$name.'.php';
        echo '1';
        }
        function autoload_test($name)
        {
        echo '2';
        }
        spl_autoload_register('autoload_test');
        spl_autoload_register('__autoload');
        $ca=new Ca();
    2. spl_autoload_unregister函数

      spl_autoload_unregister — 注销已注册的__autoload()函数,如果该函数队列处于激活状态,并且在给定函数注销后该队列变为空,则该函数队列将会变为无效。如果该函数注销后使得自动装载函数队列无效,即使存在有__autoload函数它也不会自动激活。

      1. bool spl_autoload_unregister ( mixed $autoload_function )

因本人水平有限,有些地方可能不对,欢迎留言。

如需转载请注明出处:http://www.cnblogs.com/zhuchenglin/p/8954364.html

composer 实现自动加载原理的更多相关文章

  1. 深入解析 composer 的自动加载原理 (转)

    深入解析 composer 的自动加载原理 转自:https://segmentfault.com/a/1190000014948542 前言 PHP 自5.3的版本之后,已经重焕新生,命名空间.性状 ...

  2. 深入解析 composer 的自动加载原理

    PHP 自5.3的版本之后,已经重焕新生,命名空间.性状(trait).闭包.接口.PSR 规范.以及 composer 的出现已经让 PHP 变成了一门现代化的脚本语言.PHP 的生态系统也一直在演 ...

  3. Composer 的自动加载机制

    Composer 的自动加载机制 Composer 提供了四种自动加载方式,分别是 PSR-0.PSR-4.生成 classmap 以及之间包含 files. PSR-0 方式 PSR-0 方式要求目 ...

  4. 详解composer的自动加载机制

    composer是一个用PHP开发的用来管理项目依赖的工具,当你在项目中声明了依赖关系后,composer可以自动帮你下载和安装这些依赖库,并实现自动加载代码. 安装composer composer ...

  5. composer的自动加载机制(autoload)

    composer的出现真是让人们眼前一亮,web开发从此变成了一件很『好玩』的事情,开发一个CMS就像在搭积木,从packagist中取出『积木』搭建在自己的代码中,一点一点搭建出一个属于自己的王国. ...

  6. 使用PSR-4配合composer autoload 自动加载文件夹

    require 文件很麻烦,使用PSR-4搭配composer一次加载,终生受用. 感觉类似java中的import了,自己先记录一下最近理解的. 用composer管理自己的包吧 安装compose ...

  7. 使用composer 实现自动加载

    准备工作:提前安装好composer 1.创建项目目录OOP 2.OOP目录下新建composer.json文件,composer.json是一个空json文件,代码如下: { } 3.打开控制台,进 ...

  8. php自动加载类文件探讨,spl_autoload_register自动加载原理

    spl_autoload_register函数是实现自动加载未定义类功能的的重要方法,所谓的自动加载意思就是 我们的new 一个类的时候必须先include或者require的类文件,如果没有incl ...

  9. composer 自动加载原理

    核心当然是php5加入来的_autoload函数,当实例化一个不存在的类时,在报错之前,如果定义了_autoload函数,会进行调用此函数,此函数就可以执行相关的include操作. <?php ...

随机推荐

  1. WPF 10天修炼 第五天- 内容控件

    WPF内容控件 在WPF中,所有呈现在用户界面上的对象都称为用户界面元素.但是只有派生自System.Windows.Controls.Control类的对象才称为控件.内容控件通常是指具有Conte ...

  2. curl常用命令备忘

    #####(输出请求头信息) curl -I xxx-Pro:test xxx$ curl -I https://www.baidu.com/ HTTP/1.1 200 OK Accept-Range ...

  3. 使用javaScript操作页面元素

    from selenium import webdriver import time import unittest from selenium.common.exceptions import We ...

  4. 两条命令,实现ssh免密登陆

    ssh-keygenssh-copy-id -i 目标服务器ip

  5. filp_open/filp_close/vfs_read/vfs_write

    Linux系统成功的关键因素之一就是具有与其他操作系统和谐共存的能力.Linux系统的文件系统由两层结构构建:第一层是虚拟文件系统(VFS),第二层是各种不同的具体的文件系统. VFS就是把各种具体的 ...

  6. 【Windows】JDK安装与环境变量配置

    一.JDK下载 jdk有多个版本: java se开发包:Java SE Development Kit 8u25 ,必须的配置Java开发环境的.java se开发包+示例:Java SE Deve ...

  7. flex"

    很久以前,有面试官问过我如何实现"

  8. 为什么MySQL数据库要用B+树存储索引?

    小史:树的话,无非就是前中后序遍历.二叉树.二叉搜索树.平衡二叉树,更高级一点的有红黑树.B 树.B+ 树,还有之前你教我的字典树. 红黑树 一听到红黑树,小史头都大了,开始抱怨了起来. 小史:红黑树 ...

  9. 基于Hexo搭建个人博客网站

      ## 准备工作 首先下载[nodejs](https://nodejs.org/en/download/),一路next安装即可.验证是否安装成功: ```bash node -v # 输出 v1 ...

  10. 563. Binary Tree Tilt

    https://leetcode.com/problems/binary-tree-tilt/description/ 挺好的一个题目,审题不清的话很容易做错.主要是tilt of whole tre ...