使用引用

使用引用

### 使用引用

**场景一:遍历一个数组获取新的数据结构**

也许你会这样写:

“`
// 申明一个新的数组,组装成你想要的数据
$tmp = [];
foreach ($arr as $k => $v) {

    // 取出你想要的数据
    $tmp[$k][‘youwant’] = $v[‘youwant’];
    …
    // 一系列判断得到你想要的数据
    if (…) {

        $tmp[$k][‘youwantbyjudge’] = ‘TIGERB’;
    }
    …
}
// 最后得要你想要的数组$tmp

——————————————————-

// 也许你觉着上面的写法不是很好,那我们下面换种写法
foreach ($arr as $k => $v) {

    // 一系列判断得到你想要的数据
    if (…) {

        // 复写值为你想要的
        $arr[$k][‘youwantbyjudge’] = ‘TIGERB’
    }
    …
    // 干掉你不想要的结构
    unset($arr[$k][‘youwantdel’]);
}
// 最后我们得到我们的目标数组$arr
“`

接下来我们使用引用值:

“`
foreach ($arr as &$v) {

    // 一系列判断得到你想要的数据
    if (…) {

        // 复写值为你想要的
        $v[‘youwantbyjudge’] = ‘TIGERB’
    }
    …
    // 干掉你不想要的结构
    unset($v[‘youwantdel’]);
}
unset($v);
// 最后我们得到我们的目标数组$arr
“`

使用引用是不是使我们的代码更加的简洁,除此之外相对于第一种写法,我们节省了内存空间,尤其是再操作一个大数组时效果是及其明显的。

**场景二:传递一个值到一个函数中获取新的值**

基本和数组遍历一致,我们只需要声明这个函数的这个参数为引用即可,如下:

“`
function decorate(&$arr = []) {

    # code…
}

$arr = [
    ….
];
// 调用函数
decorate($arr);
// 如上即得到新的值$arr,好处还是节省内存空间

“`

### 使用try…catch…

假如有下面一段逻辑:
“`
class UserModel
{

    public function login($username = ”, $password = ”)
    {

        code…
        if (…) {

            // 用户不存在
            return -1;
        }
        code…
        if (…) {

            // 密码错误
            return -2;
        }
        code…
    }
}

class UserController
{

    public function login($username = ”, $password = ”)
    {

        $model = new UserModel();
        $res   = $model->login($username, $password);
        if ($res === -1) {

            return [
                ‘code’ => ‘404’,
                ‘message’ => ‘用户不存在’
            ];
        }
        if ($res === -2) {

            return [
                ‘code’ => ‘400’,
                ‘message’ => ‘密码错误’
            ];
        }
        code…
    }
}
“`

我们用try…catch…改写后:
“`
class UserModel
{

    public function login($username = ”, $password = ”)
    {

        code…
        if (…) {

            // 用户不存在
            throw new Exception(‘用户不存在’, ‘404’);
        }
        code…
        if (…) {

            // 密码错误
            throw new Exception(‘密码错误’, ‘400’);
        }
        code…
    }
}

class UserController
{

    public function login($username = ”, $password = ”)
    {

        try {

            $model = new UserModel();
            $res   = $model->login($username, $password);
            // 如果需要的话,我们可以在这里统一commit数据库事务
            // $db->commit();
        } catch (Exception $e) {

            // 如果需要的话,我们可以在这里统一rollback数据库事务
            // $db->rollback();
            return [
                ‘code’    => $e->getCode(),
                ‘message’ => $e->getMessage()
            ]
        }
    }
}
“`

通过使用try…catch…使我们的代码逻辑更加清晰,try…里只需要关注业务正常的情况,异常的处理统一在catch中。所以,我们在写上游代码时异常直接抛出即可。

### 使用匿名函数

** 构建函数或方法内部的代码块 **

假如我们有一段逻辑,在一个函数或者方法里我们需要格式化数据,但是这个格式化数据的代码片段出现了多次,如果我们直接写可能会想下面这样:

