php-specialist

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PHP Specialist

PHP专家

Overview

概述

Write modern, type-safe, and maintainable PHP 8.x code adhering to PSR standards and SOLID principles. This skill covers the full modern PHP toolchain: language features introduced in PHP 8.0 through 8.4, PSR interoperability standards, Composer dependency management, static analysis with PHPStan and Psalm, coding style enforcement with PHP CS Fixer and Pint, and architectural patterns that leverage the type system for correctness at compile time rather than runtime.
Apply this skill whenever PHP code is being written, reviewed, or refactored in any framework or standalone context.
编写符合PSR标准和SOLID原则的现代、类型安全、可维护的PHP 8.x代码。本技能覆盖完整的现代PHP工具链:PHP 8.0至8.4版本引入的语言特性、PSR互操作性标准、Composer依赖管理、基于PHPStan和Psalm的静态分析、通过PHP CS Fixer和Pint落地编码规范,以及利用类型系统在编译期而非运行期保障正确性的架构模式。
无论在任何框架或独立场景下编写、评审或重构PHP代码时,均可应用本技能。

Multi-Phase Process

多阶段流程

Phase 1: Environment Assessment

阶段1:环境评估

  1. Identify PHP version from
    composer.json
    ->
    require.php
  2. Review
    composer.json
    for autoloading strategy (PSR-4 namespaces)
  3. Check for static analysis configuration (
    phpstan.neon
    ,
    psalm.xml
    )
  4. Identify coding standard tool (
    pint.json
    ,
    .php-cs-fixer.php
    )
  5. Catalog existing patterns: enums, DTOs, value objects, interfaces
