如何从零手写一个DI容器:基于gh_mirrors/co/container实现PSR-11合规容器的完整教程
如何从零手写一个DI容器基于gh_mirrors/co/container实现PSR-11合规容器的完整教程【免费下载链接】container项目地址: https://gitcode.com/gh_mirrors/co/container本教程基于 gh_mirrors/co/containerPSR-11 标准接口仓库带你从零手写一个 PHP 依赖注入容器DI 容器掌握 PSR-11 合规容器的全部 3 个接口与 2 个核心方法。 为什么值得学DI 容器是现代 PHP 框架如 Laravel、Symfony的基石。读懂 PSR-11 这 3 个几十行的接口文件你就掌握了所有合规容器的公共语言。什么是DI容器1分钟看懂核心思想DI 容器Dependency Injection Container依赖注入容器本质是一个服务工厂传统写法类 A 内部自己new类 B两者强耦合难以测试和替换DI 容器写法把创建对象的职责交给容器类 A 只声明我需要 B由容器统一组装和交付。好处一目了然✅ 依赖集中管理、✅ 便于单元测试可注入 Mock 对象、✅ 替换实现时业务代码零改动。而PSR-11是 PHP-FIG 制定的容器接口标准——它规定任何容器都至少暴露统一的get()和has()方法。gh_mirrors/co/container 正是这份标准的接口定义仓库只有 3 个接口文件、没有一行实现代码这正是我们从零手写的完美起点。PSR-11核心剖析3个接口文件定乾坤仓库结构极其精简src/目录下仅 3 个文件文件作用一句话理解ContainerInterface.php容器主体接口容器的脸面get()has()ContainerExceptionInterface.php容器异常基接口容器出错的统一身份证NotFoundExceptionInterface.php找不到异常接口专门标记查无此服务第一步读懂 ContainerInterface 的两个方法整个 PSR-11 标准的核心就在这两个方法声明里get(string $id)按标识符取对象是容器的主入口has(string $id): bool判断容器是否认识某个标识符。其中有一段非常关键的官方约定src/ContainerInterface.phphas($id)返回 true不保证get($id)一定不抛异常但保证不会抛未找到异常。换句话说has()管有没有这个 keyget()还负责构造这个对象——构造过程中仍可能因其他原因失败。写实现时务必遵守这条语义。第二步理解两级异常体系异常接口只有寥寥数行却设计了清晰的继承链Throwable └── ContainerExceptionInterface容器通用异常 └── NotFoundExceptionInterface未找到异常基接口定义在 ContainerExceptionInterface.php要求所有容器异常都继承它未找到接口定义在 NotFoundExceptionInterface.php专用于key 不存在场景。这样设计的好处调用方可以分级捕获——catch NotFoundExceptionInterface只处理没找到catch ContainerExceptionInterface兜底其他构建失败。错误语义从此清晰可控。3步写出你的PSR-11合规容器一键获取标准接口包标准库通过 Composer 包psr/container分发元数据见 composer.json要求 PHP 7.4命名空间Psr\Container映射到src/目录。获取仓库git clone https://gitcode.com/gh_mirrors/co/container composer require psr/container实现两个方法最简容器诞生手写实现其实非常短——一个数组存服务、两个方法做存取即可?php use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; final class MyContainer implements ContainerInterface { private array $services []; public function set(string $id, $service): void { $this-services[$id] $service; } public function get(string $id) { if (!array_key_exists($id, $this-services)) { throw new class(Service [$id] not found.) extends \RuntimeException implements NotFoundExceptionInterface {}; } return $this-services[$id]; } public function has(string $id): bool { return array_key_exists($id, $this-services); } }对照标准检查一遍get()未找到时抛出的异常实现了 NotFoundExceptionInterface ✅has()返回 bool ✅。两个方法齐全恭喜——你的容器已通过 PSR-11 合规检验注册与获取3行代码感受依赖注入$container new MyContainer(); $container-set(logger, new MonologLogger()); $logger $container-get(logger); // 从容器取而非 new业务类只需声明__construct(Logger $logger)由容器注入实例——依赖倒置就此完成。常见踩坑与最佳实践清单⚠️key 命名要稳定$id是全局契约建议用类型名或语义化名称如logger、app.config⚠️区分没找到和构造失败前者抛NotFoundExceptionInterface后者抛ContainerExceptionInterface的其它实现别混为一谈⚠️has()为 true 不代表get()无异常这是官方明文约定见 src/ContainerInterface.php不要据此省略异常处理✅面向接口编程业务代码依赖ContainerInterface而非你的MyContainer未来无缝切换任何 PSR-11 容器✅进阶方向把set()升级为工厂闭包传入Closure延迟实例化即可实现自动依赖解析这也是各大框架容器的核心机制。总结与延伸资源回顾一下这条从零到合规的路线理解标准——PSR-11 只用 3 个接口定义容器的行为契约实现get()/has()——两行判断、一个数组最简容器即可成立规范异常——用两级异常体系表达没找到与构建失败。 核心资料速查容器主体接口ContainerInterface.php异常基接口ContainerExceptionInterface.php未找到异常接口NotFoundExceptionInterface.php包元数据与自动加载配置composer.json项目说明README.md标准只有薄薄一层真正让 DI 容器变强大的是你的工厂闭包、自动解析和缓存策略。动手把上面的MyContainer扩展成支持工厂的版本吧——你会离手写一个迷你版框架容器只差一小步✨【免费下载链接】container项目地址: https://gitcode.com/gh_mirrors/co/container创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Android蓝牙Mesh灯光控制实战:从配网到组控的完整实现

