虚拟包无法调试,必须转为真实本地包:虚拟包仅是provide声明的占位符,不生成vendor目录、不参与autoload;需新建本地包,用path仓库接入并验证符号链接、类加载和接口存在。

虚拟包不能调试,必须转为真实本地包才能调试。 Composer 没有“虚拟包调试”这个概念——所谓虚拟包(如 phpunit/phpunit、ext-curl)只是声明式依赖占位符,不对应实际代码目录,也不参与 autoload,改不了、断不了点、加不了日志。真要调试,唯一路径是:把目标逻辑抽出来,做成一个带 src/ 和 composer.json 的真实本地包,并用 path 仓库接入主项目。
为什么 composer require 虚拟包后没法调试
虚拟包本质是 provide 声明,常见于扩展依赖(ext-json)、工具替代(phpunit/phpunit 提供 phpspec/prophecy)或抽象接口(psr/log)。它们:
- 不生成
vendor/下的真实目录,composer install不会解包或链接任何文件 - 不触发
autoload配置,class_exists()查不到实现类(因为根本没实现) - 无法在 IDE 中跳转到源码,更无法设断点或修改行为
- 运行时若报
Class not found,问题一定出在你漏写了真实提供者(比如没requiremonolog/monolog却用了PsrLogLoggerInterface)
怎么把“想调试的虚拟包逻辑”落地成可调试本地包
以想调试 psr/http-client 的实际调用行为为例(它本身是接口定义,无实现):
- 新建目录
../my-http-client-impl,执行composer init,填入 name:my-vendor/http-client-impl - 在
composer.json中写明:"provide": {"psr/http-client": "^1.0"},并配置"autoload": {"psr-4": {"MyVendor\HttpClient\": "src/"}} - 创建
src/Client.php,实现PsrHttpClientClientInterface,加var_dump(__METHOD__)方便验证 - 主项目
composer.json加 repositories:{"type": "path", "url": "../my-http-client-impl"},然后require:"my-vendor/http-client-impl": "@dev" - 运行
composer update my-vendor/http-client-impl,确认vendor/my-vendor/http-client-impl是符号链接(Linux/macOS)或目录映射(Windows)
调试前必须验证的三件事
少验一项,就可能白忙一小时:
- 执行
readlink vendor/my-vendor/http-client-impl(Linux/macOS)或dir vendormy-vendorhttp-client-impl(Windows),输出必须指向你的本地目录,不是空或报错 - 运行
php -r "echo class_exists('MyVendorHttpClientClient') ? 'ok' : 'fail';",输出ok才说明生产 autoload 生效 - 运行
php -r "echo interface_exists('PsrHttpClientClientInterface') ? 'ok' : 'fail';",确保接口本身已加载(通常由psr/http-client包提供,需composer require --dev psr/http-client)
真正难的不是配 path 仓库,而是厘清“谁提供接口、谁实现接口、谁在用接口”这三层关系。一旦把虚拟声明转成真实代码路径,后续所有调试手段(xdebug、日志、单步)就都回来了——但前提是,你得先让那个类真的存在、能被加载、且和你在编辑器里打开的是同一个文件。