STOP — Do NOT write code without knowing the PHP version and autoloading strategy.
  1. composer.json
    require.php
    字段确认PHP版本
  2. 检查
    composer.json
    中的自动加载策略(PSR-4命名空间)
  3. 确认静态分析配置是否存在(
    phpstan.neon
    psalm.xml
  4. 识别使用的编码规范工具(
    pint.json
    .php-cs-fixer.php
  5. 梳理现有代码模式:枚举、DTO、值对象、接口
停止 — 未明确PHP版本和自动加载策略前,不要编写任何代码。

Phase 2: Design

阶段2:设计

  1. Define interfaces and contracts before implementations
  2. Design value objects and DTOs with readonly properties
  3. Map domain concepts to backed enums where applicable
  4. Plan exception hierarchy for the domain
  5. Identify seams for dependency injection
STOP — Do NOT implement without interfaces defined for key boundaries.
  1. 先定义接口和契约,再编写实现逻辑
  2. 使用只读属性设计值对象和DTO
  3. 合适的领域概念映射为回退枚举(backed enums)
  4. 规划领域对应的异常层级
  5. 识别依赖注入的接缝点
停止 — 未为核心边界定义接口前,不要开始实现。

Phase 3: Implementation

阶段3:实现

  1. Write interfaces first — contracts before concrete classes
  2. Implement with constructor promotion, readonly properties, union/intersection types
  3. Use match expressions over switch; named arguments for clarity
  4. Leverage first-class callable syntax for functional composition
  5. Apply SOLID principles at every class boundary
STOP — Do NOT skip strict_types declaration in any PHP file.
  1. 优先编写接口:契约早于具体类
  2. 实现时使用构造器属性提升、只读属性、联合/交集类型
  3. 优先使用match表达式而非switch;使用命名参数提升可读性
  4. 利用一等可调用语法实现函数式组合
  5. 在每个类边界应用SOLID原则
停止 — 任何PHP文件都不能缺少strict_types声明。

Phase 4: Quality Assurance

阶段4:质量保障

  1. Run PHPStan at maximum achievable level (target level 9)
  2. Enforce coding style with PHP CS Fixer or Laravel Pint
  3. Verify type coverage — no
    mixed
    without justification
  4. Review for SOLID violations and code smells
  5. Confirm Composer autoload is optimized (
    --classmap-authoritative
    )
  1. 以可达到的最高级别运行PHPStan(目标级别9)
  2. 通过PHP CS Fixer或Laravel Pint强制执行编码规范
  3. 验证类型覆盖率:无合理理由不得使用
    mixed
    类型
  4. 检查是否违反SOLID原则、是否存在代码坏味道
  5. 确认Composer自动加载已优化(
    --classmap-authoritative

PHP Version Feature Decision Table

PHP版本特性决策表

FeatureMinimum VersionUse When
Constructor promotion8.0Any class with constructor parameters
Named arguments8.0Functions with 3+ params or boolean flags
Match expressions8.0Any switch statement (strict, returns value)
Union types8.0Parameter accepts multiple types
Backed enums8.1Any set of named constants with values
Readonly properties8.1Immutable DTOs, value objects
Fibers8.1Async frameworks (rarely used directly)
First-class callables8.1Functional composition, array_map/filter
Readonly classes8.2All-readonly DTOs (shorthand)
DNF types8.2Complex union + intersection combinations
Override attribute8.3Overriding parent methods (safety check)
Property hooks8.4Computed properties without separate methods
特性最低版本使用场景
构造器属性提升8.0所有带构造参数的类
命名参数8.0参数≥3个或包含布尔标志位的函数
Match表达式8.0所有switch语句场景(严格匹配、支持返回值)
联合类型8.0参数支持多种类型的场景
回退枚举8.1所有带值的命名常量集合
只读属性8.1不可变DTO、值对象
Fibers8.1异步框架(极少直接使用)
一等可调用对象8.1函数式组合、array_map/filter
只读类8.2全属性只读的DTO(简化写法)
DNF类型8.2复杂的联合+交集类型组合
Override属性8.3重写父类方法时的安全检查
属性钩子8.4无需单独方法实现计算属性

Modern PHP 8.x Features

现代PHP 8.x特性

Enums (PHP 8.1+)

Enums (PHP 8.1+)

php
// Backed enum with methods — replaces class constants and magic strings
enum OrderStatus: string
{
    case Draft     = 'draft';
    case Pending   = 'pending';
    case Confirmed = 'confirmed';
    case Shipped   = 'shipped';
    case Delivered = 'delivered';
    case Cancelled = 'cancelled';

    public function label(): string
    {
        return match ($this) {
            self::Draft     => 'Draft',
            self::Pending   => 'Pending Review',
            self::Confirmed => 'Confirmed',
            self::Shipped   => 'Shipped',
            self::Delivered => 'Delivered',
            self::Cancelled => 'Cancelled',
        };
    }

    public function isFinal(): bool
    {
        return in_array($this, [self::Delivered, self::Cancelled], true);
    }

    /** @return list<self> */
    public static function active(): array
    {
        return array_filter(self::cases(), fn (self $s) => ! $s->isFinal());
    }
}
php
// 带方法的回退枚举——替代类常量和魔法字符串
enum OrderStatus: string
{
    case Draft     = 'draft';
    case Pending   = 'pending';
    case Confirmed = 'confirmed';
    case Shipped   = 'shipped';
    case Delivered = 'delivered';
    case Cancelled = 'cancelled';

    public function label(): string
    {
        return match ($this) {
            self::Draft     => 'Draft',
            self::Pending   => 'Pending Review',
            self::Confirmed => 'Confirmed',
            self::Shipped   => 'Shipped',
            self::Delivered => 'Delivered',
            self::Cancelled => 'Cancelled',
        };
    }

    public function isFinal(): bool
    {
        return in_array($this, [self::Delivered, self::Cancelled], true);
    }

    /** @return list<self> */
    public static function active(): array
    {
        return array_filter(self::cases(), fn (self $s) => ! $s->isFinal());
    }
}

Readonly Properties and Classes (PHP 8.1 / 8.2)

只读属性和只读类 (PHP 8.1 / 8.2)

php
// Readonly class — all properties are implicitly readonly
readonly class Money
{
    public function __construct(
        public int    $amount,
        public string $currency,
    ) {}

    public function add(self $other): self
    {
        if ($this->currency !== $other->currency) {
            throw new CurrencyMismatchException($this->currency, $other->currency);
        }

        return new self($this->amount + $other->amount, $this->currency);
    }

    public function isPositive(): bool
    {
        return $this->amount > 0;
    }
}
php
// 只读类——所有属性隐式为只读
readonly class Money
{
    public function __construct(
        public int    $amount,
        public string $currency,
    ) {}

    public function add(self $other): self
    {
        if ($this->currency !== $other->currency) {
            throw new CurrencyMismatchException($this->currency, $other->currency);
        }

        return new self($this->amount + $other->amount, $this->currency);
    }

    public function isPositive(): bool
    {
        return $this->amount > 0;
    }
}

Constructor Promotion

构造器属性提升

php
class CreateUserAction
{
    public function __construct(
        private readonly UserRepository $users,
        private readonly Hasher         $hasher,
        private readonly EventDispatcher $events,
    ) {}

    public function execute(CreateUserData $data): User
    {
        $user = $this->users->create([
            'name'     => $data->name,
            'email'    => $data->email,
            'password' => $this->hasher->make($data->password),
        ]);

        $this->events->dispatch(new UserCreated($user));

        return $user;
    }
}
php
class CreateUserAction
{
    public function __construct(
        private readonly UserRepository $users,
        private readonly Hasher         $hasher,
        private readonly EventDispatcher $events,
    ) {}

    public function execute(CreateUserData $data): User
    {
        $user = $this->users->create([
            'name'     => $data->name,
            'email'    => $data->email,
            'password' => $this->hasher->make($data->password),
        ]);

        $this->events->dispatch(new UserCreated($user));

        return $user;
    }
}

Named Arguments

命名参数

php
// Improves readability for functions with many parameters or boolean flags
$user = User::create(
    name: $request->name,
    email: $request->email,
    isAdmin: false,
    sendWelcomeEmail: true,
);

// Particularly valuable with optional parameters
$response = Http::timeout(seconds: 30)
    ->retry(times: 3, sleepMilliseconds: 500, throw: true)
    ->get($url);
php
// 提升多参数或带布尔标志位函数的可读性
$user = User::create(
    name: $request->name,
    email: $request->email,
    isAdmin: false,
    sendWelcomeEmail: true,
);

// 对可选参数尤其有用
$response = Http::timeout(seconds: 30)
    ->retry(times: 3, sleepMilliseconds: 500, throw: true)
    ->get($url);

Match Expressions

Match表达式

php
// match is strict (===), exhaustive, and returns a value
$discount = match (true) {
    $total >= 10000 => 0.15,
    $total >= 5000  => 0.10,
    $total >= 1000  => 0.05,
    default         => 0.00,
};

// Replaces switch with no fall-through risk
$handler = match ($event::class) {
    OrderPlaced::class   => new HandleOrderPlaced(),
    PaymentFailed::class => new HandlePaymentFailed(),
    default              => throw new UnhandledEventException($event),
};
php
// match是严格匹配(===)、覆盖全场景、支持返回值
$discount = match (true) {
    $total >= 10000 => 0.15,
    $total >= 5000  => 0.10,
    $total >= 1000  => 0.05,
    default         => 0.00,
};

// 替代switch,无穿透风险
$handler = match ($event::class) {
    OrderPlaced::class   => new HandleOrderPlaced(),
    PaymentFailed::class => new HandlePaymentFailed(),
    default              => throw new UnhandledEventException($event),
};

Union and Intersection Types

联合类型和交集类型

php
// Union type — accepts either type
function findUser(int|string $identifier): User
{
    return is_int($identifier)
        ? User::findOrFail($identifier)
        : User::where('email', $identifier)->firstOrFail();
}

// Intersection type — must satisfy all interfaces
function processLoggableEntity(Loggable&Serializable $entity): void
{
    $entity->log();
    $data = $entity->serialize();
}

// DNF types (PHP 8.2) — combine union and intersection
function handle((Renderable&Countable)|string $content): string
{
    if (is_string($content)) {
        return $content;
    }

    return $content->render();
}
php
// 联合类型——接受任意一种指定类型
function findUser(int|string $identifier): User
{
    return is_int($identifier)
        ? User::findOrFail($identifier)
        : User::where('email', $identifier)->firstOrFail();
}

// 交集类型——必须满足所有接口要求
function processLoggableEntity(Loggable&Serializable $entity): void
{
    $entity->log();
    $data = $entity->serialize();
}

// DNF类型 (PHP 8.2) —— 组合联合和交集类型
function handle((Renderable&Countable)|string $content): string
{
    if (is_string($content)) {
        return $content;
    }

    return $content->render();
}

First-Class Callable Syntax (PHP 8.1+)

一等可调用语法 (PHP 8.1+)

php
// Create closures from named functions
$slugify = Str::slug(...);
$titles  = array_map($slugify, $names);

// Method references
$validator = Validator::make(...);

// Useful for pipeline / collection patterns
$activeUsers = collect($users)
    ->filter(UserPolicy::isActive(...))
    ->map(UserTransformer::toArray(...))
    ->values();
php
// 从命名函数创建闭包
$slugify = Str::slug(...);
$titles  = array_map($slugify, $names);

// 方法引用
$validator = Validator::make(...);

// 适用于流水线/集合模式
$activeUsers = collect($users)
    ->filter(UserPolicy::isActive(...))
    ->map(UserTransformer::toArray(...))
    ->values();

Fibers (PHP 8.1+)

Fibers (PHP 8.1+)

php
// Fibers enable cooperative multitasking — foundation for async frameworks
$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('paused');
    echo "Resumed with: {$value}";
});

$result = $fiber->start();        // Returns 'paused'
$fiber->resume('hello world');    // Prints: "Resumed with: hello world"

// Practical use: async HTTP client internals, event loops (Revolt, ReactPHP)
// Application developers rarely use Fiber directly — frameworks abstract it
php
// Fibers支持协作式多任务——是异步框架的基础
$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('paused');
    echo "Resumed with: {$value}";
});

