PHP Scoper 是一个独立的PHP CLI工具,用于在打包阶段重写代码及依赖的命名空间以实现隔离;它不参与composer install流程,必须显式执行且需正确配置finders、prefix和dump-autoload等选项。
PHP Scoper 是什么,为什么不能直接用 Composer install
PHP Scoper 不是 Composer 的子命令,也不是
里配个字段就能生效的工具。它是一个独立的 PHP CLI 工具,作用是在打包阶段把你的代码 + 所有依赖的命名空间全部重写(加前缀),让它们和宿主环境或其他插件彻底隔开。你运行
只是下载依赖,根本不会触发任何重命名操作。
常见错误现象:
– 写完
放进
的
,以为装上就自动隔离了
– 把
配置文件丢进项目根目录,但没手动执行
命令
– 在 CI 里只跑
,漏掉 scoping 步骤,导致打包后仍冲突
必须显式调用
CLI,通常在构建/打包环节执行
它不修改原始源码,而是生成一个全新输出目录(比如
),所有文件都已重命名
Composer 只负责依赖管理,Scoper 负责代码改造 —— 二者职责完全分离
怎么配置 scoper.php 让 vendor 里的类真正带上前缀
默认配置下,PHP Scoper 不会处理
里的代码 —— 它只扫描你指定的源目录(如
)。要让依赖也被重命名,得手动告诉它哪些包需要“纳入作用域”,否则
还是
,根本没隔离。
关键点在于
和
的组合使用:
立即学习
“
PHP免费学习笔记(深入)
”;
用
显式加入你想处理的 vendor 包路径
在
设为
,避免全局常量泄露(比如
)
必须设成非空字符串,例如
;空值或
会导致跳过重命名
如果用了
自动加载机制(如 PSR-4),记得同步更新
下的
中的
配置,否则 require 时报错 Class not found
示例片段(
):
Composer 2.9.6
Composer 2.9.6 是 PHP 生态中高效、稳定的依赖管理工具。此版本在性能与兼容性上进一步优化,改进了依赖解析算法,提升大型项目中的安装与更新速度。它支持并行下载任务,显著减少等待时间,并增强了与私有仓库及镜像源的交互稳定性。同时修复了多项命令行交互与内存使用相关的缺陷,确保在复杂依赖关系下依然可靠运行。无论是新项目初始化还是现有系统维护,Composer 2.9.6 都能为开发者提供流畅、精准的依赖管理体验。
下载
为什么 scoped 后的代码 require 失败:autoload 没跟上
PHP Scoper 生成的
目录里,类名变了(比如
→
),但
里的 autoload 规则还是旧的,
就会找不到类 —— 这是最常卡住人的地方。
Scoper 默认会为你生成一份新的
,但它依赖你是否启用了
选项:
必须开启
,否则不会生成
生成的 autoloader 默认按 PSR-4 映射新前缀,比如
如果你的项目用了 classmap 或 files 加载方式,Scoper 不会自动转换它们,得手动补到
的
配置里
别直接 require 原项目的
,scoped 后必须用
PHP Scoper 和 Composer 的 autoloader 冲突怎么办
当你的项目既要支持本地开发(用原 vendor),又要发布 scoped 包(用 build/),很容易在同一个进程里混用两个 autoloader,结果类被重复定义,报
。
这不是 Scoper 的 bug,而是加载顺序问题:
不要在 scoped 包里再
—— 这等于把原始类又载入一遍
scoped 后的代码应完全脱离原始 vendor,所有依赖都从
加载
如果必须共存(比如插件系统),用
控制性加载,避免自动触发 autoload
注意 Composer 的
配置对 Scoper 无效,它只影响
生成的文件名,不改变命名空间
最稳的做法:scoped 包对外只暴露一个入口文件(如
或
),里面只 require 自己的
,彻底切断和外部 autoloader 的联系。
composer.jsoncomposer install"php-scoper": "^4.0"composer.jsonrequire-devscoper.phpphp-scopercomposer installphp-scoperbuild/vendor/src/monolog/monologMonologLoggerfinderspatchersFinder::create()->files()->in('vendor/symfony/console')expose-global-constantsfalseJSON_THROW_ON_ERRORprefix'MyApp'nullautoloadbuild/composer.jsonautoloadscoper.php
return [
'prefix' => 'MyApp',
'finders' => [
Finder::create()->files()->in('src'),
Finder::create()->files()->in('vendor/symfony/console'),
Finder::create()->files()->in('vendor/monolog/monolog'),
],
'expose-global-constants' => false,
];
build/MonologLoggerMyAppMonologLoggercomposer.jsonrequire 'build/autoload.php'autoload.phpdump-autoload'dump-autoload' => truebuild/vendor/autoload.php"MyApp\Monolog\" => "monolog/monolog/src/"scoper.phpautoloadvendor/autoload.phpbuild/vendor/autoload.phpFatal error: Cannot declare class ... because the name is already in userequire __DIR__.'/../../vendor/autoload.php'build/vendor/class_exists('MyAppMonologLogger', false)autoloader-suffixcomposer dump-autoloadmyapp.pharbuild/index.phpautoload.php