2. composer.json 深度解析:详解 require、require-dev、autoload、scripts 等配置项

说实话,很多 PHP 开发者把 composer.json 当成一个「填名字和版本号」的配置文件。我以前也这么干过,直到有一次线上环境因为 autoload 配置写错,导致类加载失败,排查了整整一个下午。嗯,从那以后,我每次写 composer.json 都会仔细过一遍每个字段。

这一章,咱们就把 composer.json 里最核心的几个配置项掰开揉碎讲清楚。你想想看,搞懂了这些,你才算真正掌握了 Composer 的命脉。

2.1 require:项目的「硬依赖」

require 字段定义的是项目必须安装的依赖包。说白了,少了它们,你的项目就跑不起来。

{
    "require": {
        "php": ">=8.1",
        "laravel/framework": "^10.0",
        "monolog/monolog": "~2.0"
    }
}

这里有几个版本约束的写法,我简单说一下:

  • 精确版本1.0.0,只安装这个版本,不推荐,太死板
  • 波浪号 ~~2.0 表示 >=2.0.0 且 <3.0.0,适合小版本升级
  • 脱字符 ^^10.0 表示 >=10.0.0 且 <11.0.0,我个人最常用这个
我的习惯:对于框架这类核心依赖,我会用 ^ 约束,既能拿到安全更新,又不会因为大版本升级而炸掉。对于工具类库,比如 monolog,用 ~ 更稳妥。

2.2 require-dev:开发环境的「专属工具」

require-dev 里的包,只在开发环境安装。生产环境用 composer install --no-dev 就能跳过它们。

{
    "require-dev": {
        "phpunit/phpunit": "^10.0",
        "mockery/mockery": "^1.5",
        "barryvdh/laravel-ide-helper": "^2.12"
    }
}

我在项目中遇到过好几次这样的问题:有人把 phpunit 写到了 require 里,结果生产环境部署时,composer 安装了一大堆测试框架的依赖,包体积直接翻倍。你想想看,这多浪费资源?

避坑指南:我曾经见过一个项目,把 fakerdebugbar 都写在了 require 里。结果生产环境上线后,用户能看到调试工具栏……嗯,场面一度非常尴尬。记住:只有生产环境用不到的,才放 require-dev

2.3 autoload:让 PHP 自动找到你的类

autoload 配置决定了 Composer 如何加载你的代码。我见过太多人直接忽略这个字段,结果每次新增类都要手动 require 一遍。

{
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Migrations\\": "database/migrations/"
        },
        "classmap": [
            "database/seeds/",
            "app/Legacy/"
        ],
        "files": [
            "app/helpers.php"
        ]
    }
}

这里三种方式各有用途:

方式 适用场景 性能
PSR-4 现代项目,命名空间与目录结构一致 按需加载,性能好
classmap 遗留代码,没有命名空间 一次性扫描,加载快但占用内存
files 全局函数、辅助方法 每次请求都加载

重点来了:每次修改 autoload 配置后,记得执行 composer dump-autoload。我刚开始用 Composer 时经常忘记这步,结果类一直加载失败,还以为是代码写错了。

2.4 scripts:自动化你的工作流

scripts 是 composer.json 里被严重低估的功能。说白了,它让你能在 Composer 命令执行前后,自动跑一些脚本。

{
    "scripts": {
        "pre-update-cmd": [
            "echo '准备更新依赖...'",
            "php artisan down"
        ],
        "post-update-cmd": [
            "php artisan migrate",
            "php artisan cache:clear"
        ],
        "post-install-cmd": [
            "php artisan storage:link"
        ],
        "test": "phpunit",
        "check": [
            "@test",
            "phpstan analyse"
        ]
    }
}

我个人习惯把常用的命令都定义成脚本。比如:

  • composer test 直接跑测试
  • composer check 同时跑测试和静态分析
  • 部署时自动执行迁移和缓存清理
我的经验:在 post-install-cmd 里放 php artisan storage:link 特别实用。这样新同事拉完代码,执行 composer install 后,存储链接就自动创建好了,省得每次都要手动操作。

2.5 其他常用配置项

除了上面四个核心配置,还有几个字段我经常用到:

{
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true
    },
    "extra": {
        "laravel": {
            "dont-discover": [
                "spatie/laravel-permission"
            ]
        }
    },
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/mycompany/private-package"
        }
    ]
}

这里我挑几个重点说一下:

  • optimize-autoloader:生产环境建议开启,能生成优化后的类映射,提升加载速度
  • sort-packages:自动按字母排序 require 里的包,代码更整洁
  • repositories:当你需要引用私有包时,这个字段就是救星
注意:config 里的 preferred-install 设为 dist 能加快安装速度。但如果你在调试某个包的源码,可能需要改成 source。我一般开发环境用 dist,只有需要改 vendor 里的代码时才切到 source。

2.6 一个完整的 composer.json 示例

最后,我放一个实际项目中用到的配置,你可以参考一下:

{
    "name": "mycompany/myapp",
    "description": "企业级 PHP 应用",
    "type": "project",
    "require": {
        "php": "^8.1",
        "laravel/framework": "^10.0",
        "guzzlehttp/guzzle": "^7.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.0",
        "nunomaduro/collision": "^7.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            "app/helpers.php"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

嗯,这个配置基本覆盖了日常开发的大部分场景。你把它当成模板,根据自己的项目改改就能用。

记住一句话:composer.json 不是写一次就完事的。随着项目演进,依赖会变,自动加载规则会变,脚本也会变。定期 review 一下这个文件,能帮你避免很多坑。