Laravel中扩展自动注册机制(PackageAuto-discovery)解读在讨论如何自动发现作者和门面之前,我们先简单分析一下PHP中包的概念。包是一段可以在多个项目中重复使用的代码。例如,包spatie/laravel-analytics允许您在laravel项目中以简单的方式从GoogleAnalytics检索数据。该包托管在GitHub上,由Spatie维护。他们将继续发布、更新和修复软件包错误。如果你在你的项目中使用这个包,并且希望在发布后获得这些更新和修复,你不必担心使用Composer从Github复制新代码就足够了。Composer是一个PHP依赖管理工具。它允许您声明项目库依赖项并管理(安装/更新)它们。--详见官网getcomposer.orgLaravel自带一个composer.json文件。在文件中的require或require-dev入口下,给出了你需要扩展应用功能的包。执行composerupdate:{"require":{"spatie/laravel-analytics":"3.*",},}也可以使用下面的命令达到同样的效果composerrequirespatie/laravel-analyticsComposer是拉取的版本包下载到vendor目录下,执行完上面的命令后,包中的所有类和文件都加载到项目中,可以立即使用。每次你再次执行composerupdate时,Composer都会重新获取(译者注,通常是从composer仓库中拉取)来更新包,并自动更新位于你的项目vendor目录下的文件。在Laravel项目中使用一些Laravel包需要额外的步骤如下:下一步。Provider和facade,是一个好习惯,这一步是TaylorOtwell定义的,只是一个非要求,DriesVints,无论何时你决定引入一个新的包或删除一个包,服务提供者和facade可以被自动发现。重温Taylor在Medium上的新功能公告。什么是服务提供者和门面?服务提供者负责将事物绑定到Laravel的服务容器中,并告诉Laravel在哪里加载包资源,如视图、配置和本地化文件。--laravel.com文档你可以在官方文档上阅读更多关于服务提供商的信息。Facades为应用程序服务容器中可用的类提供了一个“静态”接口——laravel.com文档,您可以在官方文档上阅读更多有关facades的信息。当查找和安装/更新不同的扩展包时,Composer会触发多个事件,您可以订阅这些事件并运行您自己的代码甚至命令行可执行文件,其中一个有趣的事件称为post-autoload-dump。在composer生成项目中自动加载类的最终列表后直接触发,此时Laravel可以访问所有类并且应用程序已准备好使用加载到其中的所有包类。Laravel在主composer.json文件中订阅了这个事件:第一个是调用postAutoloadDump()静态方法,这个方法清理缓存的服务或者之前发现的包,另一个是运行package:discoverartisan命令,这就是Laravel可以自动发现的秘密。包自动发现Illuminate\Foundation\Console\PackageDiscoverCommand调用Illuminate\Foundation\PackageManifest类中的build()方法,这是Laravel发现已安装包的地方。PackageManifest在应用程序引导程序的早期注册到容器,完全来自Illuminate\Foundation\Application::registerBaseServiceProviders(),它在创建Laravel应用程序的新实例后直接运行。在build()方法中,Laravel查找vendor/composer/installed.json文件,该文件由composer生成并保存一个完整的映射,其中包含composer安装的所有扩展的composer.json文件的内容。Laravel映射此文件的内容并搜索包含extra.laravel部分的包:"extra":{"laravel":{"providers":["Barryvdh\\Debugbar\\ServiceProvider"],"aliases":{"Debugbar":"Barryvdh\\Debugbar\\Facade"}}}它首先收集该部分的内容,然后查看主composer.json文件下的extra.laravel.dont-discover的内容,看看您是否决定不这样做autodiscoversomeorallpackages:"extra":{"laravel":{"dont-discover":["barryvdh/laravel-debugbar"]}}您可以将*添加到数组中以指示laravel完全停止自动注册。现在Laravel已经收集了关于扩展包的信息是的,一旦它有了它需要的信息,它就会在bootstrap/cache/packages.php中写入一个PHP文件:array('providers'=>array(0=>'Barryvdh\\Debugbar\\ServiceProvider',),'aliases'=>array('Debugbar'=>'Barryvdh\\Debugbar\\Facade',),),);PackageRegistrationLaravel有两个引导程序,在HTTP或控制台内核启动时使用:将查看packages.php生成的文件并提取您希望Laravel自动注册的包中的任何别名并注册这些别名。它使用PackageManifest::aliases()方法来收集此信息。//在RegisterFacades::bootstrap()AliasLoader::getInstance(array_merge($app->make('config')->get('app.aliases',[]),$app->make(PackageManifest::class)->别名()))->注册();如您所见,从config/app.php文件加载的别名与从PackageManifest类加载的别名合并。同样,Laravel在启动时注册服务提供者,RegisterProviders引导程序调用Foundation\Application的registerConfiguredProviders()方法,Laravel在这里收集所有应该自动注册的bundle提供者并注册它们。$providers=Collection::make($this->config['app.providers'])->partition(function($provider){returnStr::startsWith($provider,'Illuminate\\');});$providers->splice(1,0,[$this->make(PackageManifest::class)->providers()]);在这里,我们在Illuminate服务提供者中,可能在您的配置文件中的任何其他提供者在服务提供者之间注入自动发现的服务提供者,因此我们确保您可以通过在配置文件和Illuminate组件中重新注册来覆盖扩展包服务提供者将在尝试加载任何其他服务提供商之前加载。