在PHP中,基于变量值调用不同方法的最佳实践是什么?

3

有时候,您可能需要根据某个变量的值调用不同的函数。就像这样:

if ($var == 'someValue1') {
    $someObj->abc();
} elseif ...
} elseif ($var == 'someValueN') {
    $someObj->xyz();
}

在PHP中实现这个任务有许多方法,我找到了8种可能的选项:
  1. 使用一堆if/else语句
  2. 使用switch语句
  3. 使用可变函数
  4. 使用匿名函数(定义一个匿名函数数组)
  5. 使用call_user_func和call_user_func_array函数
  6. 使用多态:抽象基类+一堆子类
  7. 使用eval语句
  8. 使用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);
        }
    }
}

4
也许如果您展示真实的使用情况,您会得到更有用的建议。您给出的例子看起来相当不太可能。 - MightyPork
2
同意@MightyPork的观点,问题太笼统了。对我来说,通常的解决方案是 - 如果你确实需要10个以上的可能情况 - 那么95%的情况下应该在应用程序设计方面进行改进。 - Ilia Kondrashov
@DWand也许你正在尝试用一个控制器/操作解决太多的业务情况?尝试使用路由器分离不同的请求类型(GET/POST/...)-这样会更好。甚至可以为每个不同的请求使用单独的控制器/操作。对我来说,单一职责很有效。 - Ilia Kondrashov
1
每个操作都必须检查所有必需参数的存在- 这仍然听起来像是你的路由器可以做的事情。但如果有什么原因你不能这样做,那么也许在一个检查方法中调用验证器列表,而不是使用 if / else,如果它们失败了就让它们抛出异常。然后你只需要在一个验证方法中拥有一个验证器列表,这似乎足够整洁和可读。 - halfer
啊,说得对。我在考虑URL/GET路由 - 例如/SausageSearch/:meatType会指定这个端点需要一个必需的肉类类型字符串。如果你想了解更多关于这方面的内容,可以查看Slim或Silex的路由部分 - 它们通常有语法来使参数可选,应用正则表达式条件等。通常,如果这些验证失败,路由会被忽略,这通常是所需的。当然,你也可以在路由器中更加宽容,然后在处理程序中引发错误,如果你愿意的话。 - halfer
显示剩余9条评论
3个回答

3
我刚刚根据问题中的验证示例,编写了一个简单的基准测试,以比较这些方法的执行速度。
一个测试会执行1000次验证循环。为了得到平均执行时间,测试会重复25次。代码可在此处找到:https://gist.github.com/DWand/54ae49470ee8557432a3 机器配置:
- CPU: Intel Core 2 Duo E7400 2.8GHz, RAM: 4Gb - Windows 7 Home Premium Edition Service Pack 1 - PHP Version 5.4.11
我得到了以下结果:
- 测试 "If/Else sequense": 0.01506411552429199 秒。 - 测试 "Switch": 0.01624316215515137 秒。 - 测试 "Variable functions": 0.02013579368591309 秒。 - 测试 "Anonymous functions": 0.1487146759033203 秒。 - 测试 "Function call_user_func": 0.1564707851409912 秒。 - 测试 "Function eval": 0.2150658702850342 秒。 - 测试 "Reflection": 0.02306700706481933 秒。 - 测试 "Polymorphism": 0.02339528083801269 秒。
这些方法可以根据执行速度分为以下组:
- If/Else、Switch(约0.016秒) - Variable functions、ReflectionMethod、Polymorphism(约0.023秒) - Anonymous functions、call_user_func(约0.14-0.15秒) - eval(约0.21秒)
由于这些结果由1000 * 7次语句执行组成,因此可以认为执行速度几乎相同。eval函数、anonymous functions和call_user_func函数可能是需要避免的选择,因为它们比较慢。

不错的比较,可能会非常有用 :) - Arius
真是太棒了。我真的印象深刻你花了时间。谢谢。 - terary

2
问题有点泛泛而谈,但在大多数情况下,使用switch语句或一堆if-else是最糟糕的选择,因为:
  1. 过一段时间后,阅读和理解这段代码将变得非常困难。
  2. 这些结构很难扩展,因为它们经常违反依赖倒置原则。
因此,根据具体情况,您可以考虑使用设计模式,例如:
  1. 工厂方法模式
  2. 桥梁模式
  3. 代理模式
  4. ...或其他模式 ;)
编辑:
在附带的代码中,您可以首先检查方法类型(POST、GET、PUT、DELETE等),然后在确切的请求类型中搜索参数。但我不确定这种逻辑的目的是什么,所以可能不正确;)

说实话,我很惊讶在不同情况下没有一般性的建议可以使用哪种方法。最终,通过谷歌搜索、提问和思考,我得出了以下结论:需要考虑方法的一般目的,并思考为什么添加了这个功能。这是一个有趣的主题进行一些研究。然而,我将接受这个答案作为所有给定答案中最有用的。谢谢,@Arius。 - DWand
欢迎您,@DWand! - Arius

0

关于脚本编程:

我更喜欢使用switch语句。

在我的C++/学校时代,switch语句似乎更高效(并不意味着PHP的实现也是如此)。

关于面向对象编程:

$someObj->func($varable)

private function    func($action)
{
   switch($action)
   {

   }

}

请按照MightyPork的编辑要求,使用Markdown格式化代码语句。此外,您是否意味着在函数前加上“function”以便PHP知道它是什么? - halfer
1
我的错,我对那些我没有打算运行的代码有点懒。 - terary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接