假设我有一个这样的类:
class Foo{
public function bar($p,$p2=null,$p3=null){
//...
}
}
有时我需要称它只传递第一个和第三个参数。问题是我必须放置第二个参数,传递任何东西,只是为了达到第三个。
我可以为可选参数创建私有属性和 setter 方法,并将它们从方法签名中删除。
这是一个好的做法吗?还是最好使用__call
或func_get_args
?
我在 SO 中读到的消息来源:
- 什么是 php 中的函数重载和覆盖?
- PHP 函数重载
并在手册中:
- http://www.php.net/manual/en/language.oop5.overloading.php
- http://www.php.net/manual/en/function.func-get-args.php
我可以为 可选参数并将其从方法签名中删除。
如果原因是您希望他们让开,那么这样做将是一个非常糟糕的主意。
什么是参数,什么是属性是构成类设计的决策,因此只有在查看全局(与任何其他设计决策一样(之后,才应将一个交换为另一个。不要进行这种更改,因为您不喜欢一个特定方法的特定调用站点的读取方式。
我们无法判断参数是否有意义,因此对于其余部分,我将假设它没有意义。在这种情况下有哪些选择?
选项 #1:重构
- 在此方法上有两个可选参数是否有意义?
- 您通常在调用它时会省略其中一个(或两个(吗?
如果这些问题的答案是"是",这可能表明该方法根据参数以不同的模式运行。在这种情况下,将模态行为分解为具有简化签名的单独方法是有意义的。
选项 #2:属性捆绑
包- 此方法是否有很多具有合理默认值的参数?
- 您是否通常在典型呼叫中仅提供其中的几个(或不提供(这些?
如果这些问题的答案是"是",那么你可以让该方法接受数组作为其最后一个参数,并将其用作"杂项选项"的容器。
这种方法有一个(很大的!(缺点,即这些选项不再通过方法签名进行通告,但如果存在合理的默认值,您不会在 90% 的时间内触及,那么它是有意义的。
选项#3:流畅的界面
如果可以指定很多选项,那么创建一个流畅的接口是有意义的,但这是一个很大的变化,除非有额外的参数(例如,如果需要可组合性(,否则不应该进行。您可以将流畅的接口视为将参数转换为属性的更好工程版本。
编写一个流畅的接口涉及一个新类,该类封装了可能进入函数调用的所有参数;该类对每个参数都有一个方法,以及一个或多个使用这些参数来执行工作的方法。一个流畅的接口调用站点看起来像
$foo->bar()->color('red')->type('widget')->execute();
此处$foo->bar()
返回封装类的实例,color
和type
是该类上设置属性并execute
读取这些属性并执行实际工作的方法。
你怎么能用funct_get_args
或call
来定义哪个参数是第二个或第三个参数?只有当它们具有不同的类型时,才有可能。
在我看来,如果您想要一种强大的方法来处理许多可能是可选的参数,请使用像捆绑对象这样的容器(通用或特定于您的函数(,或者更友好的关联数组。