目录
简介
composer 自动加载原理
首页 开发工具 composer composer实现自动加载原理【详解】

composer实现自动加载原理【详解】

Jul 02, 2020 pm 01:13 PM
composer

下面由composer教程栏目给大家介绍composer实现自动加载原理,希望对需要的朋友有所帮助!

composer实现自动加载原理【详解】

简介

一般在框架中都会用到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 (&#39;Composer\Autoload\ClassLoader&#39; === $class) {
                require __DIR__ . &#39;/ClassLoader.php&#39;;
            }
        }
    
        public static function getLoader()
        {
            if (null !== self::$loader) {
                return self::$loader;
            }
            spl_autoload_register(array(&#39;ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273&#39;, &#39;loadClassLoader&#39;), true, true);
            self::$loader = $loader = new \Composer\Autoload\ClassLoader();
            spl_autoload_unregister(array(&#39;ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273&#39;, &#39;loadClassLoader&#39;));
    
            $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined(&#39;HHVM_VERSION&#39;) && (!function_exists(&#39;zend_loader_file_encoded&#39;) || !zend_loader_file_encoded());
            if ($useStaticLoader) {
                require_once __DIR__ . &#39;/autoload_static.php&#39;;
    
                call_user_func(\Composer\Autoload\ComposerStaticInit1215780529014c2b50a6fca7ce889273::getInitializer($loader));
            } else {
                $map = require __DIR__ . &#39;/autoload_namespaces.php&#39;;
                foreach ($map as $namespace => $path) {
                    $loader->set($namespace, $path);
                }
    
                $map = require __DIR__ . &#39;/autoload_psr4.php&#39;;
                foreach ($map as $namespace => $path) {
                    $loader->setPsr4($namespace, $path);
                }
    
                $classMap = require __DIR__ . &#39;/autoload_classmap.php&#39;;
                if ($classMap) {
                    $loader->addClassMap($classMap);
                }
            }
    
            $loader->register(true);
    
            if ($useStaticLoader) {
                $includeFiles = Composer\Autoload\ComposerStaticInit1215780529014c2b50a6fca7ce889273::$files;
            } else {
                $includeFiles = require __DIR__ . &#39;/autoload_files.php&#39;;
            }
            foreach ($includeFiles as $fileIdentifier => $file) {
                composerRequire1215780529014c2b50a6fca7ce889273($fileIdentifier, $file);
            }
    
            return $loader;
        }
    }
    
    function composerRequire1215780529014c2b50a6fca7ce889273($fileIdentifier, $file)
    {
        if (empty($GLOBALS[&#39;__composer_autoload_files&#39;][$fileIdentifier])) {
            require $file;
    
            $GLOBALS[&#39;__composer_autoload_files&#39;][$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, &#39;.php&#39;);
    
            // Search for Hack files if we are running on HHVM
            if (false === $file && defined(&#39;HHVM_VERSION&#39;)) {
                $file = $this->findFileWithExtension($class, &#39;.hh&#39;);
            }
    
            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, &#39;\\&#39;, DIRECTORY_SEPARATOR) . $ext;
    
            $first = $class[0];
            if (isset($this->prefixLengthsPsr4[$first])) {
                $subPath = $class;
                while (false !== $lastPos = strrpos($subPath, &#39;\\&#39;)) {
                    $subPath = substr($subPath, 0, $lastPos);
                    $search = $subPath.&#39;\\&#39;;
                    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, &#39;\\&#39;)) {
                // namespaced class name
                $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                    . strtr(substr($logicalPathPsr4, $pos + 1), &#39;_&#39;, DIRECTORY_SEPARATOR);
            } else {
                // PEAR-like class name
                $logicalPathPsr0 = strtr($class, &#39;_&#39;, 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_register和spl_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 &#39;class/&#39;.$name.&#39;.php&#39;;
            echo &#39;1&#39;;
        }
        function autoload_test($name)
        {
            echo &#39;2&#39;;
        }
        spl_autoload_register(&#39;autoload_test&#39;);
        spl_autoload_register(&#39;__autoload&#39;);
        $ca=new Ca();
        登录后复制
    2. spl_autoload_unregister函数
      spl_autoload_unregister — 注销已注册的__autoload()函数,如果该函数队列处于激活状态,并且在给定函数注销后该队列变为空,则该函数队列将会变为无效。如果该函数注销后使得自动装载函数队列无效,即使存在有__autoload函数它也不会自动激活。
      1. bool spl_autoload_unregister ( mixed $autoload_function )
    3. 因本人水平有限,有些地方可能不对,欢迎留言。

      以上是composer实现自动加载原理【详解】的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用Composer快速搭建LaravelCMS:mki-labs/espresso的实战经验 如何使用Composer快速搭建LaravelCMS:mki-labs/espresso的实战经验 Apr 18, 2025 am 07:36 AM

在开发一个新的Laravel项目时,我遇到了一个棘手的问题:如何快速搭建一个功能齐全且易于管理的内容管理系统(CMS)。我尝试了多种解决方案,但都因为复杂的配置和不便的维护而放弃。直到我发现了mki-labs/espresso这个LaravelCMS包,它不仅安装简单,还提供了强大的功能和直观的管理界面,彻底解决了我的问题。

使用Symfony/Console库创建高效命令行接口的实践经验 使用Symfony/Console库创建高效命令行接口的实践经验 Apr 18, 2025 am 07:30 AM

在项目开发中,经常需要创建命令行工具来简化日常任务或自动化流程。然而,创建一个美观且易于测试的命令行接口并非易事。最近,我在开发一个需要命令行工具的项目时遇到了这个问题。经过一番探索,我找到了Symfony/Console库,它大大简化了命令行接口的创建过程。

使用Composer解决依赖注入:PSR-11容器接口的应用 使用Composer解决依赖注入:PSR-11容器接口的应用 Apr 18, 2025 am 07:39 AM

在开发一个大型PHP项目时,我遇到了一个常见但棘手的问题:如何有效地管理和注入依赖。最初,我尝试使用全局变量和手动注入,但这不仅增加了代码的复杂度,还容易导致错误。最终,我通过使用PSR-11容器接口,并借助Composer的强大功能,成功解决了这个问题。

如何使用Composer解决Yii框架下的数据批量处理问题 如何使用Composer解决Yii框架下的数据批量处理问题 Apr 18, 2025 am 07:54 AM

在开发Yii框架项目时,常常会遇到需要从数据库中获取大量数据的情况。如果不采取适当的措施,直接获取所有数据可能会导致内存溢出,影响程序性能。最近在处理一个大型电商平台的项目时,我遇到了这种问题,经过一番研究和尝试,最终通过pavle/yii-batch-result这个扩展库解决了难题。

如何使用 Composer 解决 HTTP 请求问题:yiche/http 库的实用指南 如何使用 Composer 解决 HTTP 请求问题:yiche/http 库的实用指南 Apr 18, 2025 am 08:06 AM

在开发过程中,经常需要处理HTTP请求,这可能是为了获取数据、发送数据或者与外部API交互。然而,当面对复杂的网络环境和多变的请求需求时,如何高效地处理HTTP请求成为了一个挑战。我曾在一个项目中遇到过这样的问题:需要频繁地向不同的API发送请求,同时还要记录这些请求的日志,以便于后续的调试和分析。尝试了几种方法后,我发现了yiche/http这个库,它不仅简化了HTTP请求的处理,还提供了动态日志记录的功能,极大地提升了开发效率。

提升SilverStripe网站的可访问性:Flying Focus模块的安装与使用 提升SilverStripe网站的可访问性:Flying Focus模块的安装与使用 Apr 18, 2025 am 08:09 AM

在开发一个政府网站项目时,我遇到了一个棘手的问题:如何提升网站的可访问性,以满足不同用户的需求,特别是对于视觉障碍用户来说,导航和操作网站可能非常困难。在尝试了多种方法后,我找到了一个名为FlyingFocus的JavaScript库,它可以显着改善网站的可访问性。然而,将其集成到SilverStripe网站中却是一个挑战。幸运的是,我发现了dia-nz/silverstripe-flying-focus模块,它简化了FlyingFocus的集成过程,解决了我的难题。

oTranCe翻译平台的使用与替代方案 oTranCe翻译平台的使用与替代方案 Apr 18, 2025 am 08:45 AM

在项目开发中,常常需要多语言支持,而oTranCe曾经是一个非常受欢迎的解决方案。然而,最近我发现oTranCe项目已经不再维护和更新,这让我不得不寻找新的替代方案来满足项目需求。幸运的是,Composer提供了一个便捷的方法来管理和安装替代的翻译平台。

解决 Craft CMS 中的缓存问题:使用 wiejeben/craft-laravel-mix 插件 解决 Craft CMS 中的缓存问题:使用 wiejeben/craft-laravel-mix 插件 Apr 18, 2025 am 09:24 AM

在使用CraftCMS开发网站时,常常会遇到资源文件缓存的问题,特别是当你频繁更新CSS和JavaScript文件时,旧版本的文件可能仍然被浏览器缓存,导致用户无法及时看到最新的更改。这个问题不仅影响用户体验,还会增加开发和调试的难度。最近,我在项目中遇到了类似的困扰,经过一番探索,我找到了wiejeben/craft-laravel-mix这个插件,它完美地解决了我的缓存问题。

See all articles