$result = $fiber->start();        // 返回 'paused'
$fiber->resume('hello world');    // 输出: "Resumed with: hello world"

// 实际应用场景:异步HTTP客户端底层、事件循环(Revolt、ReactPHP)
// 应用开发者极少直接使用Fiber——框架会做封装

PSR Standards

PSR标准

PSRNameRelevance
PSR-1Basic Coding StandardBaseline:
<?php
tag, UTF-8, namespace/class conventions
PSR-4AutoloadingMap namespaces to directories in
composer.json
— mandatory
PSR-7HTTP Message InterfacesImmutable request/response objects for middleware pipelines
PSR-11Container InterfaceDependency injection container interoperability
PSR-12Extended Coding StyleSupersedes PSR-2: formatting, spacing, declarations
PSR-15HTTP Server Middleware
MiddlewareInterface
and
RequestHandlerInterface
PSR-17HTTP FactoriesCreate PSR-7 objects (RequestFactory, ResponseFactory)
PSR-18HTTP Client
ClientInterface
for interoperable HTTP clients
PSR名称相关性
PSR-1基础编码标准基线要求:
<?php
标签、UTF-8、命名空间/类约定
PSR-4自动加载
composer.json
中映射命名空间到目录——强制要求
PSR-7HTTP消息接口中间件流水线使用的不可变请求/响应对象
PSR-11容器接口依赖注入容器互操作性标准
PSR-12扩展编码风格替代PSR-2:格式化、空格、声明规范
PSR-15HTTP服务端中间件
MiddlewareInterface
RequestHandlerInterface
标准
PSR-17HTTP工厂创建PSR-7对象的标准(RequestFactory、ResponseFactory)
PSR-18HTTP客户端可互操作HTTP客户端的
ClientInterface
标准

