【问题标题】:PHP code duplication. At what point is duplicating code the right way to go?PHP 代码重复。什么时候复制代码才是正确的做法?
【发布时间】:2013-05-10 12:58:08
【问题描述】:

我正在使用 CodeIgniter,但这个问题也适用于一般意义上。

我有一个带有列的交易表

item_name | type | date | price | document

我想在两个完全独立的情况下执行以下操作。

1) 获取特定日期范围内的交易列表。 2) 获取特定日期范围内每笔transaction.type的总价。

前者可以通过简单地使用带有> datetimestamp的select语句来实现

后者可以通过选择 SUM 并按类型分组来实现,同时类似于实现任何所需的 where 条件,例如使用 > datetimestamp

虽然是一个简单的案例,但要实现这一点,我需要有两种方法,但是这两种方法的大部分(即 WHERE 子句)在两种方法中都是重复的。

就速度等而言,这并不重要,但这似乎是毫无意义的代码复制。


第二个例子如下。

我之前有一个方法get_data($ID),它会根据传入的 ID 从表中获取一行。

例如,在一个单独的方法中,我会得到我的 100 个项目。返回一个数组,遍历它们并为每个调用 get_data。

这种设置意味着许多不同的方法可以从不同的来源获取不同的列表,然后仍然使用相同的 get_data 函数和循环来获取所需的数据。

这最大限度地减少了代码重复,但效率极低,因为它意味着循环访问大量数据项和数百个数据库查询。

在我当前的设置中,我只是在我的每个方法中加入数据表 - 代码重复但明显提高了效率。


最后一个例子如下

在 codeigniter 中,我可以有如下功能:

get_thing($ID)
{
$this->load->database();
$this->db->where('ID',$ID);
$this->db->get('table');
}

但在其他情况下,我可能只想获取特定文件夹中的项目..因此使功能更通用效果更好..例如

get_thing($array)
{
$this->load->database();
$this->db->where($array);
$this->db->get('table');
}

但是我可能想在两个不同的上下文中使用此功能,例如用户页面和管理页面,管理员可以看到所有项目,甚至是未经验证的项目。我的代码现在变成了:

get_thing($array,$show_unverified = false)
{
$this->load->database();
$this->db->where($array);
if($show_unverified == false)
{
$this->db->where('verified','YES');
}
$this->db->get('table');
}

正如您可能看到的那样,这很快就会失控,方法可能会变得过于复杂、令人困惑且充满条件。


我的问题如下 - 减少代码重复的最佳做法是什么,以及如何将它们应用于上述情况?我花了好几个小时试图让我的代码更有效率,但我一无所获,因为我无法锻炼我真正应该努力实现的目标。

干杯

【问题讨论】:

  • 我完全同情!希望 CodeIgniter(或其他框架)专家会来解决这个问题。

标签: php codeigniter refactoring code-duplication


【解决方案1】:

我对数据库访问函数中的代码重复的想法是,最好将其分开。

我在这里的规则是特别是函数不应该根据参数返回不同类型的数据,例如它不应该有时返回单个用户,有时不返回用户数组。但它可能会返回错误代码 (false)。

如果函数实现不同的访问级别,这可以在多个页面之间共享。

【讨论】:

    【解决方案2】:

    这基本上总是回到常识。您应该尽量减少重复代码并尝试降低单个函数中的复杂性。让它们小而简单。

    所以基本上每次你尝试泛化这样的函数时,你都必须询问重复代码的问题是否比函数过于复杂的问题更大。

    在这种情况下,我会在你的第二点停下来,接下来你可以为最常见的任务创建一些包装器(但要小心不要让包装器迷宫)

    //you generic function
    function get_thing($array)
    {
    $this->load->database();
    $this->db->where($array);
    $this->db->get('table');
    }
    
    // a nice and friendly wrapper
    function get_thing_by_id($id)
    {
      get_thing(array('id' => $id));
    }
    
    // this is just getting silly. don't go crazy with wrappers, only for very often used things.
    // and yes the function name is purposely crazy ;)
    function get_thing_verified_by_name_and_city_and_some_more($name, $city, $somethingElse)
    {
      get_thing(array('name' => $name, 'city' => $city, 'somethingelse' => $somethingElse));
    }
    

    【讨论】:

      【解决方案3】:

      这回答了您问题的第一部分。假设您使用的是 mysql_fetch_assoc 或类似的。当您迭代结果集时,您可以将计数值存储在循环中的变量中,以获取每种交易类型的总价格。

      第二部分,只要您没有无限重复代码,这会导致您在维护代码库时出现问题,就可以了。对于您的函数,您始终可以测试传递给函数的变量类型并相应地设置条件行为。

      查看与软件设计模式相关的工厂模式或策略模式以获得进一步的见解。

      【讨论】:

      • 嗯,是的,我可以,但在这种情况下,如果有 10,000 条记录,则此循环将比使用 SUM 花费更长的时间..
      猜你喜欢
      • 2014-08-05
      • 2016-04-06
      • 1970-01-01
      • 2016-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-15
      相关资源
      最近更新 更多