平台包是Composer对PHP环境的虚拟描述,不安装代码而仅校验php/ext-xxx/lib-xxx是否满足约束;显式声明内置扩展(如ext-json)可避免运行时函数缺失错误,config.platform用于模拟目标环境而非绕过检查。

平台包不是真实安装的包,而是 Composer 对运行环境的“虚拟描述”
Composer 里的 platform packages(平台包)根本不会下载或解压任何代码,它只是把当前 PHP 环境“翻译”成一组可参与依赖解析的虚拟包。比如你系统装了 PHP 8.3.5、启用了 ext-curl 和 ext-mbstring,Composer 就会把这些信息建模为:php:8.3.5、ext-curl:8.3.5、ext-mbstring:8.3.5 —— 它们就像普通包一样参与版本约束匹配,但不提供任何源码。
这种机制让 require 字段既能写 "monolog/monolog": "^3.0"(真包),也能写 "php": "^8.2" 或 "ext-json": "*"(平台包),统一用同一套依赖求解器处理。
-
php、ext-xxx、lib-xxx都属于平台包,全部在composer.json的require或require-dev中声明 - Composer 不安装它们,只检查:运行时是否满足这些“虚拟包”的版本约束
- 检查方式很直接:对
ext-xxx调用extension_loaded('xxx');对php比对PHP_VERSION_ID - 若不满足,
composer install直接报错中断,连vendor/autoload.php都不会生成
为什么 ext-json 这类扩展要显式声明,哪怕它是 PHP 内置的
虽然 ext-json 自 PHP 5.2 起就内置,不需单独安装,但它仍可能被禁用(比如某些 Docker 基础镜像或安全加固策略会注释掉 extension=json)。不声明,Composer 就不会校验;一旦缺失,运行时遇到 json_encode() 就直接 Fatal error: Uncaught Error: Call to undefined function json_encode()。
显式声明 "ext-json": "*" 是一种契约:告诉协作者和部署流程,“这个函数必须可用”,而不是靠人肉查文档或试错。
立即学习“PHP免费学习笔记(深入)”;
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 所有核心扩展(
ext-json、ext-pcre、ext-spl、ext-hash等)都建议显式声明,哪怕版本约束宽松 -
"ext-json": "^1.4"这类带版本的写法极少必要——因为 PHP 内置扩展通常不暴露稳定版本号;"*"或">=1.0"更实际 - Windows 用户特别注意:
php.ini中对应扩展行不能被分号注释,且路径正确(如extension=php_json.dll)
config.platform 是“假装环境存在”,不是绕过检查的捷径
config.platform 是用来在开发机或 CI 上“模拟”目标环境的,比如你本地是 PHP 8.4,但生产是 PHP 8.2,就可以设 "php": "8.2.10" 让 Composer 解析出兼容 8.2 的依赖版本。但它对 ext-xxx 同样生效——设 "ext-gd": "0",Composer 就认为 GD 扩展不存在,从而拒绝安装依赖 GD 的包。
这不是忽略检查,而是主动伪造平台状态,用于测试兼容性边界。生产部署中滥用它,等于自欺欺人。
- 常见误用:
"ext-xdebug": "0"放进config.platform来“跳过 xdebug 报错”——这会让依赖xdebug-handler的包无法安装,反而破坏调试能力 - 真正该忽略扩展检查的场景极少见,应优先用
--ignore-platform-req=ext-name临时跳过,而非固化到配置里 -
config.platform中的php版本必须 ≤ 实际 PHP 版本,否则 Composer 会拒绝运行(防降级风险)
运行时函数缺失?Composer 管不了,得自己兜底
Composer 只能确保扩展启用,但没法保证某个函数一定存在。比如 ext-openssl 启用了,不代表 openssl_pkey_new() 一定可用(旧版 OpenSSL 库可能没编译进 PHP);再比如你用 mb_str_split(),它只在 PHP 7.4+ 存在,但 ext-mbstring 在 5.3 就有了——这时候光靠 "ext-mbstring": "*" 不够,还得锁 "php": "^7.4"。
更麻烦的是用户自定义函数、files 自动加载的函数、或通过 eval() 动态注册的函数,Composer 完全无感知。
- 函数级依赖必须靠运行时检测:
if (!function_exists('some_function')) { throw new RuntimeException('Missing required function: some_function'); } - 第三方库提供的函数(如
ramsey/uuid的uuid_create())应通过其 Composer 包声明依赖,而不是指望用户手动引入 - 用
composer show --platform查当前环境“被识别出”的平台包,比盲猜靠谱得多
平台依赖不是万能胶,它只管“有没有扩展”,不管“扩展有没有你要的那个函数”。越底层的函数,越容易在跨版本或精简发行版中消失——这点最容易被忽略。


