PSR-4 Autoloading

PSR-4自动加载

json
{
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Domain\\": "src/Domain/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}
Rule: namespace segment maps 1:1 to directory.
App\Http\Controllers\UserController
lives at
app/Http/Controllers/UserController.php
.
json
{
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Domain\\": "src/Domain/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}
规则:命名空间段与目录1:1映射。
App\Http\Controllers\UserController
对应的文件路径为
app/Http/Controllers/UserController.php

Composer Dependency Management

Composer依赖管理

Essential Commands

核心命令

CommandPurpose
composer require package/name
Add production dependency
composer require package/name --dev
Add development dependency
composer update --dry-run
Preview what would change
composer why package/name
Show why a package is installed
composer audit
Check for known security vulnerabilities
composer bump
Update version constraints to installed versions
composer validate --strict
Validate
composer.json
and
composer.lock
命令用途
composer require package/name
添加生产环境依赖
composer require package/name --dev
添加开发环境依赖
composer update --dry-run
预览更新内容,不实际执行
composer why package/name
查看某个包被安装的原因
composer audit
检查已知安全漏洞
composer bump
将版本约束更新为已安装的版本
composer validate --strict
校验
composer.json
composer.lock
的合法性

Best Practices

最佳实践

  • Always commit
    composer.lock
    — reproducible installs across environments
  • Use
    ^
    (caret) constraints:
    "laravel/framework": "^12.0"
    allows minor/patch updates
  • Separate dev dependencies: testing, static analysis, and debug tools go in
    require-dev
  • Run
    composer audit
    in CI to catch known vulnerabilities
  • Use
    composer dump-autoload --classmap-authoritative
    in production for speed
  • 始终提交
    composer.lock
    ——保障多环境安装的一致性
  • 使用
    ^
    (插入符)约束:
    "laravel/framework": "^12.0"
    允许小版本和补丁版本更新
  • 分离开发依赖:测试、静态分析、调试工具放在
    require-dev
  • 在CI中运行
    composer audit
    ,提前发现已知漏洞
  • 生产环境使用
    composer dump-autoload --classmap-authoritative
    提升加载速度

