【问题标题】:How to pass a boolean argument to a function to act as a switch?如何将布尔参数传递给函数以充当开关?
【发布时间】:2017-10-18 04:55:51
【问题描述】:

如果标题不清楚,我深表歉意,但我觉得这很难描述。基本上,我有一个函数可以在给定班级 ID 号和日期的情况下查找班级(学校类型)的实例。如果需要,该函数还可以创建一个新的类实例。

function get_class_instance($class_id, $date, $create)

函数内部是对 class_instances 表的数据库选择,使用 class_iddate 作为参数。如果找到匹配的 class_instance,则返回其 ID。如果没有找到,则 create 参数有一个条件。如果为真,则使用数据库插入创建一个新的 class_instance,并返回其 ID。如果为 false,则数据库中没有任何更改并返回 false

我仍然是 PHP 和编码的初学者,所以我认为可能有更好的方法。问题是在调用函数时,有人可能不清楚为什么要传递一个布尔值。

$original_cinstance_id = get_class_instance($original_class_id, $original_date, 1);

【问题讨论】:

  • 查找“枚举数”。我不认为它真的有那么大的问题,但根据所传递标志的性质,您可以创建一个辅助数据结构,该结构基本上给出布尔或整数标志语法含义。
  • 你在寻找类似this的东西
  • 将布尔标志传递给函数以使它们做两件不同的事情而不仅仅是一件事情,这在 Robert Martin 的 Clean Code book 中被认为是 Code Smell。建议的更好的选择是有两个函数get_whatevercreate_whatever
  • @Gordon,我认为你是对的。我知道有些事情感觉不对劲,你说出了原因。另外,如果我想在搜索中使用“标志”,我可能会看到很多。无论如何,如果您想将此信息放入答案中,我会将其标记为已接受。

标签: php function


【解决方案1】:

Robert MartinClean Code book 中将布尔标志传递给函数以使它们执行两件不同的事情而不仅仅是一件事情被视为Code Smell。建议的更好的选择是有两个函数get_whatevercreate_whatever

虽然代码气味取决于上下文,但我认为布尔标志气味确实适用于这种情况,因为创建某些东西与仅仅阅读它是不同的。前者是命令,后者是查询。 So they should be separated。一个改变状态,另一个不改变。它有助于更​​好的语义和separation of concerns 拆分它们。此外,它会将函数的Cyclomatic Complexity 减少一个分支,因此您将需要更少的单元测试来覆盖它。

引用https://martinfowler.com/bliki/FlagArgument.html

布尔参数大声声明函数做不止一件事。它们令人困惑,应该消除。

引用http://www.informit.com/articles/article.aspx?p=1392524

我的理由是,单独的方法更清楚地传达了我拨打电话时的意图。当我看到book(martin, false) 时不必记住标志变量的含义,我可以轻松阅读regularBook(martin)

其他讨论和阅读材料:

【讨论】:

  • 谢谢。所以我假设create_whatever 的逻辑将始终存在于与get_whatever 相同级别的代码中?换句话说,我应该将该逻辑保留在控制器中而不是模型中吗?
  • @cbunn 控制器的职责是接受请求并委托给模型。该模型包含创建或获取任何内容的实际逻辑。所以你将在两个层中都有这两种方法。
  • 如果我理解“代码异味”的概念,重点是描述那些本身并不坏的事情,甚至导致不好的事情,但表明底层代码中存在更严重的问题.如果您要声明某种代码异味,那么您必须说出它的含义,否则您实际上只是在说“我不喜欢它”。 (这就是为什么我对“代码味道”不温不火的原因,它很容易成为一种将个人风格考虑提升为好与坏的方式)
  • @slackOverflow,我听到了,但我确实认为这表明存在问题。我在问题中提到可能会提高清晰度。所以我认为这是根本问题。这个标志的作用并不完全清楚。在您的回答中,可以肯定的是,这种意图变得更加明确,但我认为两个函数可以更好地分离关注点。此应用程序仅由我编写,但从长远来看,此类问题仍可能使其更难以维护。
  • @slackOverflow 我扩展了答案。代码异味是一种提示或启发,即应重构特定代码段以提高该特定代码段或整体软件质量。
