首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP实现代码分层设计实践与总结

PHP实现代码分层设计实践与总结

原创
作者头像
Mandy的名字被占用了
修改2021-03-21 18:43:48
2.3K0
修改2021-03-21 18:43:48
举报

简介

见过很多PHP开发者的代码,在代码分层上面都不是很注重。一般都是控制器负责所有的业务逻辑,在控制器中调用模型做数据操作、验证数据也在控制器中等等情况。这样的做法怎么说呢?也没错,但是这样写代码就显示的很杂糅。

本文分享一些个人的代码分层想法,存在不足的地方,希望大家多多提出一些宝贵建议。

文章底部有代码示例连接,可以直接通过代码查看或许更加方便。

相关技术

Laravel资源控制器Laravel模型PHP对象接口

实现思路

大致实现的思路如下:

Snipaste_2021-03-20_22-29-16
Snipaste_2021-03-20_22-29-16
// uml图
@startuml
controller->service:调用
service->repository:调用
repository->model:调用
@enduml
  1. controller层直接调用service层,controller主要负责传递请求参数,返回接口数据。
  2. service层负责处理数据逻辑,将controller接收到的参数格式化,然后将整理好的数据传递给repository层。
  3. repository层直接调用model层的示例,进行数据操作。
  4. model层主要责任是映射数据表,定义一个有关数据表的操作。例如表名、时间错、获取器和修改器等等。

代码演示

首先定义了如下的目录结构,具体的其他结构可以根据自己的需要来定义,例如验证层、接口响应层、资源层等等。

Snipaste_2021-03-20_22-38-50
Snipaste_2021-03-20_22-38-50

为了保证在controller、service、repository层中的相关方法名称以及返回参数格式都保持一致,在每一个层,都定义一个接口,接口中的方法都定义好参数格式以及返回值类型。

例如controller层。首先我们定义一个controller层接口.

<?php

namespace App\Http\Controllers;

/**
 * Api controller service
 *
 * Interface ApiServiceController
 * @package App\Http\Controllers
 */
interface ApiServiceController
{
    /**
     * 具体每个方法的定义参考laravel文档
     * https://learnku.com/docs/laravel/5.8/controllers/3893#resource-controllers
     */

    public function index();

    public function create();

    public function store();

    public function show();

    public function edit();

    public function update();

    public function destroy();
}

对应的实现类controller,实现ApiServiceController接口。

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\ApiAuthBaseController;
use App\Http\Controllers\ApiServiceController;
use App\Services\UserInterface;

/**
 * User's controller
 *
 * Class UserController
 * @package App\Http\Controllers\User
 */
class UserController extends ApiAuthBaseController implements ApiServiceController
{
    public function __construct(UserInterface $apiService)
    {
        $this->service = $apiService;
        parent::__construct($apiService);
    }

    public function index()
    {
        $items = $this->service->serviceIndex((array)$this->requestParams);

        return response()->json([
            'code' => 10001,
            'msg'  => 'select success',
            'data' => $items,
        ]);
    }

    public function create()
    {
        // TODO: Implement create() method.
    }

    public function store()
    {
        if ($this->service->serviceStore((array)$this->requestParams)) {
            return response()->json([
                'code' => 10001,
                'msg'  => 'create success',
                'data' => [
                    'id' => 1,
                ],
            ]);
        }
    }

    public function show()
    {
        // TODO: Implement show() method.
    }

    public function edit()
    {
        // TODO: Implement edit() method.
    }

    public function update()
    {
        if ($this->service->serviceUpdate((array)$this->requestParams)) {
            return response()->json([
                'code' => 10001,
                'msg'  => 'update success',
                'data' => [

                ],
            ]);
        }
    }

    public function destroy()
    {
        if ($this->service->serviceDestroy($this->requestParams)) {
            return response()->json([
                'code' => 10001,
                'msg'  => 'delete success',
                'data' => [

                ],
            ]);
        }

    }
}

对应的service层、repository层都根据类似的方式定义。具体的实现方法可以参考文章底部的代码示例。

接口调用演示

根据上面的代码演示逻辑,假设我们定义好了service层和repository层对应的逻辑,这时候我们Api添加一个资源路由的定义就可以直接调用啦。在api.php路由文件定义如下格式:

<?php
use Illuminate\Support\Facades\Route;
Route::resource('user', 'User\UserController');

接下来,我们查看一下调用结果。

1.增加数据。

Snipaste_2021-03-20_22-51-27
Snipaste_2021-03-20_22-51-27

2.删除数据。

Snipaste_2021-03-20_22-51-53
Snipaste_2021-03-20_22-51-53

3.修改数据。

Snipaste_2021-03-20_22-52-09
Snipaste_2021-03-20_22-52-09

4.查询数据。

Snipaste_2021-03-20_22-52-34
Snipaste_2021-03-20_22-52-34

总结

本文总结只是属于个人的一些总结,存在不足的地方,欢迎大家指正。这里总结一下设计这一的思路。

  1. 使用资源路由,我们直接定义一个路由规则,增删改查等接口方式,我们就自动实现并且能够规范团队中的接口,同时也符合RESTful API的规范。
  2. 使用接口定义一些业务逻辑函数,实现类直接实现接口中的方法,这样可以避免团队方法定义不一致、接口参数不一致、返回参数不一致等情况。如果接口中方法没有定义,然而业务逻辑需要单独一个方法,可以直接在实现类中定义独有的方法即可。
  3. model层主要实现表映射关系,这里直接把表当做模型。因此所有的逻辑不应该在模型层中处理,顶多定义一个属性等情况。repository层直接去调用model层,不需要处理数据格式等情况,根据service层传递的条件,将查询的数据直接返回给service层。service层则是负责业务逻辑处理,比如格式化接口请求参数、组装查询条件、删除条件等情况。controller则是负责将请求的参数传递给service层,然后将service层返回的数据返回给客户端。这样每一层负责的职能独立,互补关联。降低了代码的耦合度。
  4. 使用资源路由,简化接口。

示例代码

[代码地址](https://gitee.com/bruce_qiq/laravel-design)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 相关技术
  • 实现思路
  • 代码演示
  • 接口调用演示
  • 总结
  • 示例代码
相关产品与服务
Serverless HTTP 服务
Serverless HTTP 服务基于腾讯云 API 网关 和 Web Cloud Function(以下简称“Web Function”)建站云函数(云函数的一种类型)的产品能力,可以支持各种类型的 HTTP 服务开发,实现了 Serverless 与 Web 服务最优雅的结合。用户可以快速构建 Web 原生框架,把本地的 Express、Koa、Nextjs、Nuxtjs 等框架项目快速迁移到云端,同时也支持 Wordpress、Discuz Q 等现有应用模版一键快速创建。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档