PHP Composer 与命名空间
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
require 一堆文件的日子早就过去了。Composer 负责两件事:装第三方包、按命名空间自动加载你自己的类。
环境准备
需要 PHP 8.4 与 Composer 2.8。确认安装:
php -v
composer --version
初始化项目
mkdir blog-api && cd blog-api
composer init --name="demo/blog-api" --type=project --no-interaction
生成的 composer.json 大致是这样:
{
"name": "demo/blog-api",
"description": "示例项目",
"type": "project",
"require": {
"php": ">=8.3"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"config": {
"sort-packages": true
}
}
autoload.psr-4 的规则:App\Foo\Bar 对应 src/Foo/Bar.php。一个前缀映射一个目录,前缀必须以反斜杠结尾,很容易写错。
命名空间
<?php
// src/Post/PostRepository.php
declare(strict_types=1);
namespace App\Post;
final class PostRepository
{
public function all(): array
{
return [];
}
}
<?php
// public/index.php
declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use App\Post\PostRepository;
$repo = new PostRepository();
var_dump($repo->all());
要点:
- 一个文件一个类,文件名与类名一致(大小写敏感,Linux 上写错就是找不到)。
namespace必须是文件第一条语句(declare除外)。use只是别名,不触发加载;真正加载由自动加载器按需完成。- 同一命名空间下的类可以直接用短名,跨命名空间必须
use或写全限定名\App\Post\PostRepository。
use 的几种写法:
use App\Post\PostRepository; // 导入类
use App\Post\PostRepository as Repo; // 别名
use function App\Support\escape; // 导入函数
use const App\Support\VERSION; // 导入常量
use App\Post\{Post, PostRepository}; // 分组导入
安装第三方包
composer require guzzlehttp/guzzle
composer require --dev phpunit/phpunit
require进require段,运行时必需;--dev进require-dev,部署时composer install --no-dev会跳过。- 装完自动更新
composer.lock。锁文件要提交,它记录每个包的确切版本。 vendor/不要提交,部署时按锁文件重装。
版本约束:
| 写法 | 含义 |
|---|---|
^3.9 |
>=3.9 <4.0,允许小版本升级 |
~3.9.2 |
>=3.9.2 <3.10,只允许补丁级 |
3.9.* |
同上 |
>=3.9 <4.0 |
显式范围 |
^ 是最常用也最容易踩的:主版本升级可能带破坏性变更,composer update 之后一定要跑测试。
常用命令
composer install # 按锁文件安装(无锁文件才解析 composer.json)
composer update # 更新依赖并改写锁文件
composer update vendor/package # 只更新一个包
composer dump-autoload # 重新生成自动加载(新增类没生效时用)
composer outdated # 列出可升级的包
composer why guzzlehttp/psr7 # 谁引入了这个包
composer validate # 检查 composer.json 是否合法
CI 与部署环境:
composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction
--optimize-autoloader 生成 classmap,类多时加载更快;改了类名要重新生成。
自动加载自定义函数
PSR-4 只管类。函数、常量、需要提前执行的引导文件用 files:
{
"autoload": {
"psr-4": { "App\\": "src/" },
"files": ["src/Support/helpers.php"]
}
}
files 里的文件每次请求都会加载,别放重逻辑,也别在里面查数据库。
脚本
composer.json 的 scripts 可以固化常用命令:
{
"scripts": {
"test": "phpunit",
"serve": "php -S localhost:8000 -t public"
}
}
composer test
composer run serve
配合 post-install-cmd / post-update-cmd 可以做安装后的初始化(清缓存、生成代理类等),但不要放需要人工确认的操作。
生产环境注意
APP_ENV、数据库密码走环境变量,不进仓库;.env加到.gitignore,提供.env.example。- 使用
composer.lock安装,禁止在生产直接composer update。 vendor/目录权限要可读不可写(除个别需要缓存的包)。- 版本锁定到 PHP 次版本时,部署机的 PHP 版本要一致,否则
composer install可能因平台要求失败(--ignore-platform-reqs是掩盖问题,不是解决)。
常见错误与注意事项
1. 命名空间与目录不匹配
App\Post\PostRepository 放到 src/Repository/PostRepository.php,只有 classmap 才能救;按 PSR-4 放对目录最省事。
2. 改了类名没重新 dump
生产环境开了 --optimize-autoloader 后,classmap 是静态的,新增类必须 composer dump-autoload -o。
3. 直接改 vendor/
下次 composer install 就没了。要改行为就 fork、打补丁(cweagans/composer-patches)或提 PR。
4. 用 * 或 dev-main 当依赖版本
构建不可复现,随时可能拉到不兼容的提交。生产依赖固定到 tag。
5. 忘了 require vendor/autoload.php
命令行脚本报 Class not found,多半是缺这一行,或者路径写成了相对路径(用 __DIR__)。
6. 在 files 里做副作用
比如启动 session、连数据库,导致 CLI 脚本也跟着跑。files 只放纯函数与常量。
7. 平台差异
开发机 PHP 8.4、服务器 8.2,composer install 直接失败。config.platform.php 可以显式声明目标版本:
{ "config": { "platform": { "php": "8.2.0" } } }
小结
- Composer 管依赖,PSR-4 管命名空间到目录的映射。
- 锁文件保证可复现,部署用
composer install --no-dev -o。 - 版本约束优先
^,升级主版本必须跑测试。 - 函数与常量走
autoload.files,不要在里面写副作用。 - 命名空间、目录、文件名三者一致,能省掉大部分「找不到类」。