【解决方案2】:

您可以使用默认值进行创建,因此如果您将任何内容传递给它,它将充当数据库的正常“获取”操作。像这样:

function get_class_instance($class_id, $date, $create = false);

您可以这样查询您的 ID:

$class_id = get_class_instance(1, "18-10-2017");

然后,您可以在需要在数据库上创建它时将“true”传递给它:

$class_id = get_class_instance(1, "18-10-2017", true);

【讨论】:

  • 谢谢。实际上,我只是阅读了有关默认值的信息,但没有想到在这里应用它。我会记住它以备将来使用,但我认为@Gordon 是正确的,这是一种不好的形式。
  • 当您拥有一个具有自动完成功能的合理 IDE 时,使用可选参数没有任何问题。如果它是一种糟糕的形式,那么每种语言都不会实现此功能。阅读更多:softwareengineering.stackexchange.com/questions/22559/…
  • 这不是关于拥有一个 可选 参数,而是明确地关于拥有一个布尔标志,该标志会导致函数具有多种行为。阅读更多:softwareengineering.stackexchange.com/questions/147977/…
  • @Gordon,你说得对,大部分代码都使用了first()firstOrCreate() 等方法来进行此操作。但这并不会使这种做法成为一种糟糕的做法。这就是我的观点。而且,如果你像fopen的FILE_APPEND、FILE_CREATE标志一样使用它,当然会更好。
【解决方案3】:

您可以像这样传递一个真正的布尔值,而不是传递一个数字值:

$original_cinstance_id = get_class_instance($original_class_id, $original_date, true);

同样在你的函数声明中,你可以指定一个默认值来避免每次都传递布尔值:

function get_class_instance($class_id, $date, $create = false)

【讨论】:

  • 谢谢。数值和布尔值之间的差异并不是我担心的。更重要的是,无论哪种情况,都很难知道那面旗帜的目的是什么。所以,我会在未来记住默认值,但我认为@Gordon 是正确的,这是一种不好的形式。
【解决方案4】:

一种选择是像这样创建一个枚举器:

abstract class create_options {
    const no_action = 0;
     const create = 1;
}

所以现在你的函数调用看起来像这样:

$original_cinstance_id = get_class_instance($original_class_id, $original_date, create_options::no_action);

在实践中,只要您的代码被很好地注释,那么这不是布尔标志的主要问题,但是如果您有十几个可能的选项具有不同的结果,那么这可能会很有用。

正如其他人所提到的,在许多语言中,您还可以将参数设为可选,并具有默认行为,除非调用者明确定义了该参数。

【讨论】:

  • 我认为这种方法太过分了。 @TahaPasku 方法看起来更好
  • 我同意这种情况有点矫枉过正,我在最后也这么说。如果情况变得更复杂,很高兴知道这个选项在那里。
  • 我认为这是最好的解决方案 - 虽然你今天可能会传递一个布尔值,但谁知道你明天可能想要传递什么。您可能需要更丰富的上下文,此解决方案提供了这种可扩展性。此外,如果您需要知道 create 选项在代码中的位置,您可以使用 IDE 工具查找类常量的用法。使用动态类型的0/false/null/[]/array()/etc. 值的替代方法更难以准确和全面地跟踪整个代码库。
  • 谢谢。这真的很聪明,我会记住它的未来,但我认为@Gordon 是正确的,这是一种糟糕的形式。
  • 正如我在上面评论的那样,我并不反对 gordon 本身,但他并没有做更多的事情,只是用一个花哨的词说他不喜欢它。戈登只说传递布尔标志是不好的形式。尽管我已经有很长时间没有做某事了,但我上面描述的内容在图书馆中无处不在。一个例子是 SDL 的窗口标志:wiki.libsdl.org/SDL_WindowFlags 将它们中的每一个作为单独的函数是不切实际的。
猜你喜欢
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 2013-09-04
  • 2015-12-26
  • 2015-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多