IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    用辅助函数来取代复杂的表达式

    forecho (caizhenghai@gmail.com)发表于 2016-12-19 04:09:22
    love 0

    引言

    上上上个月在图书馆淘到一本书叫《Effective Python - 编写高质量Python代码的59个有效方法》,虽然我不用 Python 写代码,但是好歹以前写过一点 Python 的皮毛。 豆瓣看了一下评分,就果断借了这本书。当看到第四条方法《第4条:用辅助函数来取代复杂的表达式 》结合自己最近几年编程经验,深有感触,于是就有了这篇文章。

    为什么要用辅助函数?

    在编程的时候,你肯定会遇到类似这样的事情:数据库中保存的商品单价单位是分,商品详情页需要你的商品价格,但是单位肯定是元。

    那么我们可以怎么样实现呢?一般的做法肯定这样的,直接在视图页面要展示价格的地方这样写:

    1
    
    <?= round(($price / 100), 2) ?>
    

    这样写虽然能实现效果,但是如果需求有变化,需要使用强制保留两位小数,那么你需要这样改:

    1
    
    <?= number_format(round(($price / 100), 2), 2, '.', ''); ?>
    

    看上去虽然不多的代码,但是

    • 阅读起来很困难,而且很上去也很乱。
    • 如果涉及到很多东西的话,需要找到每个相应的地方然后做修改。同理,下次改需求的时候,修改也将会是一件很痛苦的事情。

    如果使用辅助函数来实践的话,代码将会是这样的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    /**		
    * 分转元		
    * @param int $price 分		
    * @return float 元		
    */
    function fenToYuan($price)
    {
        $price = round(($price / 100), 2);
        return number_format($price, 2, '.', '');
    }
    // 视图层使用方式
    echo fenToYuan($price);
    

    一旦这样使用之后,代码将变得非常清晰,而且以后重构起来也非常方便。以上是为了说明辅助函数的作用特意列举的一个小示例,实际项目中,可能会有大量需要你使用这种方式编程的地方,你需要养成这种思维模式才是最重要的。

    PS:以上代码可以在这里查看并且运行。

    Yii2 中是如何实践的?

    Yii2 中有一个 helpers 文件夹,里面的代码推荐各位 PHP 工程师都应该去看看,注释都给了示例,非常的友好。

    下面我来简单分享一些常用的 helpers:

    ArrayHelper

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    // 最基本的用法,获取数组中的某个键对应的值。好处是不必判断 username 是否存在
    $username = \yii\helpers\ArrayHelper::getValue($_POST, 'username');
    // 也可以获取对象中的某个值
    $username = \yii\helpers\ArrayHelper::getValue($user, 'username');
    // 也可以使用匿名函数
    $fullName = \yii\helpers\ArrayHelper::getValue($user, function ($user, $defaultValue) {
        return $user->firstName . ' ' . $user->lastName;
    });
    // 使用「.」获取关联对象的属性
    $street = \yii\helpers\ArrayHelper::getValue($users, 'address.street');
    // 获取数组键值的数组键值
    $versions = ['date' => '2016年12月19日', '1.0' => ['date' => '2016年12月18日']];
    $value = \yii\helpers\ArrayHelper::getValue($versions, ['1.0', 'date']); // $value 输出为 2016年12月18日
    

    PS:以上代码可以在这里查看并且运行。

    有点太花时间,以后再补充……

    使用其他 helpers

    据我了解,Yii2 的 helpers 在其他 PHP 框架中也是可以使用的,但是本人没有亲测,不作保证。

    类似这种 helpers 是可以在网上找到的,比方说我就找到了phpfunct/funct

    当然也可以自己根据需要,收集使用,比方说根据这篇文章收集到 UUID 的生成方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    
    class Sequence
    {
        const EPOCH = 1000000000000;
    
        const TIME_BITS  = 41;
        const NODE_BITS  = 10;
        const COUNT_BITS = 10;
    
        private $node = 0;
    
        private $ttl = 10;
    
        public function __construct($node)
        {
            $max = $this->max(self::NODE_BITS);
    
            if (is_int($node) === false || $node > $max || $node < 0) {
                throw new \InvalidArgumentException('node');
            }
    
            $this->node = $node;
        }
    
        public function generate($time = null)
        {
            if ($time === null) {
                $time = (int)(microtime(true) * 1000);
            }
    
            return ($this->time($time) << (self::NODE_BITS + self::COUNT_BITS)) |
                   ($this->node << self::COUNT_BITS) |
                   ($this->count($time));
        }
    
        public function restore($id)
        {
            $binary = decbin($id);
    
            $position = -(self::NODE_BITS + self::COUNT_BITS);
    
            return array(
                'time'  => bindec(substr($binary, 0, $position)) + self::EPOCH,
                'node'  => bindec(substr($binary, $position, - self::COUNT_BITS)),
                'count' => bindec(substr($binary, - self::COUNT_BITS)),
            );
        }
    
        public function setTTL($ttl)
        {
            $this->ttl = $ttl;
        }
    
        private function time($time)
        {
            $time -= self::EPOCH;
    
            $max = $this->max(self::TIME_BITS);
    
            if (is_int($time) === false || $time > $max || $time < 0) {
                throw new \InvalidArgumentException('time');
            }
    
            return $time;
        }
    
        private function count($time)
        {
            $key = "seq:count:{$time}";
    
            while (!$count = apcu_inc($key)) {
                apcu_add($key, mt_rand(0, 9), $this->ttl);
            }
    
            $max = $this->max(self::COUNT_BITS);
    
            if ($count > $max) {
                throw new \UnexpectedValueException('count');
            }
    
            return $count;
        }
    
        private function max($bits)
        {
            return -1 ^ (-1 << $bits);
        }
    }
    

    最后总结

    编写可读性,可维护性,可扩展性的代码应该是每个开发工程师去追求的目标。程序员可以说是80%的时间都是在维护代码和阅读代码(包括别人的和自己的),所以一定要重视这些小细节。

    但实际上是很多人连最基本的单一职责原则都做不到,虽然有可能他们知道这个原则,但是不实践又有什么用呢?!



沪ICP备19023445号-2号
友情链接