Static Analysis

静态分析

PHPStan Levels

PHPStan级别

LevelWhat It Checks
0Basic: undefined variables, unknown classes, wrong function calls
1+ possibly undefined variables, unknown methods on
$this
2+ unknown methods on all expressions (not just
$this
)
3+ return types verified
4+ dead code, always-true/false conditions
5+ argument types of function calls
6+ missing typehints reported
7+ union types checked exhaustively
8+ nullable types checked strictly
9+
mixed
type is forbidden without explicit handling
级别检查内容
0基础检查:未定义变量、未知类、错误的函数调用
1新增:可能未定义的变量、
$this
上的未知方法
2新增:所有表达式上的未知方法(不限于
$this
3新增:返回类型校验
4新增:死代码、恒真/恒假条件
5新增:函数调用的参数类型校验
6新增:上报缺失的类型提示
7新增:联合类型全场景覆盖检查
8新增:可空类型严格检查
9新增:无显式处理时禁止使用
mixed
类型

PHPStan Configuration

PHPStan配置

neon
undefined
neon
undefined

phpstan.neon

phpstan.neon

parameters: level: 9 paths: - app - src excludePaths: - app/Console/Kernel.php ignoreErrors: [] checkMissingIterableValueType: true checkGenericClassInNonGenericObjectType: true
includes: - vendor/larastan/larastan/extension.neon # Laravel-specific rules
undefined
parameters: level: 9 paths: - app - src excludePaths: - app/Console/Kernel.php ignoreErrors: [] checkMissingIterableValueType: true checkGenericClassInNonGenericObjectType: true
includes: - vendor/larastan/larastan/extension.neon # Laravel专属规则
undefined

PHP CS Fixer / Pint

PHP CS Fixer / Pint

php
// .php-cs-fixer.php — for non-Laravel projects
return (new PhpCsFixer\Config())
    ->setRules([
        '@PER-CS'            => true,
        'strict_types'       => true,
        'declare_strict_types' => true,
        'ordered_imports'    => ['sort_algorithm' => 'alpha'],
        'no_unused_imports'  => true,
        'trailing_comma_in_multiline' => true,
    ])
    ->setFinder(
        PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests'])
    );
For Laravel projects, use Pint with a
pint.json
preset — it wraps PHP CS Fixer with Laravel-specific defaults.
php
// .php-cs-fixer.php —— 适用于非Laravel项目
return (new PhpCsFixer\Config())
    ->setRules([
        '@PER-CS'            => true,
        'strict_types'       => true,
        'declare_strict_types' => true,
        'ordered_imports'    => ['sort_algorithm' => 'alpha'],
        'no_unused_imports'  => true,
        'trailing_comma_in_multiline' => true,
    ])
    ->setFinder(
        PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests'])
    );
Laravel项目可使用Pint配合
pint.json
预设——它封装了PHP CS Fixer,提供Laravel专属的默认配置。

SOLID Principles in PHP

PHP中的SOLID原则

PrincipleGuidelinePHP Mechanism
S — Single ResponsibilityOne reason to change per classAction classes, small services
O — Open/ClosedExtend behavior without modifying sourceInterfaces, strategy pattern, enums
L — Liskov SubstitutionSubtypes must be substitutable for base typesCovariant returns, contravariant params
I — Interface SegregationClients depend only on methods they useSmall, focused interfaces
D — Dependency InversionDepend on abstractions, not concretionsConstructor injection, interface bindings
原则指导规则PHP实现机制
S — 单一职责每个类只有一个变更理由动作类、小型服务
O — 开闭原则扩展行为时无需修改源代码接口、策略模式、枚举
L — 里氏替换子类型必须可以替换父类型协变返回、逆变参数
I — 接口隔离客户端仅依赖自身使用的方法小型、聚焦的接口
D — 依赖倒置依赖抽象而非具体实现构造器注入、接口绑定

Dependency Inversion Example

依赖倒置示例

php
// Contract (abstraction)
interface PaymentGateway
{
    public function charge(Money $amount, PaymentMethod $method): PaymentResult;
}

// Implementation (concretion) — can be swapped without changing consumers
final class StripeGateway implements PaymentGateway
{
    public function __construct(private readonly StripeClient $client) {}

    public function charge(Money $amount, PaymentMethod $method): PaymentResult
    {
        // Stripe-specific logic
    }
}

// Consumer depends on abstraction only
final class ProcessPaymentAction
{
    public function __construct(private readonly PaymentGateway $gateway) {}

    public function execute(Order $order): PaymentResult
    {
        return $this->gateway->charge($order->total, $order->paymentMethod);
    }
}
php
// 契约(抽象)
interface PaymentGateway
{
    public function charge(Money $amount, PaymentMethod $method): PaymentResult;
}

// 实现(具体类)——无需修改消费者即可替换
final class StripeGateway implements PaymentGateway
{
    public function __construct(private readonly StripeClient $client) {}

    public function charge(Money $amount, PaymentMethod $method): PaymentResult
    {
        // Stripe专属逻辑
    }
}

// 消费者仅依赖抽象
final class ProcessPaymentAction
{
    public function __construct(private readonly PaymentGateway $gateway) {}

    public function execute(Order $order): PaymentResult
    {
        return $this->gateway->charge($order->total, $order->paymentMethod);
    }
}

Error Handling Patterns

错误处理模式

Custom Exception Hierarchy

自定义异常层级

php
// Base domain exception
abstract class DomainException extends \RuntimeException {}

// Specific exceptions with factory methods
final class InsufficientFundsException extends DomainException
{
    public static function forAccount(Account $account, Money $required): self
    {
        return new self(sprintf(
            'Account %s has %d %s but %d %s is required.',
            $account->id,
            $account->balance->amount,
            $account->balance->currency,
            $required->amount,
            $required->currency,
        ));
    }
}
php
// 领域基础异常
abstract class DomainException extends \RuntimeException {}

// 带工厂方法的具体异常
final class InsufficientFundsException extends DomainException
{
    public static function forAccount(Account $account, Money $required): self
    {
        return new self(sprintf(
            'Account %s has %d %s but %d %s is required.',
            $account->id,
            $account->balance->amount,
            $account->balance->currency,
            $required->amount,
            $required->currency,
        ));
    }
}

Result Pattern (Error as Value)

结果模式(错误作为值)

php
/** @template T */
readonly class Result
{
    /** @param T|null $value */
    private function __construct(
        public bool    $ok,
        public mixed   $value = null,
        public ?string $error = null,
    ) {}

    /** @param T $value */
    public static function success(mixed $value): self
    {
        return new self(ok: true, value: $value);
    }

    public static function failure(string $error): self
    {
        return new self(ok: false, error: $error);
    }
}

// Usage — caller must handle both paths
$result = $action->execute($data);
if (! $result->ok) {
    return response()->json(['error' => $result->error], 422);
}
php
/** @template T */
readonly class Result
{
    /** @param T|null $value */
    private function __construct(
        public bool    $ok,
        public mixed   $value = null,
        public ?string $error = null,
    ) {}

    /** @param T $value */
    public static function success(mixed $value): self
    {
        return new self(ok: true, value: $value);
    }

    public static function failure(string $error): self
    {
        return new self(ok: false, error: $error);
    }
}

// 用法——调用方必须处理两种分支
$result = $action->execute($data);
if (! $result->ok) {
    return response()->json(['error' => $result->error], 422);
}

Type Safety Patterns

类型安全模式

Branded / Opaque Types via Readonly Classes

基于只读类的品牌/不透明类型

php
// Prevent accidental mixing of IDs from different entities
readonly class UserId
{
    public function __construct(public int $value) {}

    public function equals(self $other): bool
    {
        return $this->value === $other->value;
    }
}

readonly class OrderId
{
    public function __construct(public int $value) {}
}

// Compiler prevents: processOrder(new UserId(1)) when OrderId is expected
function processOrder(OrderId $orderId): void { /* ... */ }
php
// 避免不同实体的ID意外混用
readonly class UserId
{
    public function __construct(public int $value) {}

    public function equals(self $other): bool
    {
        return $this->value === $other->value;
    }
}

readonly class OrderId
{
    public function __construct(public int $value) {}
}

// 编译器会拦截:当期望OrderId时传入processOrder(new UserId(1))的调用
function processOrder(OrderId $orderId): void { /* ... */ }

Generic Collections via PHPStan Annotations

基于PHPStan注解的泛型集合

php
/**
 * @template T
 * @implements \IteratorAggregate<int, T>
 */
final class TypedCollection implements \IteratorAggregate, \Countable
{
    /** @param list<T> $items */
    public function __construct(private array $items = []) {}

    /** @param T $item */
    public function add(mixed $item): void
    {
        $this->items[] = $item;
    }

    /** @return \ArrayIterator<int, T> */
    public function getIterator(): \ArrayIterator
    {
        return new \ArrayIterator($this->items);
    }

    public function count(): int
    {
        return count($this->items);
    }
}
php
/**
 * @template T
 * @implements \IteratorAggregate<int, T>
 */
final class TypedCollection implements \IteratorAggregate, \Countable
{
    /** @param list<T> $items */
    public function __construct(private array $items = []) {}

    /** @param T $item */
    public function add(mixed $item): void
    {
        $this->items[] = $item;
    }

    /** @return \ArrayIterator<int, T> */
    public function getIterator(): \ArrayIterator
    {
        return new \ArrayIterator($this->items);
    }

    public function count(): int
    {
        return count($this->items);
    }
}

Anti-Patterns / Common Mistakes

反模式/常见错误

Anti-PatternWhy It FailsWhat To Do Instead
Using
mixed
as escape hatch
Holes in type safety netNarrow with union types or generics
Stringly-typed codeRuntime errors from typosUse backed enums for named constants
God classes (many responsibilities)Untestable, high couplingSplit into Action classes
Suppressing static analysisHides real bugsFix the issue, add
@phpstan-ignore
only with explanation
Missing
declare(strict_types=1)
Silent type coercion bugsAdd to every PHP file
Array-shaped domain dataNo IDE support, no type safetyUse readonly DTOs or value objects
Service locator (
app()
in logic)
Hidden dependencies, untestableConstructor injection
Catching
\Exception
broadly
Swallows unexpected errorsCatch specific exception types
Mutable value objectsShared state bugsUse
readonly
classes, return new instances
Ignoring
composer audit
Known vulnerabilities in productionRun in CI, treat as build failure
Deep inheritance (3+ levels)Fragile base class problemPrefer composition and interfaces
Classes not marked
final
Unintended extensionDefault to
final
, open only when designed for it
反模式缺陷替代方案
mixed
逃避类型约束
类型安全网存在漏洞使用联合类型或泛型缩小类型范围
字符串类型代码拼写错误导致运行时错误使用回退枚举替代命名常量
上帝类(承担过多职责)无法测试、耦合度高拆分为多个动作类
屏蔽静态分析告警隐藏真实bug修复问题,仅在有合理解释时添加
@phpstan-ignore
缺少
declare(strict_types=1)
隐式类型转换导致bug每个PHP文件都添加该声明
用数组承载领域数据无IDE支持、无类型安全使用只读DTO或值对象
服务定位器(逻辑中使用
app()
依赖隐藏、无法测试使用构造器注入
宽泛捕获
\Exception
吞噬非预期错误捕获特定的异常类型
可变值对象共享状态导致bug使用
readonly
类,返回新实例
忽略
composer audit
生产环境存在已知漏洞在CI中运行,告警时阻断构建
深层继承(≥3层)基类脆弱问题优先使用组合和接口
类未标记
final
非预期的扩展默认使用
final
,仅在设计为可扩展时放开

Anti-Rationalization Guards

反合理化约束

  • Do NOT skip
    declare(strict_types=1)
    because "it's just a small script" -- add it everywhere.
  • Do NOT use
    mixed
    without a comment justifying why a narrower type is impossible.
  • Do NOT suppress PHPStan errors without a written explanation of why the code is correct.
  • Do NOT use the service locator pattern (
    app()
    ) in business logic, even in Laravel.
  • Do NOT skip interfaces for key boundaries because "there's only one implementation" -- there will be two.
  • 不要因为“这只是个小脚本”就省略
    declare(strict_types=1)
    ——所有文件都要添加。
  • 不要在没有注释说明无法使用更窄类型的理由时使用
    mixed
  • 不要在没有书面解释代码正确性的前提下屏蔽PHPStan错误。
  • 不要在业务逻辑中使用服务定位器模式(
    app()
    ),即使是Laravel项目。
  • 不要因为“只有一个实现”就省略核心边界的接口——未来总会有第二个实现。

Documentation Lookup (Context7)

文档查询(Context7)

Use
mcp__context7__resolve-library-id
then
mcp__context7__query-docs
for up-to-date docs. Returned docs override memorized knowledge.
  • php
    — for language features, built-in functions, or PHP 8.x syntax
  • composer
    — for package management, autoloading, or scripts configuration

使用
mcp__context7__resolve-library-id
然后调用
mcp__context7__query-docs
获取最新文档,返回的文档优先级高于记忆知识。
  • php
    —— 查询语言特性、内置函数或PHP 8.x语法
  • composer
    —— 查询包管理、自动加载或脚本配置

Integration Points

集成点

SkillHow It Connects
laravel-specialist
PHP 8.x features power Eloquent casts, enums, readonly DTOs, and typed collections
senior-backend
SOLID architecture, interface-driven design, error handling patterns
test-driven-development
PHPUnit/Pest testing with strong type assertions
clean-code
SOLID, DRY, code smell detection at the PHP level
security-review
Input validation, type coercion risks, dependency vulnerabilities
laravel-boost
AI-generated PHP code quality via guidelines and MCP tools
技能关联方式
laravel-specialist
PHP 8.x特性支撑Eloquent类型转换、枚举、只读DTO和类型化集合
senior-backend
SOLID架构、接口驱动设计、错误处理模式
test-driven-development
PHPUnit/Pest测试配合强类型断言
clean-code
PHP层面的SOLID、DRY、代码坏味道检测
security-review
输入校验、类型转换风险、依赖漏洞
laravel-boost
通过规范和MCP工具提升AI生成PHP代码的质量

Skill Type

技能类型

FLEXIBLE — Adapt the process phases to the scope of work. A single function may need only Phase 3 and 4. A new module or package should follow all four phases. Non-negotiable regardless of scope:
declare(strict_types=1)
, PHPStan compliance at the project's configured level, and PSR-4 autoloading.
灵活适配 —— 根据工作范围调整流程阶段。单个函数可能只需要阶段3和4。新模块或包应该遵循全部四个阶段。无论范围如何都不能妥协的规则:
declare(strict_types=1)
、符合项目配置级别的PHPStan规范、PSR-4自动加载。