基于 Entropy 框架的反射式依赖注入与签名即契约控制台开发指南
基于 Entropy 框架的反射式依赖注入与签名即契约控制台开发指南【免费下载链接】rectorInstant Upgrades and Automated Refactoring of any PHP 5.3 code项目地址: https://gitcode.com/GitHub_Trending/re/rector本文以仓库内 vendor/entropy/entropy/CLAUDE.md 为核心骨架结合其 README.md 与src/源码实现展开。Entropy 是一个要求 PHP 8.3 的极简框架其 composer.json 中require为php: ^8.4核心只有两块基于反射的依赖注入容器src/Container与控制台运行器src/Console。它的最大特点是零配置、零 YAML、零魔法字符串——CommandInterface::run()的方法签名本身就是 CLI 契约。读完本文你将掌握如何用反射容器自动装配服务、如何用run()签名直接定义命令行参数与选项、option注解的强制选项机制、数组参数的自动单数化约定以及底层的映射与校验逻辑。一、框架布局先看清 Entropy 的目录结构CLAUDE.md 用一份精炼的 Layout 概括了整个框架的组织方式src/Container— 自动装配容器autowiring、自动发现autodiscovery、契约查找contract lookupsrc/Console— 命令注册表、应用启动、输入输出、基于 docblock 的参数/选项映射src/Reflection— 反射辅助工具参数解析、docblockoption标记解析器src/FileSystem、src/Utils、src/Attributes— 配套支撑模块tests/— 与src/一一镜像fixture 类位于各自的Fixture/子目录下从源码目录树看这一布局完全成立src/Container下是Autodiscovery.php与Container.php两个核心类src/Console下则细分出CommandRegistry.php、ConsoleApplication.php、Input/InputParser.php、Mapper/CLIRequestMapper.php、Mapper/CommandRunParametersMapper.php、Output/输出系列与ValueObject/值对象系列src/Reflection下正是参数解析三件套ParameterDescriptionResolver、ParameterOptionMarkerResolver、ParameterTypesResolver等。二、容器篇反射驱动的依赖注入2.1 自动发现指向一个目录全目录类皆服务CLAUDE.md 的核心主张是把容器指向一个目录目录里每个类都自动成为可用服务。README 给出了最小用法use Entropy\Container\Container; $container new Container(); $container-autodiscover(__DIR__ . /src); $someService $container-make(SomeService::class);从源码看autodiscover()的实现在 src/Container/Container.php通过Assert::directory($directory)校验目录存在委托Autodiscovery::autodiscoverDirectory()用FileFinder::findPhpFiles()扫描目录内所有 PHP 文件逐个用ClassNameResolver::resolveFromFilePath()从文件路径解析出类名对已实例化instances或已注册工厂serviceFactories的类跳过为其余每个类注册一个懒加载工厂——真正make()时才用ReflectionClass实例化。Autodiscoverysrc/Container/Autodiscovery.php内部还会过滤掉不适合当服务的类接口isInterface()、异常isSubclassOf(Throwable::class)、枚举isEnum()以及没有父类也没有实现任何接口的裸类。源码中还留有 TODO 注释计划进一步排除命名空间含 ValueObject/DTO/Enum/Exception 的类。2.2 手动注册工厂需要自定义构造时当默认的反射装配无法满足例如需要外部资源、带参数的 PDO 连接时用service()注册工厂$container-service(PDO::class, function (Container $container): PDO { return new PDO(sqlite::memory:); });注意service()的语义是唯一注册源码在 src/Container/Container.php 中若同类已注册工厂会直接抛出RegisterServiceException防止静默覆盖同时一个工厂会取代同一类的裸注册。此外还有register()方法可登记无工厂、按需反射构建的类且是幂等的。2.3 契约查找按接口拿回所有实现需要某个接口的所有实现时用findByContract()$listeners $container-findByContract(EventListenerInterface::class);底层逻辑src/Container/Container.php先通过warmUpInstanceServices()把已知属于该契约的工厂类与注册类全部make()预热进缓存再array_filter出所有instanceof该接口的实例最后array_values重新索引——这样返回的是纯 0 索引列表可以直接展开给变参使用如new Traverser(...$services)不会因类名作为键而变成命名参数。构造函数中ParameterTypesResolver解析出array类型的参数时容器正是调用findByContract()注入整个实现集合。2.4 循环依赖检测A - B - C - A容器在创建过程中维护making与makingStack两个结构src/Container/Container.phpmake()时先把类标记为构建中并压栈若再次遇到正在构建的类就用栈定位环的起点拼出精确的循环链并抛出CreateServiceException错误信息形如Circular dependency detected: A - B - C - A。构建完成后无论成败都会在finally中弹栈并解除标记确保一次异常不会污染后续解析。此外容器还提供afterResolving()回调在实例构建完成后执行一次可用于规避构造环的 setter 注入与forgetByContract()按契约遗忘工厂、注册与缓存实例。值得注意Container类被刻意设计为非 final 且可扩展源码注释标注api extendable container供需要自定义解析策略的应用继承。三、控制台篇run() 签名即 CLI 契约3.1 实现 CommandInterface命令自动接线控制台侧的核心约定是一个命令的run()方法签名就是它的命令行定义。参数类型、默认值和 docblock 会自动翻译成 CLI 参数、选项与帮助文本——不需要任何 attribute不需要手动接线输入对象。use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; use Entropy\Console\Output\OutputPrinter; final readonly class HelloCommand implements CommandInterface { public function __construct( private OutputPrinter $outputPrinter ) { } public function getName(): string { return hello; } public function getDescription(): string { return Say hello; } /** * param string[] $names Names to greet. * param bool $loud Shout instead of speak. */ public function run(array $names, bool $loud false): int { foreach ($names as $name) { $greeting $loud ? HELLO {$name}! : Hello {$name}; $this-outputPrinter-green($greeting); } return ExitCode::SUCCESS; } }接口本身src/Console/Contract/CommandInterface.php极简只需返回非空字符串的getName()与getDescription()run()甚至没有在接口中声明签名注释写明了with many arguments完全由实现类自由定义。final readonly类、构造器注入OutputPrinter等写法与现代 PHP 风格完全兼容。3.2 启动应用三行代码完成引导在入口二进制中引导整个应用use Entropy\Console\ConsoleApplication; use Entropy\Container\Container; $container new Container(); $container-autodiscover(__DIR__ . /src); $consoleApplication $container-make(ConsoleApplication::class); exit($consoleApplication-run($argv));容器构造函数里预设了一个内置工厂src/Container/Container.phpCommandRegistry会通过findByContract(CommandInterface::class)自动收集所有命令——这就是实现接口即自动接线的机制来源。ConsoleApplication::run()src/Console/ConsoleApplication.php随后完成解析argv→ 解析命令名 → 处理默认命令/帮助 → 映射参数 →$command-run(...$runArguments)展开调用任何异常都会以红底输出并返回ExitCode::ERROR。运行命令bin/console hello Alice Bob --loud3.3 参数/选项的映射规则由CommandRunParametersMappersrc/Console/Mapper/CommandRunParametersMapper.php实现签名到 CLI 定义的翻译规则如下第一个string/array参数按约定成为位置参数positional argument其余参数一律变成--option复数数组选项名自动单数化$names参数会变成--name$options变成--option源码中用substr_compare(..., s)判断末尾的s并去掉驼峰参数名转 kebab-case 选项名dryRun→--dry-runcamelToKebab()的preg_replace(/[A-Z]/, -$0, ...)逻辑布尔参数是开关bool $loud false默认false出现--loud即为真默认值参与映射[]这类无意义默认值会被归一化为null源码 CommandRunParametersMapper.php每个参数必须有显式类型声明否则抛出InvalidCommandExceptiondocblock 的param描述会进入帮助文本ParameterDescriptionResolver负责解析。3.4 option 强制标记让首参也变成选项按约定第一个 string/array 参数是位置参数若希望它变成--option在 docblock 中标注option $name/** * option $source * param string $source The source path */ public function run(string $source, bool $verbose false): int { // ... }bin/console hello --sourcesrc/ParameterOptionMarkerResolversrc/Reflection/ParameterOptionMarkerResolver.php负责解析它读取run()的 docblock逐行匹配/^option\s\$([A-Za-z_]\w*)\b/收集所有被标记的参数名。CommandRunParametersMapper中只要首参命中optionMarkers就会被归入选项而非参数CLIRequestMapper同样据此保证被标记的参数绝不消费位置参数src/Console/Mapper/CLIRequestMapper.php。3.5 类型强制转换与校验CLI 字符串到类型化参数CLIRequestMapper::castValueByParameterType()src/Console/Mapper/CLIRequestMapper.php把 CLI 上拿到的字符串按反射类型转换bool→filter_var($value, FILTER_VALIDATE_BOOLEAN)int→(int) $valuefloat→(float) $valuestring→(string) $valuearray→(array) $value标量类型收到数组时先array_shift取单值空值回落到参数默认值映射的完整优先级同文件resolveArguments()为① 已出现的--option优先 → ②option标记参数无值时取默认/false仍缺失则抛ConsoleInputMappingException→ ③ 变参...$values消费全部剩余位置参数 → ④array类型参数把剩余位置参数收成单个数组 → ⑤ 单个位置参数 → ⑥ 默认值/布尔回退/必需值缺失报错。最后还会兜底校验多余位置参数提示改用array $values或变参收集与未知选项--help、--h、--version、--quiet等全局标志被显式忽略都会报错。3.6 输入解析--optvalue、--opt value 与 -v 短标志InputParser::parse()src/Console/Input/InputParser.php处理argv的全部形态长选项--namevalue用explode(, $item, 2)拆分长选项--name value会把下一个非-开头的 token 当作值消费裸长选项--name值为true短标志-v记为$options[v] true非数值的重复选项会累积成数组支持多值选项其余 token 全部进入位置参数列表。3.7 命令注册表重复检测、模糊匹配与默认命令CommandRegistrysrc/Console/CommandRegistry.php在构造时即校验至少注册一个命令、命令名与描述非空、必须存在run()方法、命令名不得重复否则抛InvalidCommandException。命令名拼错时FuzzyMatcher会给出最接近的匹配实现DefaultCommandInterface的命令在无命令名时兜底执行且未知的首个 token 会被当作它的第一个参数如ecs src实现HiddenCommandInterface的命令不会出现在帮助列表getVisible()。四、帮助系统与模糊匹配CLAUDE.md 明确指出传--help显示全局帮助传command --help显示由 docblock 生成的逐命令帮助。ConsoleApplication::run()中的分支逻辑src/Console/ConsoleApplication.php证实了这一点无命令名且带--help/-h时打印全局帮助CLIRequest::isCommandHelp()为真时由CommandHelpFactory基于run()签名与param描述构建该命令专属帮助文本经HelpPrinter输出。也就是说帮助文档完全由 docblock 驱动写注释即写帮助不存在需要单独维护的文档文件。五、约定与工程质量让框架保持极简的约束CLAUDE.md 在 Conventions 一节总结的约定正是保持框架零配置的纪律run()签名即 CLI 契约——第一个string/array参数是位置参数其余是--option必要时用option $name强制改为选项复数数组选项名自动单数化$names→--name无 YAML、无装配 attribute、无魔法字符串——一切由容器自动发现契约查找按接口收集实现测试使用 PHPUnit 12tests/**/Fixture/下的 fixture 类排除在 Rector 规则之外避免自动重构误伤测试夹具。CLAUDE.md 还给出了一套完整的开发命令配合 composer.json 中的 require-dev 依赖vendor/bin/phpunit # 运行测试 vendor/bin/ecs # 编码规范检查 vendor/bin/ecs --fix # 自动修复编码规范 vendor/bin/rector # 应用 Rector 自动重构 vendor/bin/rector --dry-run # 预览 Rector 变更不落盘 vendor/bin/phpstan # 静态分析 vendor/bin/composer-dependency-analyser # 未使用/遮蔽依赖分析配置composer-dependency-analyser.php这套命令链覆盖了测试、编码规范EasyCodingStandard、自动重构Rector、静态分析PHPStan与依赖体检ShipMonk 的 composer-dependency-analyser与require-dev中的phpunit/phpunit: ^12.5、symplify/easy-coding-standard: ^13.1、phpstan/phpstan: ^2.1、rector/rector: ^2.4、shipmonk/composer-dependency-analyser: ^1.8等依赖一一对应构成一个可直接复用的 PHP 包工程质量基线。六、写在最后这套设计的适用场景Entropy 的设计哲学可以概括为把契约全部收进类型签名与 docblock让框架只做反射翻译。其价值在于对小型到中型 PHP 8.3 应用容器自动发现 契约查找让服务注册代码趋近于零控制台命令零样板——写一个类、定义run()签名与注释CLI 参数、选项、帮助文本全部自动生成循环依赖检测、未知参数/选项报错、模糊命令匹配等防御性设计让错误在运行第一时间以清晰的异常信息暴露。如果后续计划开发遵循约定优于配置的 PHP CLI 工具或微应用src/Container与src/Console两套模块连同其tests/镜像结构可作为最直接的参考实现tests/**/Fixture/的目录划分方式与composer-dependency-analyser.php的依赖审计配置也是值得借鉴的工程实践。【免费下载链接】rectorInstant Upgrades and Automated Refactoring of any PHP 5.3 code项目地址: https://gitcode.com/GitHub_Trending/re/rector创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →