← 返回目录

第七章:常用库与工具

Composer 生态与实用工具库

1 Composer 详解

Composer 是 PHP 的依赖管理工具,也是整个 PHP 现代生态的基石。它负责下载、安装第三方包并自动生成 autoload 文件。

🔄 跨语言对比:Composer 之于 PHP,就像 npm 之于 Node.js、pip 之于 Python、Maven/Gradle 之于 Java。配置文件 composer.json 等价于 package.json / requirements.txt。锁文件 composer.lock 等价于 package-lock.json

常用命令

# 初始化项目(交互式生成 composer.json)
composer init

# 安装一个包(自动写入 composer.json 并下载)
composer require guzzlehttp/guzzle

# 安装开发依赖(仅开发环境使用)
composer require --dev phpunit/phpunit

# 根据 composer.lock 安装所有依赖(部署时使用)
composer install

# 更新依赖到最新兼容版本
composer update

# 更新 autoload 映射(添加新类后)
composer dump-autoload

composer.json 结构

{
    "name": "myvendor/myproject",
    "description": "我的 PHP 项目",
    "type": "project",
    "require": {
        "php": ">=8.4",
        "guzzlehttp/guzzle": "^7.8",
        "monolog/monolog": "^3.0",
        "nesbot/carbon": "~3.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^11.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}

版本约束

符号 含义 示例
^ 兼容更新(不破坏主版本) ^7.8>=7.8.0 <8.0.0
~ 允许最后一位增长 ~3.0>=3.0.0 <4.0.0
* 通配符 3.* → 任何 3.x 版本
精确版本 锁定特定版本 3.7.2

PSR-4 自动加载

配置 autoload.psr-4 后,只需引入 vendor/autoload.php,所有类都能自动加载:

<?php
// 项目入口文件
require __DIR__ . '/vendor/autoload.php';

// 直接使用,无需手动 require 每个文件
use App\Services\UserService;
use App\Models\User;

$service = new UserService();
$user = $service->findById(1);

目录结构对应关系:命名空间 App\Services\UserService 映射到文件 src/Services/UserService.php

2 Guzzle — HTTP 客户端

Guzzle 是 PHP 最流行的 HTTP 客户端库,提供简洁的 API 发送 HTTP 请求、处理响应,支持异步并发。

composer require guzzlehttp/guzzle

基本用法

<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

$client = new Client([
    'base_uri' => 'https://api.example.com',
    'timeout'  => 5.0,
]);

// GET 请求
$response = $client->get('/users', [
    'query' => ['page' => 1, 'limit' => 10],
    'headers' => [
        'Authorization' => 'Bearer ' . $token,
        'Accept' => 'application/json',
    ],
]);

$statusCode = $response->getStatusCode();        // 200
$body = json_decode($response->getBody(), true);  // 解析 JSON

// POST 请求(发送 JSON)
$response = $client->post('/users', [
    'json' => [
        'name'  => '张三',
        'email' => 'zhangsan@example.com',
    ],
]);

// POST 表单数据
$response = $client->post('/login', [
    'form_params' => [
        'username' => 'admin',
        'password' => 'secret',
    ],
]);

异常处理

<?php
try {
    $response = $client->get('/users/999');
} catch (RequestException $e) {
    if ($e->hasResponse()) {
        $error = json_decode($e->getResponse()->getBody(), true);
        echo "错误: " . $error['message'];
    } else {
        echo "请求失败: " . $e->getMessage();
    }
}

异步请求

<?php
use GuzzleHttp\Promise\Utils;

$promises = [
    'users'    => $client->getAsync('/users'),
    'products' => $client->getAsync('/products'),
    'orders'   => $client->getAsync('/orders'),
];

// 并发执行所有请求
$results = Utils::unwrap($promises);

$users    = json_decode($results['users']->getBody(), true);
$products = json_decode($results['products']->getBody(), true);
$orders   = json_decode($results['orders']->getBody(), true);
💡 提示:在第五章中我们用了原生 cURL 发送请求。实际项目中推荐使用 Guzzle —— API 更简洁,内置重试、连接池、异步等高级特性。

3 Monolog — 日志库

Monolog 是 PHP 的标准日志库(遵循 PSR-3 接口),支持将日志输出到文件、数据库、Slack、邮件等多种目标。Laravel、Symfony 等框架均内置 Monolog。

composer require monolog/monolog

基本使用

<?php
require 'vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Formatter\LineFormatter;

// 创建日志通道
$log = new Logger('app');

// Handler 1:所有日志写入文件
$log->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG));