“`
function doSomething(…) {

    …
    // 格式化代码段
    …
    …
    // 格式化代码段[重复的代码]
    …
}
“`

我相信大多数的人应该不会像上面这么写,可能都会像下面这样:

“`
function doSomething(…) {

    …
    format(…);
    …
    format(…);
    …
}

// 再声明一个格式花代码的函数或方法
function format() {

    // 格式化代码段
    …
}
“`

上面这样的写法没有任何的问题,最小单元化我们的代码片段,但是如果这个format函数或者方法只是doSomething使用呢?我通常会像下面这么写,为什么?因为我认为在这种上下文的环境中format和doSomething的一个子集。

“`
function doSomething() {

    …
    $package = function (…) use (…) { // 同样use后面的参数也可以传引用
        // 格式化代码段
        …
    };
    …
    package(…);
    …
    package(…);
    …
}
“`

** 实现类的【懒加载】和实现设计模式的【最少知道原则】 **

假如有下面这段代码:

“`
class One
{

    private $instance;

    // 类One内部依赖了类Two
    // 不符合设计模式的最少知道原则
    public function __construct()
    {  
        $this->intance = new Two();
    }

    public function doSomething()
    {

        if (…) {

            // 如果某种情况调用类Two的实例方法
            $this->instance->do(…);
        }
        …
    }
}

$instance = new One();
$instance->doSomething();

“`

上面的写法有什么问题?

– 不符合设计模式的最少知道原则,类One内部直接依赖了类Two
– 类Two的实例不是所有的上下文都会用到,所以浪费了资源,有人说搞个单例,但是解决不了实例化了不用的尴尬

所以我们使用匿名函数解决上面的问题,下面我们这么改写:

“`
class One
{

    private $closure;

    public function __construct(Closure $closure)
    {  
        $this->closure = $closure;
    }

    public function doSomething()
    {

        if (…) {

            // 用的时候再实例化
            // 实现懒加载
            $instance = $this->closure();
            $instance->do(…)
        }
        …
    }
}

$instance = new One(function () {

    // 类One外部依赖了类Two
    return new Two();
});
$instance->doSomething();

“`

### 减少对if…else…的使用

如果你碰见下面这种类型的代码,那一定是个黑洞。

“`
function doSomething() {

    if (…) {

        if (…) {

            …
        } esle {

            …
        }
    } else {

        if (…) {

            …
        } esle {

            …
        }
    }
}

“`

** 提前return异常 **

细心的你可能会发现上面这种情况,可能绝大多数else代码里都是在处理异常情况,更有可能这个异常代码特别简单,通常我会这么去做:

“`
// 如果是在一个函数里面我会先处理异常的情况,然后提前return代码,最后再执行正常的逻辑
function doSomething() {

    if (…) {

        // 异常情况
        return …;
    }
    if (…) {

        // 异常情况
        return …;
    }
    // 正常逻辑
    …
}

// 同样,如果是在一个类里面我会先处理异常的情况,然后先抛出异常
class One
{

    public function doSomething()
    {

        if (…) {

            // 异常情况
            throw new Exception(…);
        }
        if (…) {

            // 异常情况
            throw new Exception(…);
        }
        // 正常逻辑
        …
    }
}

“`

** 关联数组做map **

如果我们在客户端做决策,通常我们会判断不同的上下文在选择不同策略,通常会像下面一样使用if或者switch判断:

“`
class One
{

    public function doSomething()
    {

        if (…) {

            $instance = new A();
        } elseif (…) {

            $instance = new A();
        } else {

            $instance = new C();
        }
        $instance->doSomething(…);
        …
    }
}
“`

上面的写法通常会出现大量的if语句或者switch语句,通常我会使用一个map来映射不同的策略,像下面这样:

“`
class One
{

    private $map = [
        ‘a’ => ‘namespace\A’, // 带上命名空间,因为变量是动态的
        ‘b’ => ‘namespace\B’,
        ‘c’ => ‘namespace\C’
    ];
    public function doSomething()
    {

        …
        $instance = new $this->map[$strategy];// $strategy是’a’或’b’或’c’
        $instance->doSomething(…);
        …
    }
}
“`

