十:Composer 与自动加载——现代 PHP 开发的起点

一、回顾与本篇目标

上一篇你学会了 PHP 面向对象编程——类、对象、继承、接口、命名空间。你的代码现在可以用面向对象的方式来组织了——把数据和操作数据的方法封装在类里,通过继承和接口实现代码复用。

但有一个实际问题还没解决:当项目中有几十个甚至上百个类文件时,你需要手动写几十行 require_once 来引入每个类文件。这不仅繁琐,而且容易出错——如果文件名或路径变了,所有引入它的地方都需要修改。更麻烦的是,如果你使用第三方库(比如发送邮件的库、处理图片的库、生成 PDF 的库),你需要手动下载它们的代码,手动引入它们的类文件,手动管理它们之间的依赖关系。

这就是 Composer 要解决的问题。Composer 是 PHP 的包管理器——相当于 Node.js 的 npm、Python 的 pip、C/C++ 的 vcpkg。它帮你做两件核心的事:

  1. 管理依赖:自动下载和更新第三方库,处理库与库之间的依赖关系。
  2. 自动加载类:你只需要声明”这个类在哪个文件里”,Composer 就会在你使用类的时候自动引入对应的文件。不需要写任何 require_once

现代 PHP 开发中,Composer 是必备工具。Laravel、Symfony、WordPress 的现代开发流程都依赖 Composer。学会 Composer,你就打开了 PHP 生态的大门——成千上万个高质量的开源库都可以通过 Composer 一键安装使用。

本篇的目标:

  1. 理解 Composer 是什么、为什么需要它
  2. 学会安装 Composer
  3. 学会用 Composer 安装和管理第三方库
  4. 理解 PSR-4 自动加载规范
  5. 学会配置 Composer 自动加载自己的类
  6. 了解 composer.jsoncomposer.lock 的区别

二、没有 Composer 的时代:手动引入的噩梦

先看看没有 Composer 时,项目是怎么组织的:

<?php
// 手动引入所有需要的类文件
require_once 'app/Database.php';
require_once 'app/Models/User.php';
require_once 'app/Models/Article.php';
require_once 'app/Controllers/UserController.php';
require_once 'app/Controllers/ArticleController.php';
require_once 'app/Middleware/AuthMiddleware.php';
require_once 'app/Helpers/StringHelper.php';
require_once 'app/Helpers/DateHelper.php';
require_once 'vendor/mailer/Mailer.php';
require_once 'vendor/pdf/PDFGenerator.php';
require_once 'vendor/cache/Cache.php';
// ... 几十行 require_once ...

// 现在才能开始写业务逻辑
$userController = new App\Controllers\UserController();
?>

这段代码有几个问题:

  • 繁琐:每新建一个类,就要加一行 require_once。项目有 50 个类就要写 50 行。
  • 容易出错:文件名和路径必须完全匹配。如果把 User.php 改名为 UserModel.php,所有引入它的地方都要改。
  • 不必要的加载:无论请求是否需要这个类,所有文件都会被加载。如果一个请求只需要 UserController,为什么要把 PDFGenerator 也加载进来?
  • 依赖管理困难:如果 Mailer 库又依赖了 Socket 库,你需要手动下载 Socket 库,然后手动保证引入顺序正确。

Composer 一次性解决所有这些问题。

三、安装 Composer

3.1 Windows 安装

  1. 打开浏览器,访问 https://getcomposer.org/download/
  2. 下载 Composer-Setup.exe
  3. 运行安装程序。安装过程中,它会自动找到你系统上的 PHP 路径。如果没有自动找到,手动选择 php.exe 所在目录(比如 C:\php\php.exe)。
  4. 一路点击 Next,完成安装。

3.2 Mac 安装

推荐用 Homebrew:

brew install composer

或者手动安装(如果不用 Homebrew):

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
sudo mv composer.phar /usr/local/bin/composer

3.3 Linux 安装(Ubuntu/Debian)

sudo apt update
sudo apt install composer

3.4 验证安装

打开终端,输入:

composer --version

如果出现类似 Composer version 2.8.x 的版本号,说明安装成功。

四、Composer 的核心文件

4.1 composer.json:项目的依赖声明

composer.json 是 Composer 的配置文件,放在项目根目录。它告诉 Composer:这个项目叫什么名字、依赖哪些第三方库、用什么 PHP 版本、以及如何自动加载类。

一个典型的 composer.json