// Handler 2:错误日志单独归档,按天轮转,保留 30 天
$errorHandler = new RotatingFileHandler(
    __DIR__ . '/logs/error.log',
    30,              // 保留天数
    Logger::ERROR    // 最低记录级别
);
$log->pushHandler($errorHandler);

// 写入日志
$log->debug('调试信息', ['module' => 'auth']);
$log->info('用户登录成功', ['user_id' => 42]);
$log->warning('缓存命中率低', ['rate' => 0.35]);
$log->error('数据库连接失败', ['host' => 'db.example.com']);
$log->critical('支付网关无响应');

日志级别(从低到高)

级别 用途
DEBUG详细调试信息
INFO关键业务事件(用户登录、订单创建)
NOTICE正常但需关注的事件
WARNING异常情况但不影响运行
ERROR运行时错误,需修复
CRITICAL关键组件不可用
ALERT必须立即处理
EMERGENCY系统不可用

自定义格式

<?php
$formatter = new LineFormatter(
    "[%datetime%] %channel%.%level_name%: %message% %context%\n",
    'Y-m-d H:i:s'
);

$handler = new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG);
$handler->setFormatter($formatter);

$log = new Logger('app');
$log->pushHandler($handler);
// 输出: [2026-03-31 10:30:00] app.INFO: 用户登录成功 {"user_id":42}

4 Carbon — 日期时间处理

Carbon 是 PHP DateTime 的增强封装,提供极其流畅的 API 处理日期和时间,Laravel 中默认集成。

composer require nesbot/carbon
🔄 跨语言对比:Carbon 之于 PHP,类似 dayjs / moment.js 之于 JavaScript,pendulum / arrow 之于 Python。PHP 原生 DateTime 功能较弱,Carbon 补齐了差距。

创建与格式化

<?php
require 'vendor/autoload.php';

use Carbon\Carbon;

// 创建实例
$now = Carbon::now();                         // 当前时间
$today = Carbon::today();                     // 今天 00:00:00
$date = Carbon::create(2026, 3, 31, 10, 30);  // 指定时间
$parsed = Carbon::parse('2026-03-31 10:30:00');

// 格式化输出
echo $now->format('Y-m-d H:i:s');   // 2026-03-31 10:30:00
echo $now->toDateString();           // 2026-03-31
echo $now->toDateTimeString();       // 2026-03-31 10:30:00
echo $now->isoFormat('YYYY年MM月DD日'); // 2026年03月31日

日期计算

<?php
$now = Carbon::now();

// 加减运算
$tomorrow = $now->copy()->addDay();
$nextWeek = $now->copy()->addWeek();
$lastMonth = $now->copy()->subMonth();
$future = $now->copy()->addDays(45)->addHours(3);

// 链式操作
$deadline = Carbon::parse('2026-12-31')
    ->subDays(7)
    ->startOfDay();   // 2026-12-24 00:00:00

比较与差值

<?php
$start = Carbon::parse('2026-01-01');
$end = Carbon::parse('2026-03-31');

echo $start->diffInDays($end);        // 89
echo $start->diffInMonths($end);      // 2
echo $start->diffForHumans($end);     // "2个月前"

// 布尔判断
$date = Carbon::parse('2026-03-31');
$date->isWeekday();     // true
$date->isToday();       // true (假设今天是 3/31)
$date->isFuture();      // false
$date->isPast();        // false
$date->isLeapYear();    // false

// 比较
$a = Carbon::parse('2026-01-01');
$b = Carbon::parse('2026-06-01');
$a->lt($b);   // true (less than)
$a->gte($b);  // false (greater than or equal)

时区处理

<?php
$beijing = Carbon::now('Asia/Shanghai');
$newYork = $beijing->copy()->setTimezone('America/New_York');

echo $beijing->format('Y-m-d H:i');   // 2026-03-31 22:30
echo $newYork->format('Y-m-d H:i');   // 2026-03-31 10:30
⚠️ 注意:Carbon 的 add/sub 方法会修改原对象。如果需要保留原始日期,使用 copy() 先复制再操作,或者使用不可变版本 CarbonImmutable

5 PHPUnit — 单元测试

PHPUnit 是 PHP 事实上的标准测试框架,支持单元测试、Mock、代码覆盖率等。

# 安装为开发依赖
composer require --dev phpunit/phpunit

# 运行测试
./vendor/bin/phpunit

phpunit.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
         colors="true"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Unit">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
    <source>
        <include>
            <directory>src</directory>
        </include>
    </source>
</phpunit>

编写测试类

<?php
// tests/CalculatorTest.php
namespace Tests;

use PHPUnit\Framework\TestCase;
use App\Calculator;

class CalculatorTest extends TestCase
{
    private Calculator $calc;

