记一次基类优化

March 5, 2019 PHP

记一次基类优化

为什么要优化?

首先我们来看下代码,如下:

<?php

abstract class AssistantDesk_ActionAbstract extends Ap_Action_Abstract
{

    protected $_requestParam = null;
    protected $_actionName = null;
    protected $_controller = null;
    protected $_apiVersion = null;
    protected $_tpl = null;
    protected $_errTpl = null;
    protected $_loginUrl = null;
    protected $_innerNetwork = false;
    protected $_feFisProjectName = 'fis';
    protected $_feVueProjectName = 'vue';
    protected $_avatarDefaultUrl = '头像地址';

    protected $_developerUid = [
        'Uid',
    ];

    protected $_tplData = [
        'errNo'  => 0,
        'errStr' => 'success',
        'data'   => [],
    ];

    protected $_outerNetRoute = [
       'Url'
    ];

    protected $_userInfo = [
        'assistantUid' => 0,
        'roleGrade'    => [],
        'groupRole'    => [],
        'nickname'     => '',
        'gradeGroup'   => '',
        'phone'        => 0,
        'isLogin'      => false,
    ];
    //    protected $_homeHost = null;
    //    private $_origUid = null;

    /*
     * 子类特有逻辑,强制子类必须实现
     */

    protected function _init()
    {
        //初始化配置文件选项
        $this->initConfig();

        $arrRequestParam     = Saf_SmartMain::getCgi();
        $this->_requestParam = ! is_null($arrRequestParam['request_param']) ? $arrRequestParam['request_param'] : [];

        $sessionInfo = Saf_SmartMain::getUserInfo();

        if (! in_array($sessionInfo['uid'], $this->_developerUid)) {

            // 内网判断使用
            $this->isNetworkType();

            // 内网判断使用
            $checkNetwork = $this->isNetworkType();

            if (! $checkNetwork) {
                header('Location: 错误页面');
                exit;
            }
        }

        //自动登录跳转
        $this->_loginUrl = 'url';

        if (! empty($sessionInfo) && ($sessionInfo['isLogin'] != false)) {
            //            if (! in_array($sessionInfo['uid'], $this->_developerUid)) {
            //                exit();
            //            }
            $this->getUserInfo($sessionInfo);
        }

        //打印输入参数日志
        $arrLogData = $this->_requestParam;
        foreach ($arrLogData as $logKey => $logValue) {
            if (is_string($logValue) && strlen($logValue) > 1000) {
                $logValue            = 'LongString';
                $arrLogData[$logKey] = $logValue;
            }
        }

        Hk_Util_Log::setLog('request_param', json_encode($arrLogData));
        //        if ( ! empty($this->_origUid)) {
        //            Hk_Util_Log::setLog('origUid', $this->_origUid);
        //        }
        if ($this->_innerNetwork === true) {
            Hk_Util_Log::setLog('innerNetwork', 1);
        }

    }

    abstract protected function invoke();

    /**
     * 校验用户是否登录
     * 如果未登录 同步接口跳转到登录页面 异步接口返回异常
     *
     * @throws Hk_Util_Exception
     */
    public function checkLogin($redirectFlag = false)
    {
       ...
    }

     /**
     * 设置前端模板  如果是非ajax接口  请先调用本方法设置模板
     *
     * @param $tpl
     */
    protected function setTpl($tpl)
    {
        $this->_tpl = $tpl;
        ...

    }

    /**
     * 设置错误页前端模板
     *
     * @param $tpl
     */
    protected function setErrorTpl($tpl)
    {
        $this->_errTpl = $tpl;
    }

