menu LittleJake's Blog
color_lens
avatar
Jake Liu
Never Settle
creative commons by-nc-sa
hit
Category
keyboard_arrow_down

© 2024 LittleJake's Blog.

萌ICP备20223020号

ThinkPHP5使用魔术方法加载model、validate、logic

thinkphp5

描述

根据ThinkPHP5手册的说明,模型能进行分层:

通常情况下,不同的分层模型仍然是继承系统的\think\Model类或其子类,所以,其基本操作和Model类的操作是一致的。

例如在index模块的设计中需要区分数据层、逻辑层、服务层等不同的模型层,我们可以在模块目录下面创建model、logic和service目录,把对用户表的所有模型操作分成三层:

数据层:app\index\model\User 用于定义数据相关的自动验证和自动完成和数据存取接口

逻辑层:app\index\logic\User 用于定义用户相关的业务逻辑

服务层:app\index\service\User 用于定义用户相关的服务接口等

解决方案

所有的层全部继承Model类,因此受到某个项目的启发,可以在基类添加如下语句使其使用魔术方法加载各层实例方法。

  • 在common.php添加字符串处理函数
/**
 * 魔术方法获取逻辑层、模型层、验证层
 *
 * @author Jake
 * @param $str
 * @param $prefix
 * @return bool
 */
function str_prefix($str, $prefix)
{
    return strpos($str, $prefix) === 0 ? true : false;
}
function sr($str = '', $target = '', $content = '')
{
    return str_replace($target, $content, $str);
}
  • 在Controller父类添加魔术方法处理
public function __get($logicName)
{
    $layer = $this->getLayerPre($logicName);
    $model = sr($logicName, $layer);
    return VALIDATE_LAYER_NAME == $layer ? validate($model) : model($model, $layer);
} 
protected function getLayerPre($name)
{
    $layer = false;
    $layer_array = [MODEL_LAYER_NAME, LOGIC_LAYER_NAME, VALIDATE_LAYER_NAME, SERVICE_LAYER_NAME];
    foreach ($layer_array as $v)
        if (str_prefix($name, $v)) {
            $layer = $v;
            break;
        }
    return $layer;
 }
  • 入口文件添加常量define
define('LOGIC_LAYER_NAME'       , 'logic');
define('MODEL_LAYER_NAME'       , 'model');
define('SERVICE_LAYER_NAME'     , 'service');
define('CONTROLLER_LAYER_NAME'  , 'controller');
define('LIBRARY_LAYER_NAME'     , 'library');
define('VALIDATE_LAYER_NAME'    , 'validate');
define('VIEW_LAYER_NAME'        , 'view');

当然也可将魔术方法封装成一个trait文件,随时引用

<?php
/**
 * Created by IntelliJ IDEA.
 * User: Jake
 * Date: 2019/8/23
 * Time: 16:47
 */
namespace app\common\traits;
define('LOGIC_LAYER_NAME'       , 'logic');
define('MODEL_LAYER_NAME'       , 'model');
define('SERVICE_LAYER_NAME'     , 'service');
define('CONTROLLER_LAYER_NAME'  , 'controller');
define('LIBRARY_LAYER_NAME'     , 'library');
define('VALIDATE_LAYER_NAME'    , 'validate');
define('VIEW_LAYER_NAME'        , 'view');
trait Magic
{
    public function __get($logicName)
    {
        $layer = $this->getLayerPre($logicName);
        $model = sr($logicName, $layer);
        return VALIDATE_LAYER_NAME == $layer ? validate($model) : model($model, $layer);
    }
    protected function getLayerPre($name)
    {
        $layer = false;
        $layer_array = [MODEL_LAYER_NAME, LOGIC_LAYER_NAME, VALIDATE_LAYER_NAME, SERVICE_LAYER_NAME];
        foreach ($layer_array as $v)
            if (str_prefix($name, $v)) {
                $layer = $v;
                break;
            }
        return $layer;
    }
} 

实现效果

  1. $this->logicFoo->bar()等效于new namespace\logic\Foo() -> bar()
  2. $this->modelFoo->bar()等效于new namespace\model\Foo() -> bar()
  3. $this->serviceFoo->bar()等效于new namespace\service\Foo() -> bar()
  4. $this->controllerFoo->bar()等效于new namespace\controller\Foo() -> bar()
  5. $this->libraryFoo->bar()等效于new namespace\library\Foo() -> bar()
  6. $this->validateFoo->bar()等效于new namespace\validate\Foo() -> bar()
  7. $this->viewFoo->bar()等效于new namespace\view\Foo() -> bar()

潜在缺点(个人看法)

  1. 分层需要很明细,如果不同app之间需要模块重用的话,需要将模块放置到common文件夹内。
  2. 处理模板view的模块,最后还是交给Controller处理,复杂逻辑交给Logic处理。
Buy me a beer
Jake Liu
Never Settle

Title: ThinkPHP5使用魔术方法加载model、validate、logic

Author: Jake Liu

Origin:

Creative Commons License

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) For any re-post you must give appropriate credit.

文章遵循CC许可 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 转载请注明出处

Tag:thinkphp

评论区

Add a new comment.

Theme