    // 每个测试方法执行前调用
    protected function setUp(): void
    {
        $this->calc = new Calculator();
    }

    // 每个测试方法执行后调用
    protected function tearDown(): void
    {
        // 清理资源(如果需要)
    }

    public function testAdd(): void
    {
        $this->assertEquals(5, $this->calc->add(2, 3));
        $this->assertEquals(0, $this->calc->add(-1, 1));
    }

    public function testDivide(): void
    {
        $this->assertEquals(2.5, $this->calc->divide(5, 2));
    }

    public function testDivideByZeroThrowsException(): void
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage('除数不能为零');
        $this->calc->divide(10, 0);
    }
}

常用断言

<?php
// 相等性
$this->assertEquals('hello', $result);     // 值相等(== 宽松比较)
$this->assertSame('hello', $result);       // 类型+值完全相同(===)

// 布尔
$this->assertTrue($user->isActive());
$this->assertFalse($user->isBanned());
$this->assertNull($user->deletedAt());

// 数组
$this->assertCount(3, $items);
$this->assertContains('admin', $roles);
$this->assertArrayHasKey('email', $data);
$this->assertEmpty($errors);

// 类型与实例
$this->assertInstanceOf(User::class, $result);
$this->assertIsString($name);
$this->assertIsArray($list);

// 字符串
$this->assertStringContainsString('error', $message);
$this->assertMatchesRegularExpression('/^\d{4}-\d{2}/', $date);

数据提供器(Data Provider)

<?php
use PHPUnit\Framework\Attributes\DataProvider;

class MathTest extends TestCase
{
    public static function additionProvider(): array
    {
        return [
            '正数相加'   => [3, 4, 7],
            '负数相加'   => [-1, -2, -3],
            '零加任意数' => [0, 5, 5],
            '大数相加'   => [PHP_INT_MAX, 0, PHP_INT_MAX],
        ];
    }

    #[DataProvider('additionProvider')]
    public function testAdd(int $a, int $b, int $expected): void
    {
        $this->assertSame($expected, $a + $b);
    }
}
# 运行特定测试文件
./vendor/bin/phpunit tests/CalculatorTest.php

# 运行特定方法
./vendor/bin/phpunit --filter testAdd

# 显示详细输出
./vendor/bin/phpunit --testdox

6 vlucas/phpdotenv — 环境变量

phpdotenv 从 .env 文件加载环境变量,让敏感配置(数据库密码、API 密钥)与代码分离。

composer require vlucas/phpdotenv

.env 文件示例

# .env(不要提交到 Git!加入 .gitignore)
APP_NAME=MyApp
APP_ENV=production
APP_DEBUG=false

DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=root
DB_PASSWORD=secret

REDIS_HOST=127.0.0.1
API_KEY=sk-xxxxxxxxxxxx

加载与使用

<?php
require 'vendor/autoload.php';

// 加载 .env 文件(通常在应用入口处执行一次)
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

// 必须存在的变量(缺少则抛异常)
$dotenv->required(['DB_HOST', 'DB_DATABASE', 'DB_USERNAME']);

// 读取环境变量(三种方式)
$dbHost = $_ENV['DB_HOST'];               // 推荐
$dbHost = $_SERVER['DB_HOST'];            // 也可以
$dbHost = getenv('DB_HOST');              // 传统方式

// 实际使用
$dsn = sprintf(
    'mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4',
    $_ENV['DB_HOST'],
    $_ENV['DB_PORT'],
    $_ENV['DB_DATABASE']
);

$pdo = new PDO($dsn, $_ENV['DB_USERNAME'], $_ENV['DB_PASSWORD']);

最佳实践

✅ 推荐

  • • 将 .env 加入 .gitignore
  • • 提供 .env.example 作为模板
  • • 使用 required() 校验必要变量
  • • 生产环境用真实环境变量替代 .env

❌ 避免

  • • 将 .env 提交到版本控制
  • • 在代码中硬编码密码或密钥
  • • 在非入口文件多次 load()
  • • 在 .env 中存储大段文本

7 其他推荐库

PHP 生态中还有很多高质量的库,以下是实际项目中高频使用的:

🖥️

symfony/console

构建命令行工具的框架,支持参数解析、彩色输出、进度条、交互式问答。

composer require symfony/console
📁

league/flysystem

文件系统抽象层,统一 API 操作本地磁盘、S3、FTP、阿里云 OSS 等存储。

composer require league/flysystem
🔑

ramsey/uuid

生成 RFC 4122 标准 UUID(v4 随机、v7 时间排序),广泛用于分布式 ID。

composer require ramsey/uuid

respect/validation