{
    "name": "myapp/my-blog",
    "description": "一个简单的博客系统",
    "type": "project",
    "require": {
        "php": ">=8.1",
        "monolog/monolog": "^3.0",
        "phpmailer/phpmailer": "^6.9"
    },
    "require-dev": {
        "phpunit/phpunit": "^11.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

关键字段说明:

字段 含义 示例
name 项目名称(格式:组织名/项目名) "myapp/my-blog"
require 生产环境依赖(线上运行必需的库) "monolog/monolog": "^3.0"
require-dev 开发环境依赖(只在本地开发时使用的库,如测试框架) "phpunit/phpunit": "^11.0"
autoload 自动加载配置(告诉 Composer 如何找到你的类文件) "psr-4": {"App\\": "src/"}

版本号中的 ^ 符号^3.0 表示兼容 3.0 到 3.x 的所有版本,但不包括 4.0。这允许你接收 bug 修复和次要功能更新,但不会自动升级到下一个可能破坏兼容性的大版本。

4.2 composer.lock:锁定精确版本

第一次执行 composer install 时,Composer 会生成 composer.lock 文件。这个文件记录了你实际安装的每个库的精确版本号。把它提交到 Git,确保团队所有成员和服务器上安装的是完全相同的依赖版本。

composer.json 和 composer.lock 的分工

  • composer.json:声明”我需要什么库,版本范围是什么”(松散的约束)。
  • composer.lock:记录”上次安装的具体是什么版本”(精确的锁定)。

五、安装第一个第三方库

我们用 Monolog 来演示——这是 PHP 最流行的日志记录库,被 Laravel、Symfony 等框架广泛使用。

5.1 初始化项目

# 创建项目目录
mkdir my-composer-demo
cd my-composer-demo

# 初始化 Composer 项目(交互式,一路回车使用默认值即可)
composer init

或者直接手动创建 composer.json

{
    "name": "demo/composer-demo",
    "description": "学习 Composer 的演示项目",
    "require": {}
}

5.2 安装 Monolog

composer require monolog/monolog

这个命令做了三件事:

  1. https://packagist.org(PHP 的官方包仓库)下载 Monolog 及其所有依赖。
  2. 更新 composer.json,在 require 中添加 Monolog。
  3. 生成或更新 composer.lock,锁定精确版本。

安装完成后,项目结构变成:

my-composer-demo/
├── composer.json          ← 你编辑的配置文件
├── composer.lock          ← Composer 生成的版本锁定文件
├── vendor/                ← 所有第三方库的代码
│   ├── autoload.php       ← Composer 生成的自动加载入口
│   ├── monolog/           ← Monolog 的代码
│   └── psr/               ← Monolog 依赖的 PSR 接口
└── index.php              ← 你的业务代码

vendor 文件夹:所有第三方库的代码都在这里。它相当于 Node.js 的 node_modules、Python 的 site-packages永远不要手动修改 vendor 里的任何文件——它们是 Composer 管理的,composer update 会覆盖你的修改。把 vendor 加入 .gitignore——不提交到版本控制,团队成员通过 composer install 自行安装。

5.3 使用 Monolog 写日志

<?php
// index.php

// 引入 Composer 的自动加载器(只需要这一行!)
require_once __DIR__ . '/vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// 创建日志记录器
$log = new Logger('my-app');
$log->pushHandler(new StreamHandler(__DIR__ . '/app.log', Logger::WARNING));

// 记录不同级别的日志
$log->info('这是一条信息日志');
$log->warning('这是一条警告日志');
$log->error('这是一条错误日志', ['user_id' => 123, 'action' => 'login']);

echo "日志已写入 app.log";
?>

关键点:只需要一行 require_once __DIR__ . '/vendor/autoload.php';,就可以使用所有通过 Composer 安装的类。不需要手动写任何 require_once 引入 Monolog 的文件。

六、Composer 常用命令

命令 作用 对应 npm 命令
composer install 根据 composer.lock 安装所有依赖(部署时使用 npm ci
composer require 库名 安装一个库并添加到 composer.json npm install 库名
composer require --dev 库名 安装到开发环境依赖(不会部署到生产环境) npm install --save-dev 库名
composer update 更新所有依赖到符合 composer.json 的最新版本 npm update
composer remove 库名 卸载一个库并从 composer.json 中移除 npm uninstall 库名
composer dump-autoload 重新生成自动加载文件(修改了 autoload 配置后使用) (无直接对应)

install 和 update 的区别很重要

  • composer install:根据 composer.lock 中锁定的精确版本安装。不会升级任何库。适合部署到生产环境——确保服务器上安装的版本和你在本地测试的版本完全一致。
  • composer update:根据 composer.json 中声明的版本范围,下载最新符合要求的版本,然后更新 composer.lock。适合在本地开发时升级依赖——比如你想把 Monolog 从 3.2 升级到 3.5。

新手容易犯的错误:在服务器上执行 composer update,结果把一个库从 3.2 升级到了 3.5,而 3.5 引入了一个 bug,导致线上服务崩溃。部署时永远用 composer install

七、自动加载自己的类

Composer 不仅能加载第三方库,还能自动加载你自己写的类。你需要遵循 PSR-4 自动加载规范——这是 PHP 社区制定的标准,规定了”命名空间的前缀对应文件目录”。

7.1 PSR-4 规范

PSR-4 的核心规则只有一条:命名空间的前缀对应文件目录,类名对应文件名。

举个例子:

// 命名空间:App\Models
// 类名:User
// 完整类名:App\Models\User
// 文件路径:src/Models/User.php

// 命名空间:App\Controllers\Admin
// 类名:DashboardController
// 完整类名:App\Controllers\Admin\DashboardController
// 文件路径:src/Controllers/Admin/DashboardController.php

你在 composer.json 中配置命名空间前缀到目录的映射:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

这行配置的意思是:所有以 App\ 开头的命名空间,去 src/ 目录下找对应的文件。

配置好之后,执行:

composer dump-autoload

告诉 Composer 重新生成自动加载文件。之后就可以直接使用 use App\Models\User; 了——Composer 会自动引入 src/Models/User.php

7.2 完整的项目示例

项目结构:

my-app/
├── composer.json
├── vendor/
├── src/
│   ├── Models/
│   │   └── User.php
│   └── Controllers/
│       └── UserController.php
├── public/
│   └── index.php          ← 前端入口
└── app.log

composer.json:

{
    "name": "demo/my-app",
    "require": {
        "monolog/monolog": "^3.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

src/Models/User.php:

<?php
namespace App\Models;

class User {
    public function __construct(
        private string $name,
        private string $email
    ) {}

    public function getName(): string {
        return $this->name;
    }

    public function getEmail(): string {
        return $this->email;
    }
}

src/Controllers/UserController.php:

<?php
namespace App\Controllers;

use App\Models\User;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

class UserController {
    private Logger $log;

    public function __construct() {
        $this->log = new Logger('user-controller');
        $this->log->pushHandler(new StreamHandler(__DIR__ . '/../app.log', Logger::INFO));
    }

    public function show(int $id): void {
        $user = new User('张三', 'zhangsan@example.com');
        $this->log->info("显示用户 ID: {$id}");
        echo "用户:{$user->getName()} ({$user->getEmail()})";
    }
}

public/index.php:

<?php
// 只需要这一行,所有类都能自动加载
require_once __DIR__ . '/../vendor/autoload.php';

use App\Controllers\UserController;

$controller = new UserController();
$controller->show(1);

执行:

cd my-app
composer install        # 安装第三方依赖
composer dump-autoload  # 生成自动加载文件
php public/index.php    # 运行

输出:用户:张三 (zhangsan@example.com)

关键点index.php 只需要引入 vendor/autoload.php 这一行。之后使用 use 引入的任何类——不管是自己写的 App\Models\User 还是第三方库的 Monolog\Logger——Composer 都会自动找到对应的文件并加载。

八、autoload 的三种方式

PSR-4 是 Composer 中最常用的自动加载方式,但它不是唯一的方式。Composer 还支持两种方式:

方式 适用场景 配置示例
PSR-4 遵循命名空间规范的类(最常用) "App\\": "src/"
Classmap 不遵循命名规范的旧代码、单一文件 "classmap": ["lib/", "legacy/"]
Files 需要每次请求都加载的全局函数文件 "files": ["app/helpers.php"]

Classmap:Composer 会扫描指定目录下的所有 .php 文件,建立一个”类名 → 文件路径”的映射表。即使这些类没有遵循 PSR-4 命名规范,也能被自动加载。

{
    "autoload": {
        "classmap": ["lib/", "legacy/"]
    }
}

Files:指定一些 PHP 文件,它们会在每次请求时被自动加载。适合存放全局辅助函数。

{
    "autoload": {
        "files": ["app/helpers.php"]
    }
}
<?php
// app/helpers.php —— 全局辅助函数
function view(string $name, array $data = []): void {
    extract($data);
    require __DIR__ . "/views/{$name}.php";
}

function config(string $key, $default = null) {
    // 读取配置文件...
}

配置之后,view()config() 函数就可以在项目的任何位置直接使用,不需要 userequire_once

九、Packagist:PHP 的包仓库

https://packagist.org 是 PHP 官方的公共包仓库。当你执行 composer require monolog/monolog 时,Composer 会去 Packagist 上搜索这个包,下载它的代码,同时下载它依赖的其他包。

Packagist 上有超过 40 万个 PHP 包,覆盖了几乎所有常见的需求:

  • 日志:monolog/monolog
  • 邮件:phpmailer/phpmailer
  • 图片处理:intervention/image
  • PDF 生成:dompdf/dompdf、mpdf/mpdf
  • Excel 读写:phpoffice/phpspreadsheet
  • HTTP 客户端:guzzlehttp/guzzle
  • 测试框架:phpunit/phpunit
  • 加密:defuse/php-encryption
  • 验证:respect/validation
  • 数据库迁移:robmorgan/phinx

需要某个功能时,先去 Packagist 搜索,大概率已经有现成的优质库可以用。

十、Composer 脚本:自动化常见任务

Composer 可以在特定时机自动执行脚本——比如安装依赖后生成配置文件、更新依赖后清理缓存。

{
    "scripts": {
        "post-install-cmd": [
            "php -r \"echo '依赖安装完成!';\""
        ],
        "post-update-cmd": [
            "php bin/clear-cache.php"
        ],
        "test": [
            "phpunit"
        ],
        "serve": [
            "php -S localhost:8080 -t public/"
        ]
    }
}

之后可以执行:

composer test    # 运行 PHPUnit 测试
composer serve   # 启动内置开发服务器

composer test 等价于 npm test,都是运行项目中定义的测试脚本。

十一、Composer 和 npm 的对比

如果你之前跟过《后端零基础入门》用过 npm,这张对比表帮你快速理解 Composer:

功能 npm (Node.js) Composer (PHP)
包管理文件 package.json composer.json
版本锁定文件 package-lock.json composer.lock
依赖安装目录 node_modules/ vendor/
安装依赖 npm install composer install
添加新依赖 npm install 库名 composer require 库名
更新依赖 npm update composer update
开发依赖 --save-dev --dev
公共包仓库 npmjs.com packagist.org
自动加载入口 无需(Node.js 有内置的模块解析) vendor/autoload.php

两者的核心理念完全一致——声明依赖、锁定版本、自动加载。如果你用过 npm,Composer 几乎可以零学习成本上手。

十二、本篇动手练习

练习 1:创建 Composer 项目并安装库

创建一个新目录,用 composer init 初始化项目。安装 phpmailer/phpmailer 库,写一个简单的 PHP 脚本来发送一封测试邮件(可以使用 Mailtrap 等测试邮件服务,或者只是创建一个 PHPMailer 对象并输出一些属性来验证安装成功)。

练习 2:配置 PSR-4 自动加载

创建一个项目,结构如下:

project/
├── composer.json
├── public/
│   └── index.php
└── src/
    ├── Models/
    │   └── Product.php
    └── Services/
        └── Cart.php

composer.json 中配置 PSR-4 自动加载。在 index.php 中通过 Composer 自动加载来使用 ProductCart 类。

练习 3:使用全局辅助函数

在练习 2 的基础上,创建 app/helpers.php 文件,包含两个全局辅助函数:dd($var)(var_dump 后 die)和 base_path($path)(返回项目根目录拼接后的绝对路径)。在 composer.json 中用 files 方式加载这个文件。在 index.php 中测试这两个函数。

练习 4:重构之前的用户管理系统

把之前第七篇或第九篇中写的用户管理系统用 Composer 重写。创建合理的命名空间结构(如 App\Models\UserApp\Controllers\UserController),用 PSR-4 自动加载,用 Monolog 记录日志。确保不需要任何 require_once 语句。

十三、本篇小结

这一篇你学会了现代 PHP 开发的必备工具——Composer:

  • Composer 是什么:PHP 的包管理器,相当于 npm(Node.js)、pip(Python)。解决依赖管理和自动加载两大核心问题。
  • composer.json 和 composer.lock:前者声明依赖范围和自动加载规则,后者锁定精确版本。
  • 安装第三方库composer require 库名。所有库下载到 vendor/ 目录。只需要一行 require_once 'vendor/autoload.php' 就能使用所有库。
  • PSR-4 自动加载:命名空间前缀对应文件目录。在 composer.json 中配置 "App\\": "src/",之后 use App\Models\User; 会自动引入 src/Models/User.php
  • 其他加载方式:Classmap(扫描目录建立映射)、Files(每次请求都加载的全局函数文件)。
  • Composer 脚本:在 scripts 中定义自动化任务,如 composer test 运行测试、composer serve 启动开发服务器。

Composer 是现代 PHP 开发的起点。学会了 Composer,你就能使用 PHP 生态中成千上万个高质量的开源库,也能用面向对象的方式组织自己的代码,为接下来学习 Laravel 等框架打下坚实的基础。

下一篇预告

下一篇是《PHP 零基础入门》的终篇——《回顾与进阶——你的 PHP 学习路线图》。我们将总结本系列学过的所有内容,对比面向过程 vs 面向对象的写法,介绍 Laravel 框架的核心理念,并给出后续的学习建议。

PHP 零基础入门,每周更新。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容