有时您可能需要根据某个变量的值调用不同的函数。像这样:
if ($var == 'someValue1') {
$someObj->abc();
} elseif ...
} elseif ($var == 'someValueN') {
$someObj->xyz();
}
在 PHP 中有很多方法可以完成此任务。我找到了 8 种可能的选项:
- 使用一堆
if
/else
语句 - 使用
switch
语句 - 使用变量函数
- 使用匿名函数(定义匿名函数数组)
- 使用
call_user_func
和call_user_func_array
函数 - 使用多态性:抽象基类+一堆子类
- 使用
eval
语句 - 使用
ReflectionMethod::invoke
方法
看起来这些方法是情境化的。那么,请您解释一下我应该在哪些情况下使用这些选项以及为什么?
附言:下面是可能需要根据变量值调用不同方法的情况示例:
/**
* Checks if all needed parameters are present in the HTTP request
* @param array $params Parameters which have to be present in the request
* @throws MissingParameterException if any of the given parameters is missing
*/
public function checkParametersExistence($params)
{
foreach ($params as $param) {
$method = $param[0]; // a type of the param: get, post, put, delete
$name = $param[1]; // a name of the param
$code = $param[2]; // a code to send if this param is missing
// $exists = $this->request->isGetParamSet($name);
// ... = $this->request->isPostParamSet($name);
// ... = $this->request->isPutParamSet($name);
// ... = $this->request->isDeleteParamSet($name);
if ($exists == false) {
throw new MissingParameterException($name, $code);
}
}
}
我刚刚根据问题的验证示例编写了一个简单的基准测试来比较这些方法的执行速度。
一个测试执行验证循环 1000 次。测试重复 25 次以获得平均执行时间。代码可以在这里找到:https://gist.github.com/DWand/54ae49470ee8557432a3
机器配置:
- 中央处理器: 英特尔酷睿 2 双核 E7400 2.8GHz, 内存: 4Gb
- Windows 7 Home Premium Edition Service Pack 1
- PHP 版本 5.4.11
我得到以下结果:
- 测试"如果/否则顺序":0.01506411552429199秒
- 测试"开关":0.01624316215515137秒
- 测试"变量函数":0.02013579368591309秒
- 测试"匿名函数":0.1487146759033203秒
- 测试"函数call_user_func":0.1564707851409912秒
- 测试"函数值":0.2150658702850342秒
- 测试"反射":0.02306700706481933秒
- 测试"多态性":0.02339528083801269秒
这些方法可以根据执行速度进行分组:
- 如果/否则,切换(~ 0.016 秒)
- 变量函数, 反射方法, 多态性 (~ 0.023 秒)
- 匿名函数,call_user_func(~ 0.14-0.15 秒)
- 评估(~ 0.21 秒)
由于这些结果是由 1000 * 7 次语句执行而成的,因此可以认为执行速度几乎相同。 eval
函数中,匿名函数和call_user_func
函数可能是要避免的候选项,因为它们速度较慢。
问题有点笼统,但在大多数情况下,使用 swtich 语句或一堆 if-elses 是最糟糕的选择,因为:
- 一段时间后,阅读或/和理解此代码将非常困难。
- 这些构造很难扩展,因为它们经常破坏依赖反转原则。
这就是为什么根据具体情况,您可以考虑使用如下设计模式:
- 工厂方法模式
- 桥接模式
- 代理模式
- 。或其他;)
编辑:
在附加的代码中,您可以考虑首先检查方法(POST,GET,PUT,DELETE等),然后搜索精确请求类型的参数。但我不确定这个逻辑的目的是什么,所以我可能是错的;)
对于脚本:我更喜欢开关语句。
在我看来,在我的 c++/学生时代,开关更有效率(并不意味着 php 的暗示是)。
对于 OOP:
$someObj->func($varable)
private function func($action)
{
switch($action)
{
}
}