如何在PHP-DI配置文件中使用构建时传入的变量?
PHP-DI:如何在配置文件中使用构建时变量完成复杂计算
问题描述
在构建PHP-DI容器时,需要基于外部传入的构建时变量(比如示例里的$number)在config.php里执行复杂计算(实际需求是根据指定目录查找要注入的服务),但config.php里无法直接访问PHP-DI容器,导致没法读取已添加的number定义,现有代码无法运行。
容器构建代码(可正常运行):
<?php use DI\Container; use DI\ContainerBuilder; class MyContainerBuilder { // @param number 是后续要使用的构建时(配置)变量 public function build(int $number): Container { $builder = new \DI\ContainerBuilder(); $builder->addDefinitions(['number' => $number]); // 希望在config.php中进行复杂计算 $builder->addDefinitions(__DIR__ . '/config.php'); // 生产环境中可编译容器,使config.php的复杂计算仅执行一次 return $builder->build(); } }
问题代码(config.php):
<?php $number = $container->get('number'); // 复杂计算: $number += 1; return [ 'improvedNumber' => $number, ];
解决方案
方案1:利用PHP变量作用域传递参数
PHP中,include的文件会继承当前作用域的变量,所以直接在build方法里保留$number变量,修改config.php直接使用该变量即可:
修改后的config.php:
<?php // 直接用当前作用域的$number $number += 1; return [ 'improvedNumber' => $number, ];
同时调整MyContainerBuilder的构建逻辑,手动include并传入结果:
public function build(int $number): Container { $builder = new \DI\ContainerBuilder(); $builder->addDefinitions(['number' => $number]); // 手动加载config.php,利用变量作用域传递$number $configDefs = include __DIR__ . '/config.php'; $builder->addDefinitions($configDefs); return $builder->build(); }
这个方案完全符合你的需求,config.php里的计算逻辑保留不变,生产环境编译容器时,计算只会执行一次。
方案2:把config.php改成带参数的函数
如果不想依赖隐式的变量作用域,可将config.php改为返回一个接收参数的函数,显式传递构建时变量:
修改后的config.php:
<?php return function(int $number) { $number += 1; return [ 'improvedNumber' => $number, ]; };
然后在构建类中调用该函数:
public function build(int $number): Container { $builder = new \DI\ContainerBuilder(); $builder->addDefinitions(['number' => $number]); // 加载函数并传入$number获取定义 $configFn = include __DIR__ . '/config.php'; $builder->addDefinitions($configFn($number)); return $builder->build(); }
这种写法更显式,避免了作用域依赖,代码可读性更强。
方案3:直接在构建类中处理服务查找(针对实际需求)
针对你实际要查找目录中服务的需求,也可以把服务扫描逻辑直接放在MyContainerBuilder里,无需依赖config.php:
public function build(string $serviceDir): Container { $builder = new \DI\ContainerBuilder(); // 扫描目录生成服务定义 $serviceDefs = []; $files = scandir($serviceDir); foreach ($files as $file) { if (pathinfo($file, PATHINFO_EXTENSION) !== 'php') continue; $className = pathinfo($file, PATHINFO_FILENAME); // 自动注入服务类 $serviceDefs[$className] = \DI\autowire($className); } $builder->addDefinitions($serviceDefs); return $builder->build(); }
这种方式把逻辑集中在容器构建类里,减少了额外配置文件的依赖。
内容的提问来源于stack exchange,提问作者Lord Bo
相关产品推荐
相关产品推荐