Android蓝牙Mesh灯光控制实战:从配网到组控的完整实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 2:34:59 阅读更多 →
CMU自主探索环境AEDE:搭建、测试与调优全攻略

CMU自主探索环境AEDE:搭建、测试与调优全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 2:34:59 阅读更多 →
嵌入式系统第一性原理:从物理信号到可靠工程实践

嵌入式系统第一性原理:从物理信号到可靠工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 2:34:59 阅读更多 →

最新新闻

终端AI编程助手横评:Claude Code、Codex、OpenCode与WorkBuddy选型指南

终端AI编程助手横评:Claude Code、Codex、OpenCode与WorkBuddy选型指南

1. 先别急着装,弄清楚这几条命脉1.1 它们是竞品,还是互补?先把这个最关键的问题摆到台面上:Claude Code、Codex、OpenCode,这三款才是真正意义上的同类竞品,都是跑在终端里的AI编程助手。它们的核心工作方式…

2026/9/19 3:17:25 阅读更多 →
YAML快速入门:核心语法与真实场景排查指南

YAML快速入门:核心语法与真实场景排查指南

1. 别被一堆配置文件吓到:先搞清楚 YAML 是干嘛的1.1 YAML 是配置文件界的“骨架笔记”做开发或者运维的朋友,应该都对 YAML 不陌生——Kubernetes 的 Pod 定义、GitLab CI/CD 的流水线、Ansible 的 playbook、Docker Compose 的服务编排,甚至…

2026/9/19 3:17:25 阅读更多 →
Bootstrap 5 gutter自定义完全指南:CSS变量与工具类实战解析

Bootstrap 5 gutter自定义完全指南:CSS变量与工具类实战解析

1. 先搞清楚gutter到底在改什么:栅格间距的底层机制我真是见过不少人拿着Bootstrap 5的栅格系统用了大半年,一遇到"设计稿里两个卡片之间要留32px"这种需求,第一反应就是打开scss把$grid-gutter-width一改,然后重新编译…

2026/9/19 3:17:25 阅读更多 →
Spring AI(第五章)Tools自定义工具调用

Spring AI(第五章)Tools自定义工具调用

Spring AI(第五章)Tools自定义工具调用 文章目录Spring AI(第五章)Tools自定义工具调用一、章节目的二、工具调用三、如何自定义工具3.1 定义工具类3.2 注册工具类3.3 引用工具类3.4 实际工作流程四、示例代码4.1 自定义网络检索工…

2026/9/19 3:17:25 阅读更多 →
18万帧压成41张图:视频语义压缩管线实战

18万帧压成41张图:视频语义压缩管线实战

1. 从 18 万帧到 41 张图,这个压缩比到底怎么来的第一次看到“18 万帧压成 41 张图”这个数字,我下意识觉得是标题党。18 万帧,按 30fps 算就是 100 分钟的视频,压成 41 张图,等于平均每 2.4 分钟才留一张画面。这要是…

2026/9/19 3:17:25 阅读更多 →
YOLO桌面版工具:开箱即用的目标检测应用

YOLO桌面版工具:开箱即用的目标检测应用

1. 这不是又一个“跑通YOLO”的Demo,而是一个真正能塞进设计师、质检员、巡检员电脑里的工具你有没有遇到过这样的场景:工厂产线主管想用AI查漏补缺,但让他装Python环境、配CUDA、改config文件?他第一反应是关掉网页。学校老师想带…

2026/9/19 3:16:25 阅读更多 →

日新闻

BP神经网络时序预测:滑窗长度与多窗口平均策略

BP神经网络时序预测:滑窗长度与多窗口平均策略

简介:面向机器学习、深度学习与数据建模学习者的一份完整研究文献,聚焦BP神经网络在农业产量预测中的应用。文档以1980—2018年全国棉花产量为样本,系统讲解数据归一化处理、激活函数原理、多层神经网络结构搭建及训练流程,展示敏…

2026/9/19 0:00:30 阅读更多 →
Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

上个月调一个Deformable DETR模型,在单卡上要跑将近两天。第二天早上我下意识打开终端翻日志,发现loss从凌晨两点就开始往上爬,一路从0.8涨到1.35,整整六个小时没人发现。那六个小时的训练不仅白跑,还霸占着卡——等于…

2026/9/19 0:00:30 阅读更多 →
OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南 【免费下载链接】opencloud 🌤️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign. 项目地址: htt…

2026/9/19 0:00:30 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/16 19:03:19 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/17 7:57:36 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/17 10:19:14 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →