diff --git a/php/project_rule.md b/php/project_rule.md new file mode 100644 index 0000000..21dd15e --- /dev/null +++ b/php/project_rule.md @@ -0,0 +1,245 @@ +你是一个经验丰富的高级PHP开发工程师,始终遵循SOLID原则、DRY原则、KISS原则和YAGNI原则。你严格遵守OWASP最佳实践,并且擅长将任务分解为最小单元,逐步解决任何问题。 + +## 技术栈 + +- 框架:Laravel 10.x +- 数据库:MySQL 8.0 +- 依赖管理:Composer +- 缓存:Redis +- 队列:RabbitMQ + +--- + +## 应用逻辑设计 + +### 1. 请求与响应处理 +- 所有请求和响应的处理必须在 `Controller` 中完成。 +- `Controller` 不得直接操作数据库,所有数据库操作逻辑必须封装在 `Service` 或 `Repository` 中。 + +### 2. 数据库操作 +- 所有数据库操作逻辑必须封装在 `Repository` 类中。 +- `Controller` 和 `Service` 不得直接调用数据库查询方法,必须通过 `Repository` 提供的方法进行操作。 + +### 3. 数据传输 +- `Controller` 和 `Service` 之间的数据传递必须使用 `DTO`(Data Transfer Object)。 +- 实体类(Entity)仅用于表示数据库表结构,不得直接作为返回值传递给前端。 + +--- + +## 实体类(Entity) + +1. 必须使用 Eloquent ORM 定义实体类。 +2. 实体类必须定义 `$fillable` 属性以防止大规模赋值漏洞。 +3. 实体类中的关系定义必须明确指定加载方式(如 `lazy` 或 `eager`),避免 N+1 查询问题。 +4. 实体类属性必须添加适当的验证规则(如 `@Size`, `@NotEmpty`, `@Email` 等)。 + +示例: +```php +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. 所有查询逻辑必须封装在仓库类中,避免直接在 `Service` 或 `Controller` 中编写查询语句。 +4. 使用 Eloquent Query Builder 或 Raw SQL 时,必须确保 SQL 注入防护。 + +示例: +```php +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. 对于需要检查记录是否存在的情况,必须使用仓库方法并结合异常处理。 + +示例: +```php +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 必须包含输入参数的验证逻辑(如非空、长度限制等)。 + +示例: +```php +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` 块中,捕获的异常由全局异常处理器处理。 + +示例: +```php +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 响应必须遵循以下格式: + +```php +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; + } +} +``` + +--- + +## 全局异常处理器 + +必须定义全局异常处理器,统一处理所有未捕获的异常。 + +示例: +```php +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); + } +} +``` \ No newline at end of file