php - 如何减少 IF 语句的数量?

标签 php class if-statement refactoring dry

我有很多 IF 语句,每个语句都启动一个函数。
有没有明显的方法可以使这段代码更简单?
每个 IF 启动不同的功能,但它仍然看起来有点矫枉过正。

    if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool == '') {
        $this->AllTime();
    }
    if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool == '') {
        $this->ByMachine();
    }
    if ($this->machine == '' AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool == '') {
        $this->ByDate();
    }
    if ($this->machine <> 0 AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool == '') {
        $this->ByMachineByDate();
    }
    if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool == '') {
        $this->ByDateLike();
    }
    if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool == '') {
        $this->ByMachineByDateLike();
    }
    if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool <> 0) {
        $this->ByArticle();
    }
    if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool <> 0) {
        $this->ByMachineByArticle();
    }
    if ($this->machine == '' AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool <> 0) {
        $this->ByDateByArticle();
    }
    if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool <> 0) {
        $this->ByDateLikeByArticle();
    }
    if ($this->machine <> 0 AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool <> 0) {
        $this->ByMachineByDateByArticle();
    }
    if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool <> 0) {
        $this->ByMachineByDateLikeByArticle();
    }

解决方案
这是我重构后的代码:

function MethodPicker() {
    $machine            = $this->machine            <> 0;
    $date_from          = $this->date_from          <> 0;
    $date_to            = $this->date_to            <> 0;
    $date_like          = $this->date_like          <> 0;
    $article_or_tool    = $this->article_or_tool    <> 0;

    $decision  = array($machine, $date_from, $date_to, $date_like, $article_or_tool);
    $decisions = array(
                    'AllTime' =>                        array(false,    false,  false,  false,  false   ),
                    'ByMachine' =>                      array(true,     false,  false,  false,  false   ),
                    'ByDate' =>                         array(false,    true,   true,   false,  false   ),
                    'ByMachineByDate' =>                array(true,     true,   true,   false,  false   ),
                    'ByDateLike' =>                     array(false,    false,  false,  true,   false   ),
                    'ByMachineByDateLike' =>            array(true,     false,  false,  true,   false   ),
                    'ByArticle' =>                      array(false,    false,  false,  false,  true    ),
                    'ByMachineByArticle' =>             array(true,     false,  false,  false,  true    ),
                    'ByDateByArticle' =>                array(false,    true,   true,   false,  true    ),
                    'ByDateLikeByArticle' =>            array(false,    false,  false,  true,   true    ),
                    'ByMachineByDateByArticle' =>       array(true,     true,   true,   false,  true    ),
                    'ByMachineByDateLikeByArticle' =>   array(true,     false,  false,  true,   true    ),
    );
    $method = array_keys($decisions, $decision, true);
    $method && list($method) = $method;
    $method && $this->$method();
}

最佳答案

首先我会做一些标准的重构。不知道我为什么那样做,但这是什么:

  1. 用局部变量替换属性,比如

    $machine = $this->machine;
    
  2. 同样适用于这些条件,但是仔细观察这些条件会发现每个变量只有两个状态,所以这实际上是每个变量只有一个条件(请参阅 Type Juggling ),这导致 。分配条件,而不是:

    $machine = $this->machine == '' || $this->machine == 0;
    

(感谢 martinstoeckli 正确的条件)

这将是一个开始。到现在为止的 if 子句已经改变并且会更紧凑。然而,为什么要停在这里呢?有一个当前的决定:

$decision  = [$machine, $date_from, $date_to, $date_like, $article_or_tool];

并且有一组决策可供选择:

$decisions = [
    'AllTime' => [true, true, true, true, true],
    ...
];

所以需要做的就是找到决策并执行方法:

$method = array_keys($decisions, $decision, true);
$method && $this->$method();

if block 已变成矩阵。该功能已映射到它的一个状态。

您丢失了字段上的名称,但是,您可以通过注释解决该问题:

    $decisions = [
        //            machine  from  to    like  article
        'AllTime' => [true   , true, true, true, true],
        ...
    ];

一目了然:

$machine = $this->machine == '' || $this->machine == 0;
... # 4 more times

$decision  = [$machine, $date_from, $date_to, $date_like, $article_or_tool];

$decisions = [
    'AllTime' => [true, true, true, true, true],
    ... # 11 more times
];

$method = array_keys($decisions, $decision, true);
$method && $this->$method();

如果 this 所在的类表示一个值对象,我建议您将决策移到它自己的类型中,然后将该决策类型用作单个方法对象。将使您以后能够更轻松地做出不同的决策集。

关于php - 如何减少 IF 语句的数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13138952/

相关文章:

php - Mysql INSERT INTO 和 UPDATE 无法正常工作

javascript - jQuery - 将标签和复选框组限制为最大数量

php - 通过 ORM 将扩展的 Kohana DB 类用于多个数据库

PHP Addslashes 在转义单引号时添加双反斜杠

c++ - C++ 中的谓词是什么?

c++ - 如何在类构造函数和重载运算符中创建不同的类对象(C++)

matlab - 无法设置Matlab类的参数

java - 我的用于输入姓名、年龄以及查看一个人是否年龄足以做某事的 Java 代码有什么问题?

javascript - 避免两个 php 请愿同时发生

c++ - 我怎样才能 Eloquent 地写 "if not greater than or equal to some value"?