pimple容器为空,必须手动注册服务或参数才能使用;服务用匿名函数定义并支持依赖注入,参数直接赋值,factory()确保每次返回新实例,protect()用于延迟求值的可变值。

Pimple 不是“装上就能用”的开箱即用型容器,直接 composer require pimple/pimple 后调用 $container['service'] 报错或返回 null,根本原因在于服务没定义、参数没注入、或工厂行为误用。必须明确区分「服务」和「参数」,并理解匿名函数的执行时机。
为什么 new Container() 后取不到服务?
因为 Pimple\Container 实例本身是空的——它不自动扫描类、不加载配置、也不预定义任何服务。你必须手动注册服务或参数,否则 $container['xxx'] 会触发 ArrayAccess::offsetGet 查找失败,最终抛出 InvalidArgumentException 或返回 null(取决于 PHP 版本和错误报告级别)。
- 服务必须用匿名函数定义:
$container['db'] = function ($c) { return new PDO(...); }; - 参数直接赋值即可:
$container['host'] = 'localhost'; - 若想在服务中用到参数,得显式写
$c['host'],不能靠类型提示自动注入 - 别把参数当服务用:写成
$container['host'] = function () { return 'localhost'; }就变成了单例服务,不是变量
如何让同一个服务每次返回新实例?
Pimple 默认所有服务都是共享实例(Singleton),即首次 get 后缓存结果,后续调用复用。如果你需要每次新建对象(比如 Request、Logger 实例),必须用 factory() 包裹匿名函数。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 错误写法(总是返回同一个
Session):$container['session'] = function ($c) { return new Session($c['storage']); }; - 正确写法(每次新建):
$container['session'] = $container->factory(function ($c) { return new Session($c['storage']); }); -
factory()只影响该键,不影响其他服务;且不能嵌套使用(比如$container->factory($container->factory(...))无效)
怎么安全地在服务里引用其他服务或参数?
匿名函数签名中的 $c 参数就是当前容器实例,可用来读取其他服务或参数,但要注意循环依赖和执行顺序。
- 可以安全引用已定义的服务:
$container['logger'] = function ($c) { return new FileLogger($c['log_path']); }; - 参数也支持同方式访问:
$container['log_path'] = '/var/log/app.log'; - 禁止循环依赖:A 依赖 B,B 又依赖 A → 运行时报
LogicException: Circular reference detected - 定义顺序无关,但运行时第一次访问才执行函数,所以只要最终能解析通就行
protect() 是干啥的?什么时候必须用?
当你想把一个**可变值**(比如当前时间、随机数、$_GET)存进容器,又不希望它被当成服务缓存,就得用 protect()。否则 Pimple 会把它当服务处理,首次调用后就固定了。
- 错误(
time()只执行一次):$container['now'] = function () { return time(); }; - 正确(每次取都重新执行):
$container['now'] = $container->protect(function () { return time(); }); -
protect()返回的是闭包本身,不是执行结果;取值时需手动调用:$container['now']() - 别对服务用
protect():它只适用于「你想延迟求值的变量」,不是服务注册机制
factory() 和 protect() 的边界。一旦混用,行为就不可预测,调试时很难定位是定义问题还是调用时机问题。










