目次
简介
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 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

クラフトCMSのキャッシングの問題を解決する:Wiejeben/Craft-Laravel-Mixプラグインの使用 クラフトCMSのキャッシングの問題を解決する:Wiejeben/Craft-Laravel-Mixプラグインの使用 Apr 18, 2025 am 09:24 AM

CraftCMSを使用してWebサイトを開発する場合、特にCSSやJavaScriptファイルを頻繁に更新する場合、リソースファイルのキャッシュ問題が発生することがよくあります。古いバージョンのファイルがブラウザによってキャッシュされ、ユーザーが最新の変更を表示しないようにすることがあります。この問題は、ユーザーエクスペリエンスに影響を与えるだけでなく、開発とデバッグの難しさを高めます。最近、プロジェクトで同様のトラブルに遭遇し、いくつかの調査の後、プラグインWiejeben/Craft-Laravel-Mixが見つかりました。

Laravel Frameworkインストール方法 Laravel Frameworkインストール方法 Apr 18, 2025 pm 12:54 PM

記事の概要:この記事では、Laravelフレームワークを簡単にインストールする方法について読者をガイドするための詳細なステップバイステップの指示を提供します。 Laravelは、Webアプリケーションの開発プロセスを高速化する強力なPHPフレームワークです。このチュートリアルは、システム要件からデータベースの構成とルーティングの設定までのインストールプロセスをカバーしています。これらの手順に従うことにより、読者はLaravelプロジェクトのための強固な基盤を迅速かつ効率的に築くことができます。

作曲家とlaravelcmsをすばやく構築する方法:mki-labs/エスプレッソの実践的な経験 作曲家とlaravelcmsをすばやく構築する方法:mki-labs/エスプレッソの実践的な経験 Apr 18, 2025 am 07:36 AM

新しいLaravelプロジェクトを開発する際に、トリッキーな問題に遭遇しました。完全に機能的で簡単なコンテンツ管理システム(CMS)を迅速に構築する方法です。私は複数のソリューションを試しましたが、複雑な構成と不便なメンテナンスのためにすべてをあきらめました。 LaravelcmsパッケージMKI-Labs/Espressoを発見するまで、インストールが簡単であるだけでなく、強力な機能と直感的な管理インターフェイスも提供し、問題を完全に解決しました。

Composerを使用してHTTP要求の問題を解決する方法:Yiche/HTTPライブラリの実用的なガイド Composerを使用してHTTP要求の問題を解決する方法:Yiche/HTTPライブラリの実用的なガイド Apr 18, 2025 am 08:06 AM

開発中、HTTP要求が必要になることがよくあります。これは、データを取得したり、データを送信したり、外部APIと対話するためです。ただし、複雑なネットワーク環境に直面してリクエスト要件を変更すると、HTTPリクエストを効率的に処理する方法が課題になります。プロジェクトで問題に遭遇しました。リクエストを異なるAPIに頻繁に送信し、リクエストを記録して、その後のデバッグと分析を促進する必要があります。いくつかの方法を試した後、Yiche/HTTPライブラリを発見しました。 HTTP要求の処理を簡素化するだけでなく、動的ロギング機能も提供し、開発効率を大幅に改善します。

作曲家を使用したJavaScriptエラー処理の問題を解決する方法 作曲家を使用したJavaScriptエラー処理の問題を解決する方法 Apr 18, 2025 am 08:30 AM

複雑なWebアプリケーションを開発する際には、JavaScriptエラーを効果的に処理してログインする方法を開発する際に、困難な問題を抱えています。私はいくつかの方法を試しましたが、このライブラリDvasilenko/Alterego_toolsを見つけるまで、それらのどれも私のニーズを満たすことができませんでした。このライブラリの設置を通じて、この問題を簡単に解決し、プロジェクトの保守性と安定性を大幅に改善しました。作曲家は次のアドレスを通して学ぶことができます:学習アドレス

Symfony/Consoleライブラリを使用して、効率的なコマンドラインインターフェイスを作成する実用的な経験 Symfony/Consoleライブラリを使用して、効率的なコマンドラインインターフェイスを作成する実用的な経験 Apr 18, 2025 am 07:30 AM

プロジェクト開発では、毎日のタスクを簡素化したり、プロセスを自動化するためにコマンドラインツールを作成する必要があることがよくあります。ただし、美しくテストしやすいコマンドラインインターフェイスを作成するのは簡単ではありません。最近、コマンドラインツールを必要とするプロジェクトを開発しながら、この問題に遭遇しました。いくつかの調査の後、私はSymfony/Consoleライブラリを見つけました。これにより、コマンドラインインターフェイスの作成プロセスが大幅に簡素化されます。

コンポーザーを使用して依存関係注入を解きます:PSR-11コンテナインターフェイスの適用 コンポーザーを使用して依存関係注入を解きます:PSR-11コンテナインターフェイスの適用 Apr 18, 2025 am 07:39 AM

大規模なPHPプロジェクトを開発する際に、一般的ではあるが難しい問題に遭遇しました。依存関係を効果的に管理し、注入する方法です。最初は、グローバル変数と手動注入を使用しようとしましたが、これによりコードの複雑さが増加するだけでなく、簡単にエラーが発生しました。最後に、PSR-11コンテナインターフェイスを使用し、作曲家の力を使用して、この問題をうまく解決しました。

SilverStripeのアクセシビリティの向上Webサイト:フライングフォーカスモジュールのインストールと使用 SilverStripeのアクセシビリティの向上Webサイト:フライングフォーカスモジュールのインストールと使用 Apr 18, 2025 am 08:09 AM

政府のウェブサイトプロジェクトを開発するとき、私は困難な問題に遭遇しました。特に視覚障害のあるユーザーにとって、さまざまなユーザーのニーズを満たすためにウェブサイトのアクセシビリティを改善する方法は、ウェブサイトをナビゲートして運営することは非常に困難です。複数の方法を試した後、Webサイトのアクセシビリティを大幅に向上させるFlyingFocusというJavaScriptライブラリを見つけました。ただし、SilverStripeのWebサイトに統合することは課題です。幸いなことに、FlyingFocusの統合プロセスを簡素化し、パズルを解決するDia-NZ/Silverstripe-Flying-Focusモジュールを見つけました。

See all articles