composer 不支持 .so 文件自动加载,因其仅处理 php 类、接口、trait 和函数文件;psr-4 和 classmap 依赖 require/include 加载 php 源码,而 .so 是需通过 php.ini 或 dlopen() 加载的二进制扩展,autoloader 无法触达该层级。

Composer 本身不支持、也不处理 .so 文件的“自动加载”——它只管 PHP 类、接口、trait 和函数文件(files 类型)。把 .so 当作“类”去 autoload,是根本方向错误。
为什么不能用 PSR-4 或 classmap 加载 .so 文件
PSR-4 是字符串替换规则,classmap 是类名 → PHP 文件路径映射,两者都依赖 require/include 加载 PHP 源码。而 .so 是编译后的 C 扩展二进制模块,必须通过 extension=xxx.so 写入 php.ini,或运行时调用 dlopen()(PHP 层面不可见);PHP 的 autoloader 机制完全无法触达这个层级。
-
.so不是 PHP 文件,没有命名空间、类定义、<?php开头,class_exists()和spl_autoload_register()对它无效 - 试图在
composer.json的autoload或autoload-dev中写"ext/": "ext/",不会生成任何映射,也不会触发dl()(该函数自 PHP 8.0 起已被移除) - 把
.so放进files列表会直接报错:Cannot declare extension 'xxx', because the name is already in use或更底层的Failed loading extension
正确接入 .so 扩展的三个实际路径
对外部 .so 的“共享对象管理”,本质是扩展部署 + 运行时桥接,不是 autoload 问题。真正要做的只有三件事:
- 确保
.so已编译适配当前 PHP 版本(如 PHP 8.5.5)、架构(x86_64/arm64)、线程模型(ZTS/non-ZTS),并放在extension_dir下(可通过php -i | grep extension_dir查) - 在
php.ini或conf.d/下新增配置:extension=your_ext.so;若需 ini 设置(如your_ext.api_key=xxx),一并写入 - 在 PHP 代码中显式检查和使用:
if (!extension_loaded('your_ext')) { throw new RuntimeException('Extension your_ext not loaded'); },之后调用其函数(如your_ext_do_something())或类(如果该扩展暴露了 PHP 类)
如何让 Composer 项目“感知” .so 依赖并校验环境
虽然不能 autoload .so,但可以用 Composer 的 require 和脚本钩子做前置约束和提示:
- 在
composer.json的require中加虚拟包:"ext-your_ext": "*"(注意前缀ext-),再配合composer validate或 CI 检查,提醒开发者该扩展必须存在 - 写
scripts钩子,在post-install-cmd或post-autoload-dump里执行 PHP 脚本:php -r "if (!extension_loaded('your_ext')) exit(1);",构建失败时立刻暴露问题 - 若该
.so提供了 PHP 类(如某些 SDK 封装),这些类应放在普通 PHP 文件中(如src/YourExt/Client.php),走标准 PSR-4;.so只作为底层驱动,由这些 PHP 类内部调用
真正容易被忽略的是:很多团队误以为“把 .so 放进项目目录、再配个 autoload 就能跨环境自动加载”,结果在 Docker 构建或不同 PHP 版本下反复失败。记住——.so 是 PHP 解释器的插件,不是 PHP 代码;它的生命周期在 autoloader 启动之前就结束了。











