composer install 不能直接打包 vendor,因为需执行 --no-dev --optimize-autoloader 生成优化 autoload 和排除开发依赖,且 vendor 中的 installed.json、vendor/bin/ 脚本、构建产物等为环境相关,复制即失效。

composer install 为什么不能直接打包 vendor?
因为 composer install 默认只装 vendor/autoload.php 和依赖代码,但不保证所有文件都可移植:有些包含 post-install-cmd 脚本(比如生成 classmap、编译扩展),跳过这些步骤会导致运行时报 Class not found;还有些包通过 composer bin 注册二进制命令,或依赖 vendor/bin 下的软链,直接复制可能断链。
打包前必须执行 composer install --no-dev --optimize-autoloader
这是最常被跳过的一步。不加这两个参数,打包出来的 vendor 可能包含开发依赖(如 phpunit)、未优化的 autoload 映射,体积大且启动慢,迁移后还可能因环境差异触发 dev-only 的自动加载逻辑。
-
--no-dev:排除require-dev中的包,避免把测试工具带到生产环境 -
--optimize-autoloader:生成vendor/composer/autoload_classmap.php,让类加载从 O(n) 降到 O(1),否则迁移后首次请求可能卡顿几秒 - 务必在目标环境同版本 PHP 下执行,否则
opcache.preload或某些ext-*兼容性会出问题
哪些文件/目录不能直接复制?
vendor 看似全是代码,但以下内容要么是生成的、要么是环境相关的,复制即错:
-
vendor/composer/installed.json:记录已安装包的完整哈希和路径,不同机器路径不同,复制后composer show会混乱 -
vendor/bin/下的脚本:很多是带绝对路径的 shell wrapper(比如#!/usr/bin/env php+require __DIR__.'/../autoload.php'),换环境后vendor/路径一变就失效 -
vendor/<package>/src/</package>以外的构建产物:比如vendor/monolog/monolog/build/或vendor/doctrine/orm/tools/,属于本地构建缓存,非源码
真正安全的打包方式:tar + 排除动态文件
别用 cp -r vendor/ /target/,用 tar 显式控制内容。核心是保留源码和优化后的 autoload,剔除运行时生成物:
tar -czf vendor.tar.gz \
--exclude='vendor/*/build' \
--exclude='vendor/*/tests' \
--exclude='vendor/*/Tests' \
--exclude='vendor/composer/installed.json' \
--exclude='vendor/bin/*' \
vendor/
解压后,在目标机上仍需补一行:composer dump-autoload --optimize——不是为了重新生成 classmap(它已存在),而是重建 vendor/composer/autoload_static.php 里的路径常量,否则某些静态分析工具或 IDE 会找不到符号。
路径硬编码、autoload 静态化、dev 依赖残留——这三个点,只要漏一个,迁移后就不是“少个文件”的问题,而是整个 autoloader 失效。










