强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 27 章 — 最佳实践

第 27 章 — 最佳实践:PSR 规范、代码风格与项目结构

27.1 PSR 规范

PSR名称说明
PSR-1基础编码标准文件格式、命名空间、类名
PSR-4自动加载命名空间与文件路径映射
PSR-3日志接口LoggerInterface
PSR-7HTTP 消息请求/响应接口
PSR-11容器接口ContainerInterface
PSR-12扩展编码风格代码格式化标准
PSR-14事件调度EventDispatcherInterface
PSR-15HTTP 服务器处理器MiddlewareInterface
PSR-16缓存接口SimpleCacheInterface
PSR-17HTTP 工厂各种工厂接口
PSR-18HTTP 客户端ClientInterface
PSR-20时钟接口ClockInterface

PSR-12 编码风格要点

<?php
declare(strict_types=1);

namespace Vendor\Package;

use Vendor\Package\SomeClass;
use Vendor\Package\AnotherClass;
use function Vendor\Package\someFunction;
use const Vendor\Package\SOME_CONSTANT;

/**
 * 类的文档注释
 */
class ClassName extends ParentClass implements InterfaceName
{
    // 常量大写 + 下划线
    public const CONSTANT_NAME = 'value';

    // 属性声明
    private string $privateProperty;
    protected int $protectedProperty;

    // 构造器
    public function __construct(
        string $parameter1,
        string $parameter2,
    ) {
        $this->privateProperty = $parameter1;
        $this->protectedProperty = (int) $parameter2;
    }

    // 方法名 camelCase
    public function doSomething(): void
    {
        // 4 空格缩进
        if ($condition) {
            // ...
        }
    }

    // 链式调用
    public function setOption(string $key, mixed $value): static
    {
        $this->options[$key] = $value;
        return $this;
    }
}

27.2 SOLID 原则

原则说明示例
S 单一职责一个类只做一件事UserService 只处理用户逻辑
O 开闭原则对扩展开放,对修改关闭使用接口和策略模式
L 里氏替换子类可以替换父类不改变方法语义
I 接口隔离接口应该小而专分离 Readable 和 Writable
D 依赖倒置依赖抽象而非具体注入接口而非实现
<?php
// ❌ 违反单一职责
class UserManager
{
    public function create() {}
    public function sendEmail() {}
    public function generateReport() {}
    public function exportCSV() {}
}

// ✅ 遵循单一职责
class UserService { public function create() {} }
class UserMailer { public function sendWelcome() {} }
class UserReport { public function generate() {} }
class UserExporter { public function toCSV() {} }

27.3 推荐项目结构

my-project/
├── app/
│   ├── Console/            # Artisan 命令
│   ├── Http/
│   │   ├── Controllers/
│   │   ├── Middleware/
│   │   ├── Requests/       # 表单请求验证
│   │   └── Resources/      # API Resources
│   ├── Models/
│   ├── Services/           # 业务逻辑
│   ├── Repositories/       # 数据访问层
│   ├── Events/
│   ├── Listeners/
│   ├── Jobs/               # 队列任务
│   ├── Mail/
│   └── Exceptions/
├── config/
├── database/
│   ├── migrations/
│   └── seeders/
├── resources/
│   └── views/
├── routes/
├── storage/
├── tests/
│   ├── Unit/
│   └── Feature/
├── docker/
│   ├── nginx/
│   └── php/
├── .env.example
├── .gitignore
├── composer.json
├── docker-compose.yml
└── README.md

27.4 设计模式

27.4.1 仓库模式(Repository Pattern)

<?php
interface UserRepositoryInterface
{
    public function findById(int $id): ?User;
    public function save(User $user): bool;
}

class EloquentUserRepository implements UserRepositoryInterface
{
    public function findById(int $id): ?User
    {
        return User::find($id);
    }

    public function save(User $user): bool
    {
        return $user->save();
    }
}

27.4.2 策略模式(Strategy Pattern)

<?php
interface PaymentStrategy
{
    public function pay(float $amount): bool;
}

class AlipayStrategy implements PaymentStrategy
{
    public function pay(float $amount): bool
    {
        // 支付宝支付逻辑
        return true;
    }
}

class WechatPayStrategy implements PaymentStrategy
{
    public function pay(float $amount): bool
    {
        // 微信支付逻辑
        return true;
    }
}

class PaymentService
{
    public function process(PaymentStrategy $strategy, float $amount): bool
    {
        return $strategy->pay($amount);
    }
}

27.4.3 观察者模式(Observer Pattern)

<?php
class UserRegisteredEvent
{
    public function __construct(
        public readonly User $user,
    ) {}
}

class SendWelcomeEmailListener
{
    public function handle(UserRegisteredEvent $event): void
    {
        // 发送欢迎邮件
    }
}

class AssignDefaultRoleListener
{
    public function handle(UserRegisteredEvent $event): void
    {
        // 分配默认角色
    }
}

27.5 代码审查清单

  • 严格类型声明 declare(strict_types=1)
  • 使用 === 而非 ==
  • 所有用户输入都经过验证
  • SQL 使用预处理语句
  • 输出使用 htmlspecialchars() 转义
  • 密码使用 password_hash()
  • 异常被正确捕获和记录
  • 没有硬编码的敏感信息
  • 方法名遵循 camelCase
  • 类名遵循 PascalCase
  • 无未使用的导入和变量
  • 复杂逻辑有注释说明

27.6 性能检查清单

  • 开启 OPcache
  • 生产环境关闭 display_errors
  • 使用 composer install --no-dev --optimize-autoloader
  • 缓存配置 php artisan config:cache
  • 缓存路由 php artisan route:cache
  • 使用 Redis/Memcached 缓存热点数据
  • 数据库查询避免 N+1 问题
  • 大数据处理使用生成器

27.7 扩展阅读


上一章第 26 章 — CI/CD 下一章第 28 章 — 实战项目