### 使用接口

为什么要使用接口?极大的便于后期的扩展和代码的可读性,例如设计一个优惠系统,不同的商品只是在不同的优惠策略下具备不同的优惠行为,我们定义一个优惠行为的接口,最后对这个接口编程即可,伪代码如下

“`
Interface Promotion
{

    public function promote(…);
}

class OnePromotion implement Promotion
{

    public function doSomething(…)
    {

        …
    }
}

class TwoPromotion implement Promotion
{

    public function doSomething(…)
    {

        …
    }
}
“`

### 控制器拒绝直接的DB操作

最后我想说的是永远拒绝在你的Controller里直接操作DB,为什么?我们的程序绝大多数的操作基本都是增删改查,可能是查询的where条件和字段不同,所以有时候我们可以抽象的把对数据库增删改查的方法写到model中,通过参数暴露我们的where,fields条件。通常这样可以很大程度的提高效率和代码复用。比如像下面这样:

“`
class DemoModel implement Model
{

    public function getMultiDate($where = [], $fields = [‘id’], $orderby = ‘id asc’)
    {

        $this->where($where)
             ->field($fields)
             ->orderby($orderby)
             ->get();
    }
}
“`

### 最后

如果有写的不对的地方,欢迎大家指正,THX~

> [Easy PHP:一个极速轻量级的PHP全栈框架](http://php.tigerb.cn/)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/113821.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • LeetCode–046–全排列(java)

    LeetCode–046–全排列(java)给定一个没有重复数字的序列,返回其所有可能的全排列。示例:无奈,用swap的方法从左向右滑动,直到最后结果和最初的一致停止,只适用于三位数。。。。(改进一下让每个数字作为第一位后面的进行滑动,应该

  • 走近webpack(1)–多入口及devServer的使用

    上一篇文章留下了一些问题,如果你没看过上一篇文章,可以在我的博客里查找,或者直接从这篇文章开始也是没问题的。这是上一篇文章中使用但是没有详细讲解的代码片段。现在我们来一一做一个了解。entry:配

  • wxpython自定义控件_wxPython 教程(十三) 自定义控件

    wxpython自定义控件_wxPython 教程(十三) 自定义控件本节讲述wxPython自定义控件。GUIToolkits会提供多数常用的部件,比如按钮、文本控件、滚动条、滑块等等。wxPython也会提供很多控件,但若需要更定制化的控件还是需要开发者自己编写。自定义控件通过两种方式创建:一种是通过修改或增强现有控件,另一种是我们从零开始直接创建。超链接控件第一个例子是创建一个超链接控件,我们基于wx.lib.stattext.GenStatic…

  • Latex 公式换行、等号对齐问题

    Latex 公式换行、等号对齐问题Latex编辑遇到长公式需要换行、等号对齐问题。\usepackage{amsmath}%需要的包…\begin{equation}\begin{aligned}…%插入公式\end{aligned}\end{equation}在需要换行的位置添加“\\”,在需要对齐的’=‘前添加’&’(注意需要对齐的每个等号前都要加)运行即可。…

  • Android程序员如何制定自己的职业规划,拒绝做码农[通俗易懂]

    Android程序员如何制定自己的职业规划,拒绝做码农[通俗易懂]无论是程序员还是任何其他的职业,我认为都应该有清晰长远的职业规划。虽然说计划没有变化快,但如果没有计划就更谈不上计划了。没有职业规划的人,在工作上基本都是为了完成任务而做,很难得到提升,因为没有目标,所以人就是一种得过且过的状态。所以作为一个有眼光的人,应该有自己长远的职业规划,即使没有长远的职业规划,也应该有短期的规划,这样人做事才有动力,有目标。程序员一直都是一个热门话题,因为工资比较高,…

  • PXE分发安装CentOS6.5

    PXE分发安装CentOS6.5

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号