    /**
     * 输出
     *
     * @return bool
     */
    protected function _display()
    {
        if ($this->_tpl && $this->_tplData['errNo'] == Hk_Util_ExceptionCodes::USER_NOT_LOGIN) {
            ...
            $this->redirect($this->_loginUrl);
        } else if ($this->_tplData['errNo'] > 0 && $this->_errTpl) {
            //错误页面输出
            $tpl = Bd_TplFactory::getInstance();
            //所有同步页面 补充登录用户信息
            ...
            $this->_tplData['refer']    = $_SERVER['HTTP_REFERER'];
            $tpl->assign($this->_tplData);
            $tpl->display($this->_errTpl);
        } else if ($this->_tplData['errNo'] == 0 && $this->_tpl) {
            //正常输出
            $tpl = Bd_TplFactory::getInstance();
            //所有同步页面 补充登录用户信息
            ...

            $tpl->assign($this->_tplData['data']);
            $tpl->display($this->_tpl);
        } else {
            if (! is_array($this->_tplData)) {
                $this->_tplData = [];
            }
            //json格式输出及jsonp格式输出
            if (isset($_GET['callback']) && ! empty($_GET['callback'])) {
                echo strval($_GET['callback']) . '(' . json_encode($this->_tplData) . ')';
            } else {
                Header('Content-type:application/json; charset=UTF-8');
                echo json_encode($this->_tplData);
            }
        }

        return true;
    }

    //统计处理
    protected function _processLog()
    {
        ...
        
    }

    /**
     * 开始执行
     */
    public function execute()
    {

        ...
        try {

            ...
            $this->_init();
            ...


            $res = $this->invoke();
            ...
            $this->_tplData['data'] = is_array($res) ? $res : [];

        } catch (Hk_Util_Exception $e) {
            $this->_tplData['errNo']  = $e->getErrNo();
            $this->_tplData['errStr'] = $e->getErrStr();
        }
        //输出
        Hk_Util_Log::start('ts_display');
        $this->_display();
        Hk_Util_Log::stop('ts_display');
        Hk_Util_Log::stop('ts_all');
        $this->_processLog();
    }


    /**
     * 内网判断使用
     */
    private function isNetworkType()
    {

        // 内网检测
        
        if ($this->_innerNetwork){
            return true;
        }

        foreach ($this->_outerNetRoute as $path) {
            if (strstr($_SERVER['REQUEST_URI'], $path) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * 初始化配置文件
     */
    private function initConfig()
    {
        // 域名请求参数等信息...
    }


    /**
     * 获取userInfo信息
     *
     * @param $sessionInfo
     */
    private function getUserInfo($sessionInfo)
    {
            // 省略大段逻辑判断,约100行...
    }
}

我们从以上代码可以看出来以下几个问题:

  • 代码逻辑不清晰
  • 声明的成员变量过多,并有些成员变量没有使用
  • 有些不需要登陆状态的API接口继承该基类也会把所有逻辑走一遍

针对以上问题作出改进如下:

UML类图

优化基本思路

将原有的逻辑段拆分成模块,每个模块之间不可以互相调用,具体如下:

  • 初始化模块
  • 网络模块
  • 请求模块
  • 外部用户信息模块
  • 用户信息模块
  • 日志模块
  • 白名单模块
  • 重定向模块
  • 模版渲染模块

实现两个基础基类:

  • api接口是对外部提供的接口,故不需要获取用户等信息,直接实现最基础的接口相关基类
  • 提供一个兼容现在老系统的基类,并添加自动检查权限、登陆态等信息,而不是在子类调用登陆和权限检查

如果其他业务有特殊要求,则自行组装即可

目录结构

├── ActionAbstract.php
├── ActionExceptionCode.php
├── ApiAbstract.php
└── component
    ├── InitConfig.php
    ├── Log.php
    ├── NetWork.php
    ├── Redirect.php
    ├── Request.php
    ├── Session.php
    ├── Tpl.php
    ├── User.php
    └── Whitelist.php

收益

  • 将基类拆解成模块化之后方便扩展,原聚合页面逻辑更加清晰
  • 减少不必要的逻辑验证,减少基类耗时,内存开销
  • 能够很好的控制和自定义组装基类,达到根据业务灵活调整

添加新评论