Kodokon kodokon.com

命名空间、自动加载与 Composer

用 PSR-4 命名空间来组织你的代码,并让 Composer 替你加载类和依赖。

8 分钟 · 3 题

在 Kodokon 中打开本课

命名空间消除了名称冲突:两个库可以各自定义一个 Client 类而互不冲突。通用的约定:一个供应商前缀(AppAcme\Blog),然后是映射文件夹树的子命名空间。use 把一个完全限定名导入到当前文件,as 则在有歧义时给它改名。一个文件 = 一个类 = 一个命名空间:这条纪律不是什么风格上的怪癖,而是自动加载得以成立的根本前提。

PHP
<?php

declare(strict_types=1);

namespace App\Service;

use App\Repository\UserRepository;
use Psr\Log\LoggerInterface as Logger;

final class UserService
{
    public function __construct(
        private UserRepository $users,
        private Logger $logger,
    ) {
    }
}
一个 src/Service/UserService.php 文件:命名空间、导入、别名。

自动加载按需载入类文件:不再需要手动 requirePSR-4 标准定义了这套映射:一个命名空间前缀与一个根文件夹关联,每个子命名空间对应一个子文件夹。于是 App\Service\UserService 就解析为 src/Service/UserService.php。在底层,这一切都依赖 spl_autoload_register - 下面是最简实现,即使你永远不会重写它,也值得理解一下:

PHP
<?php

declare(strict_types=1);

spl_autoload_register(function (string $class): void {
    $prefix = 'App\\';
    $baseDir = __DIR__ . '/src/';

    if (!str_starts_with($class, $prefix)) {
        return;
    }

    $relative = substr($class, strlen($prefix));
    $path = $baseDir
        . str_replace('\\', '/', $relative)
        . '.php';

    if (is_file($path)) {
        require $path;
    }
});

echo 'Autoloader registered';
手写的 PSR-4 自动加载器:前缀、根文件夹、转换成路径。

Composer 把这一切工业化了:composer.json 声明你的依赖和你的 PSR-4 映射 - 通常是 "autoload": { "psr-4": { "App\\\\": "src/" } } - 然后 composer install 把这些包下载到 vendor/,并生成 vendor/autoload.php,也就是你整个应用唯一的那句 require。一个关键区别:require 用于生产环境需要的包,require-dev 用于工具链(测试、静态分析),通过 --no-dev 从部署中排除。

BASH
composer init --name acme/app --no-interaction
composer require monolog/monolog
composer require --dev phpunit/phpunit
composer dump-autoload -o
生命周期:初始化、添加依赖、重新生成自动加载器。

知识检测

确认你已牢记本课的重点内容。

  1. 根据 PSR-4,如果 App\ 前缀指向 src/,类 App\Blog\PostRepository 位于哪里?
    • src/App/Blog/PostRepository.php
    • src/Blog/PostRepository.php
    • src/blog/postrepository.php
  2. 为了享受 Composer 生成的自动加载,你应该引入哪个文件?
    • composer.json
    • vendor/autoload.php
    • 一个需要在根目录创建的 autoload.php
  3. composer require --dev 是用来做什么的?
    • 安装一个仅用于开发的包,通过 --no-dev 从部署中排除
    • 安装该包的一个不稳定版本
    • 在机器上全局安装该包