流畅的数据验证库,链式 API 校验邮箱、手机号、长度、范围等。

composer require respect/validation
🔴

predis/predis

纯 PHP 实现的 Redis 客户端,无需安装 C 扩展即可连接 Redis。

composer require predis/predis
🖼️

intervention/image

图片处理库,支持裁剪、缩放、水印、格式转换,API 简洁优雅。

composer require intervention/image

快速示例

<?php
// ramsey/uuid - 生成 UUID
use Ramsey\Uuid\Uuid;

$uuid = Uuid::uuid4()->toString();  // "550e8400-e29b-41d4-a716-446655440000"
$uuid7 = Uuid::uuid7()->toString(); // 时间排序的 UUID v7

// respect/validation - 数据验证
use Respect\Validation\Validator as v;

$valid = v::email()->validate('user@example.com');          // true
$valid = v::stringType()->length(2, 50)->validate('张三');   // true
$valid = v::numericVal()->between(1, 100)->validate(42);    // true

// predis/predis - Redis 操作
$redis = new Predis\Client(['host' => '127.0.0.1']);
$redis->set('user:1:name', '张三');
$redis->expire('user:1:name', 3600);
$name = $redis->get('user:1:name'); // "张三"

8 PHP 框架概览

掌握 PHP 基础后,选择一个框架能极大提升开发效率。以下是目前最主流的三个框架:

框架 类型 特点 适用场景 学习曲线
Laravel 全栈框架 优雅语法、Eloquent ORM、Blade 模板、队列、广播、丰富生态 Web 应用、SaaS、API 后端 ⭐⭐ 中等
Symfony 全栈框架 企业级、组件化设计、高度可配置、长期支持版本 大型企业项目、复杂业务系统 ⭐⭐⭐ 较高
Slim 微框架 轻量、仅路由+中间件、自由选择组件 REST API、微服务、小型项目 ⭐ 简单

快速创建项目

# Laravel
composer create-project laravel/laravel my-app
cd my-app && php artisan serve   # 启动开发服务器 http://localhost:8000

# Symfony
composer create-project symfony/skeleton my-app
cd my-app && symfony server:start

# Slim
composer require slim/slim slim/psr7

Slim 微框架示例

<?php
// public/index.php
require __DIR__ . '/../vendor/autoload.php';

use Slim\Factory\AppFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

$app = AppFactory::create();
$app->addErrorMiddleware(true, true, true);

$app->get('/', function (Request $request, Response $response) {
    $response->getBody()->write(json_encode(['message' => '你好,PHP!']));
    return $response->withHeader('Content-Type', 'application/json');
});

$app->get('/users/{id}', function (Request $request, Response $response, array $args) {
    $userId = $args['id'];
    $response->getBody()->write(json_encode(['id' => $userId]));
    return $response->withHeader('Content-Type', 'application/json');
});

$app->run();
🎯 框架选择建议:
  • • 新手入门或构建 API → Slim(轻量,概念少,快速上手)
  • • 快速开发 Web 应用 → Laravel(生态最丰富,社区最活跃,文档优秀)
  • • 大型企业项目 → Symfony(架构严谨,适合复杂业务)
  • • 本教程学完后,建议从 LaravelSlim 开始实战

9 本章要点

📦 Composer

  • require 安装、install 部署
  • ^ / ~ 语义化版本约束
  • • PSR-4 自动加载映射类到文件

🌐 Guzzle

  • • GET/POST 请求、JSON 处理
  • • 异步并发请求
  • • 替代原生 cURL 的最佳选择

📋 Monolog

  • • PSR-3 标准日志接口
  • • Handler 控制输出目标
  • • 8 个级别从 DEBUG 到 EMERGENCY

📅 Carbon

  • • DateTime 增强封装
  • • 流畅的链式日期操作
  • copy() 避免修改原对象

🧪 PHPUnit

  • TestCase + assert* 方法
  • • Data Provider 参数化测试
  • setUp/tearDown 管理测试生命周期

🔒 phpdotenv

  • .env 文件加载环境变量
  • • 敏感配置与代码分离
  • .env 不提交、.env.example 提交

🎉 恭喜完成 PHP 速成教程!

你已经掌握了 PHP 8.4 的核心知识 —— 从环境搭建、基础语法、函数与 OOP、数据库操作、网络通信、文件处理,到 Composer 生态与常用工具库。

下一步建议:

  1. 用 Slim 或 Laravel 构建一个完整的 REST API 项目
  2. 为项目编写 PHPUnit 测试,养成测试驱动的习惯
  3. 阅读 PHP-FIG PSR 标准,了解社区最佳实践
  4. 探索 Packagist 上的更多开源包