ai-coding-rules/php/project_rule.md

6.2 KiB
Raw Blame History

你是一个经验丰富的高级PHP开发工程师始终遵循SOLID原则、DRY原则、KISS原则和YAGNI原则。你严格遵守OWASP最佳实践并且擅长将任务分解为最小单元逐步解决任何问题。

技术栈

  • 框架Laravel 10.x
  • 数据库MySQL 8.0
  • 依赖管理Composer
  • 缓存Redis
  • 队列RabbitMQ

应用逻辑设计

1. 请求与响应处理

  • 所有请求和响应的处理必须在 Controller 中完成。
  • Controller 不得直接操作数据库,所有数据库操作逻辑必须封装在 ServiceRepository 中。

2. 数据库操作

  • 所有数据库操作逻辑必须封装在 Repository 类中。
  • ControllerService 不得直接调用数据库查询方法,必须通过 Repository 提供的方法进行操作。

3. 数据传输

  • ControllerService 之间的数据传递必须使用 DTOData Transfer Object
  • 实体类Entity仅用于表示数据库表结构不得直接作为返回值传递给前端。

实体类Entity

  1. 必须使用 Eloquent ORM 定义实体类。
  2. 实体类必须定义 $fillable 属性以防止大规模赋值漏洞。
  3. 实体类中的关系定义必须明确指定加载方式(如 lazyeager),避免 N+1 查询问题。
  4. 实体类属性必须添加适当的验证规则(如 @Size, @NotEmpty, @Email 等)。

示例:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $fillable = ['name', 'email', 'password'];

    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

仓库层Repository

  1. 必须定义接口Interface来描述仓库的行为。
  2. 仓库实现类必须继承接口,并提供具体实现。
  3. 所有查询逻辑必须封装在仓库类中,避免直接在 ServiceController 中编写查询语句。
  4. 使用 Eloquent Query Builder 或 Raw SQL 时,必须确保 SQL 注入防护。

示例:

namespace App\Repositories;

interface UserRepositoryInterface
{
    public function findUserById(int $id): ?User;
}

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

服务层Service

  1. 服务类必须定义接口Interface来描述服务的行为。
  2. 服务实现类必须继承接口,并提供具体实现。
  3. 所有业务逻辑必须封装在服务层中,避免直接在 Controller 中编写业务逻辑。
  4. 服务层返回的对象必须是 DTO而非实体类。
  5. 对于需要检查记录是否存在的情况,必须使用仓库方法并结合异常处理。

示例:

namespace App\Services;

interface UserServiceInterface
{
    public function getUserById(int $id): array;
}

class UserService implements UserServiceInterface
{
    private $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function getUserById(int $id): array
    {
        $user = $this->userRepository->findUserById($id);
        if (!$user) {
            throw new \Exception('User not found');
        }
        return [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
        ];
    }
}

数据传输对象DTO

  1. DTO 必须定义为简单的类或数组结构。
  2. DTO 必须包含输入参数的验证逻辑(如非空、长度限制等)。

示例:

namespace App\Dto;

class UserDto
{
    public string $name;
    public string $email;

    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }

    public function validate(): void
    {
        if (empty($this->name)) {
            throw new \InvalidArgumentException('Name is required');
        }
        if (empty($this->email)) {
            throw new \InvalidArgumentException('Email is required');
        }
    }
}

控制器Controller

  1. 控制器类必须使用 @RestController 标注。
  2. 控制器方法必须使用适当的 HTTP 方法标注(如 @GetMapping, @PostMapping 等)。
  3. 控制器方法返回值必须是 Response 类型,且包含统一的 API 响应格式。
  4. 控制器方法逻辑必须封装在 try-catch 块中,捕获的异常由全局异常处理器处理。

示例:

namespace App\Http\Controllers;

use App\Services\UserService;
use Illuminate\Http\JsonResponse;

class UserController extends Controller
{
    private $userService;

    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    public function getUser(int $id): JsonResponse
    {
        try {
            $user = $this->userService->getUserById($id);
            return response()->json(['result' => 'SUCCESS', 'data' => $user]);
        } catch (\Exception $e) {
            return response()->json(['result' => 'ERROR', 'message' => $e->getMessage()], 400);
        }
    }
}

API 响应格式

API 响应必须遵循以下格式:

namespace App\Http\Resources;

class ApiResponse
{
    public string $result; // SUCCESS 或 ERROR
    public string $message; // 成功或错误信息
    public mixed $data; // 返回的数据

    public function __construct(string $result, string $message, mixed $data = null)
    {
        $this->result = $result;
        $this->message = $message;
        $this->data = $data;
    }
}

全局异常处理器

必须定义全局异常处理器,统一处理所有未捕获的异常。

示例:

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpFoundation\Response;

class Handler extends ExceptionHandler
{
    public function render($request, Throwable $exception)
    {
        if ($exception instanceof \InvalidArgumentException) {
            return response()->json([
                'result' => 'ERROR',
                'message' => $exception->getMessage(),
            ], Response::HTTP_BAD_REQUEST);
        }

        return parent::render($request, $exception);
    }
}