后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载导读服务定位器Service Locator是 Yii 2 框架中负责按 ID 提供各类服务/组件的核心对象它保证每个组件在定位器内只存在单一实例并允许你通过 ID 以读属性一样的方式获取组件。本篇以 docs/guide-ja/concept-service-locator.md 为主线结合 yii\di\ServiceLocator 源码、yii\base\Module 的树遍历实现与 ServiceLocatorTest 测试用例系统讲解组件注册的四种方式、惰性实例化与共享实例机制、components批量配置、模块树遍历解析以及封装第三方库时的推荐实践。读完本篇你将能够熟练使用Yii::$app-get(db)/Yii::$app-db访问并自定义应用组件也能在自己的模块中按需注册与覆写服务。什么是服务定位器服务定位器是一个知道如何提供应用可能需要的各种服务或组件的对象。在服务定位器内部每个组件只以单一实例存在并通过唯一的ID标识你使用该 ID 即可从定位器中取出组件。在 Yii 2 中服务定位器就是 yii\di\ServiceLocator 的实例或其子类实例。该类继承自 yii\base\Component因此它本身也是带属性、事件与行为的组件对象。源码类注释明确指出其实现的是经典的service locator 模式framework/di/ServiceLocator.php。Yii 中最常用的服务定位器是通过\Yii::$app访问的应用Application对象。它提供的服务被称为应用组件Application Components例如request、response、urlManager等。借助服务定位器提供的功能你可以轻松配置这些组件甚至用自研实现整体替换它们。除应用对象外每个模块Module对象也都是一个服务定位器并且模块实现了 树遍历tree traversal能力。注册组件set() 的四种定义形式使用服务定位器的第一步是向其注册组件注册通过 yii\di\ServiceLocator::set() 完成。set()接受组件 ID 与组件定义definition共有四种合法定义形式定义形式说明源码判定分支framework/di/ServiceLocator.php类名字符串例如yii\caching\ApcCache取用时由容器按类名创建实例is_callable($definition, true)且为字符串配置数组必须包含class键或__class键其余键值对用于初始化属性is_array($definition)PHP 可调用匿名函数/静态方法取用时调用该回调并返回对象is_object($definition) || is_callable($definition, true)已实例化的对象取用时直接返回该对象本身is_object($definition) !$definition instanceof Closureset()的注册逻辑非常严格如果传入的是配置数组但缺少class或__class元素会抛出InvalidConfigException提示The configuration for the $id component must contain a class element.如果传入的类型既非对象、非可调用、也非数组例如字符串、整数等同样会抛出InvalidConfigExceptionframework/di/ServiceLocator.php。此外set()总是先执行unset($this-_components[$id])这意味着重新注册同名组件会使之前已实例化的旧实例作废而传入null则等价于移除该组件定义framework/di/ServiceLocator.php。文档给出了四种注册方式的完整示例use yii\di\ServiceLocator; use yii\caching\FileCache; $locator new ServiceLocator; // 使用类名注册 cache取用时创建组件 $locator-set(cache, yii\caching\ApcCache); // 使用配置数组注册 db $locator-set(db, [ class yii\db\Connection, dsn mysql:hostlocalhost;dbnamedemo, username root, password , ]); // 使用匿名函数注册 search函数负责构建组件 $locator-set(search, function () { return new app\components\SolrService; }); // 使用现成组件实例注册 pageCache $locator-set(pageCache, new FileCache);关于set()的更多细节可参考源码中的完整示例注释framework/di/ServiceLocator.php其中还展示了配置数组形式的db组件可附带charset utf8等更多初始化参数以及[Foo, bar]这种类方法数组形式的 PHP 可调用定义。获取组件get() 与属性式访问组件注册完成后可以通过以下两种等价方式中的任意一种使用其 ID 访问$cache $locator-get(cache); // 或者 $cache $locator-cache;第二种写法之所以可行是因为ServiceLocator重写了魔术方法__get()当访问的属性名是一个已注册组件 ID 时直接委托给get()否则才回退到父类Component::__get()的常规属性解析framework/di/ServiceLocator.php。同理__isset()也会优先检查组件是否已注册或已加载framework/di/ServiceLocator.php。惰性实例化与共享单例语义get()的行为framework/di/ServiceLocator.php可概括为若_components[$id]中已存在实例直接返回——即后续访问返回同一实例若只存在定义_definitions[$id]定义是对象且非Closure即注册时传入的实例直接缓存并返回该对象其他形式类名、配置数组、可调用交给Yii::createObject($definition)创建后缓存并返回若既无实例也无定义且$throwException为true抛出InvalidConfigException: Unknown component ID: $id为false时返回null。也就是说组件在你第一次访问时才被创建惰性实例化之后一直被复用共享单例。Yii::createObject()实际委托给Yii::$container全局 DI 容器完成实例创建、构造器依赖解析与属性配置framework/BaseYii.php这也是服务定位器与 依赖注入容器 协作的关键点。测试用例 testShared() 明确验证了共享语义连续两次get()返回的对象通过assertSame()判定为同一实例同时验证了配置数组prop1 10、prop2 20被正确应用到新建组件上。检查与清理has() 用于判断组件 ID 是否已注册$checkInstance false时检查是否存在定义或是否已经实例化$checkInstance true时检查_components。clear($id) 同时移除定义与已加载实例。getComponents($returnDefinitions) 返回全部组件定义或已加载实例的列表。通过 components 属性批量注册由于服务定位器通常通过配置configuration创建ServiceLocator提供了一个可写属性components对应 setComponents()允许一次性配置并注册多个组件。下面的配置数组可为服务定位器例如应用注册db、cache、tz、search四个组件return [ // ... components [ db [ class yii\db\Connection, dsn mysql:hostlocalhost;dbnamedemo, username root, password , ], cache yii\caching\ApcCache, tz function() { return new \DateTimeZone(Yii::$app-formatter-defaultTimeZone); }, search function () { $solr new app\components\SolrService(127.0.0.1); // ... 其他初始化 ... return $solr; }, ], ];注意tz组件展示了回调定义的另一实用场景它可以在回调体内引用Yii::$app-formatter-defaultTimeZone等运行时状态动态构建组件而类名与静态配置数组都无法做到这一点。应用如何预置核心组件对于 Yii 应用而言components配置会在 Application::__construct() 中与核心组件合并coreComponents()返回的log、view、formatter、i18n、urlManager、assetManager、security以及安装了 swiftmailer 时的mailer等定义会被预置framework/base/Application.php。合并规则是若你在配置中未定义该 ID则使用默认定义若已定义但缺少class键则自动补充默认类名。这就是应用组件可以按需覆写机制的底层来源。用静态工厂方法封装第三方库上述配置中search组件还有另一种更推荐的配置方式不直接书写构建SolrService实例的 PHP 回调而是用一个返回该回调的静态类方法class SolrServiceBuilder { public static function build($ip) { return function () use ($ip) { $solr new app\components\SolrService($ip); // ... 其他初始化 ... return $solr; }; } } return [ // ... components [ // ... search SolrServiceBuilder::build(127.0.0.1), ], ];这种方式在发布封装了非 Yii 第三方库的 Yii 组件时尤为推荐用上述静态方法表达构建第三方对象的复杂逻辑而组件的使用者只需调用静态方法即可完成组件配置无需关心第三方库的构建细节。树遍历Tree Traversal模块允许任意嵌套一个 Yii 应用本质上就是一棵模块树。由于每个模块都是服务定位器让子模块能够访问其父模块的服务是顺理成章的。这使得模块内部可以使用$this-get(db)而不必引用根服务定位器写Yii::$app-get(db)。额外的好处是开发者可以在模块内覆写override配置。任何从模块请求服务的操作如果该模块自身无法满足都会向上传递给父模块处理。源码实现印证了这一点Module::get() 先检查自身是否挂在父模块下isset($this-module)若存在父模块则先以$throwException false在自身查找找不到再递归调用$this-module-get($id, $throwException)——父模块可能是应用对象或其他上级模块。对应的 Module::has() 也采用同样的自身或祖先判定逻辑。该行为自 2.0.13 起加入源码注释明确说明。需要特别注意的是模块内组件的配置永远不会与父模块内同名组件的配置合并。服务定位器模式允许我们定义具名服务但不能假定同名服务使用相同的配置参数。这也是模块可覆写、但覆写是整体替换而非合并这一规则的根源——一旦子模块以某个 ID 注册了组件该请求就由子模块的定义完全接管不会再回溯到父模块。常见陷阱与最佳实践小结重复访问不会重建实例get()返回的是缓存后的同一实例这是服务定位器的核心契约若需要每次取新对象应改用 DI 容器Yii::$container而非服务定位器。注册同名组件会清空旧实例set()先unset(_components[$id])重注册后再get()将按新定义重建。配置数组必须有 class否则抛出InvalidConfigException__class键作为class的别名也会被归一化处理framework/di/ServiceLocator.php。模块树遍历只向上回溯不做配置合并子模块同名组件完全覆盖父模块定义。第三方库封装优先使用静态工厂方法让用户只调用SolrServiceBuilder::build(...)即可完成配置隐藏第三方对象构建复杂度。应用组件可安全覆写通过components配置覆盖核心组件时只需给出class与所需属性框架会保留其余默认行为见 framework/base/Application.php。延伸阅读概念配置Configurations理解components配置数组的完整语法与合并规则。概念依赖注入容器DI Container服务定位器与 DI 容器的区别与协作Yii::createObject的底层。结构应用Applications应用对象作为服务定位器的完整生命周期。结构应用组件Application Components内置应用组件的分类与自定义方式。源码yii\di\ServiceLocator、yii\base\Module、yii\base\Application、BaseYii::createObject。测试tests/framework/di/ServiceLocatorTest.php其中testShared()共享实例、testCallable()回调注册、testObject()实例注册、testModulePropertyIsset()组件属性式访问等用例直接验证了本文所述行为。赞分享后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载相关推荐Yii 2 服务定位器Service Locator深入解析从组件注册到模块树遍历Yii 2 服务定位器Service Locator深入解析从组件注册到模块树遍历 服务定位器Service Locator是 Yii 2 框架依赖管后端Web框架Yii 2 服务定位器Service Locator深度解析组件注册、单例共享与模块树遍历Yii 2 服务定位器Service Locator深度解析组件注册、单例共享与模块树遍历 服务定位器Service Locator是 Yii 2 框后端Web框架Yii 2 Service Locator 全面解析应用组件注册、获取与模块树遍历机制Yii 2 Service Locator 全面解析应用组件注册、获取与模块树遍历机制 Service Locator服务定位器是 Yii 2 框架依赖管后端Web框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
Python爬虫与推荐算法:从新闻抓取到个性化推送的完整实践 简介:面向新闻资讯类应用开发与数据挖掘学习者,一套完整的Python网络爬虫与推荐算法项目资源实现了新浪新闻数据采集与个性化推荐。爬虫部分可抓取新闻标题、正文、图片、视频链接,并保留页面排版;推荐部分集成权重衰减、标签推荐… · 2026/9/23 7:32:43
Diem Move 模块解析:NetworkIdentity 网络身份管理的链上实现与形式化验证 Diem Move 模块解析:NetworkIdentity 网络身份管理的链上实现与形式化验证 【免费下载链接】diem Diem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world. 项目地址: https://gitcode.c… · 2026/9/23 7:32:43
知识工作插件实战:从捕获到AI生成,打造高效知识流水线 知识工作者的日常里,最磨人的往往不是某一件具体的事,而是那种“信息刚到手、转头就要用”的碎片感。找文件、翻对话记录、把资料从网页搬到笔记里再搬到文档里,每个环节都不难,但串起来特别费时间。我接触knowledge-work-plugins… · 2026/9/23 7:32:43
3步图解原理:觉今是而昨非,搞定版本升级API全变了 3步图解原理:觉今是而昨非,搞定版本升级API全变了 版本升级后 API 全变了,这种绝望感只有写过代码的人才懂。你盯着屏幕,看着昨天还跑通的代码,今天直接抛出 AttributeError 或 ImportError… · 2026/9/23 8:14:11
DFA词法分析器与LALR(1)语法分析器:从原理到高效实现 简介:这份资源面向高校计算机专业修读编译原理课程的学生及需要完成课设的开发者,提供一套C实现的完整编译器前端方案,重点解决词法分析与语法分析两个核心阶段的工程落地问题。压缩包共17个文件,约2.48MB,包含3个cpp与… · 2026/9/23 8:14:11
3天搞定水果价格网卡顿,一文搞懂后端优化避坑指南 3天搞定水果价格网卡顿,一文搞懂后端优化避坑指南 配置环境就卡半天,查个水果价格还得转圈圈?别急,这不仅仅是你的网络问题。很多项目上线后,数据查询慢如蜗牛,根源往往不在带宽,而在代码逻辑与数据库交互的“内耗”。今天不聊虚的,咱们直接拆解一个… · 2026/9/23 8:13:59
泰昌足浴盆源码解析:3招解决代码跑不通的性能瓶颈 泰昌足浴盆源码解析:3招解决代码跑不通的性能瓶颈 复制来的泰昌足浴盆控制板代码,烧录进芯片后风扇不转、水温显示乱跳,甚至直接死机?别急着骂硬件不行,90%的问题出在软件逻辑的“水土不服”上。很多开发者拿到开源项目,连一个 while(1)… · 2026/9/23 8:13:59
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29