【问题标题】:How to replace nested switch statements如何替换嵌套的 switch 语句
【发布时间】:2012-05-25 16:09:06
【问题描述】:

我被要求编写一个小的 PHP 脚本,该脚本从几个下拉框中获取一些 POST 输入,这些下拉框给出了一些可选择的标准,最后,吐出一个或多个包含唯一代码的字符串变量。

变量names 的形式是$thingPlaceType,并且每一个都是唯一的。下拉框允许选择:

  • 一个“事物”或所有“事物”一起
  • 一个“地方”或所有“地方”一起
  • 一个“类型”或所有“类型”一起

如果不使用嵌套的 switch 语句,我无法弄清楚如何选择这些代码

switch($_POST['thing'])
{
  case "thing1":
     switch($_POST['place'])
     {
       case "place1":
          switch($_POST['type'])
          {
            case "type1":
               $output = $thing1Place1Type1;
            case "type2":
               $output = $thing1Place1Type2;
            case "alltypes":
               $output = $thing1Place1Type1.$thing1Place1Type2.$thing1PlaceType3;
           }
        case "place2":
        ...
        case "allplaces":
        ...
      }
  case "thing2":
     switch($_POST['place'])
     {
       case "place1":
          switch($_POST['type'])
          {
            case "type1":
               $output = $thing1Place1Type1;
            ...
      ...
  ...
}

似乎代码正在变成箭头反模式。我想我可以使用多维数组或单个数组来做一些事情,我将值与键进行匹配。但我觉得那是在抓着稻草,一定有什么我错过了。是时候将字符串转换为具有属性的适当对象了吗?

【问题讨论】:

  • 像 '$thing1Place1Type1' 这样的变量 - 这只是伪代码,还是您真的需要评估变量名?
  • 任何时候你有一堆名称非常相似的变量,你很有可能需要重新评估你的设计。例如。 $thing1place1$thing1place2 等非常自然地映射到例如$things_places = array( 1 => array( 1 => 'some place', 2 => 'another place' ), 2 => ... );(或者您也可以使用显式键名,例如 'places' => array( 1 => ... ))。转向更合理的数据模型,您会发现此类问题更易于管理,即使不是不存在。

标签: php nested switch-statement anti-patterns


【解决方案1】:

您需要将代码重构为函数。例如:-

switch($_POST['thing'])
{
  case "thing1":
      $result = processThings($thing1);
      break;
  case "thing2":
      $result = processThings($thing2);
      break;
}

function processThings($thing)
{
    //processing code goes here
}

我相信你明白了。如果您愿意,您可以在函数中添加更多的 switch 块,这将避免您的反模式并使您的代码更易于理解。

【讨论】:

  • 这有帮助,但之后仍然是一个几乎无法维护的烂摊子,所以我不得不重写整个部分。
  • @Biggles 也看看这个答案。 stackoverflow.com/a/106482/212940
【解决方案2】:

如果你想将它们转换为对象..你可以创建这个。

  class Object {
        private $thing;
        private $place;
        private $type;

        public function __construct() {
            $this->thing = $_POST['thing'];
            $this->place = $_POST['place'];
            $this->type  = $_POST['type'];

            $this->processThing($this->thing, $this->place, $this->type);
        }

        public function processThing($thing = false, $place = false, $type = false) {
               //noW that you have all the properties you just need just process it
        }

    }

    if(isset($_POST['thing']) && isset($_POST['place']) && isset($_POST['type'])) {
        $object = new Object();
    }

【讨论】:

  • 这与我最终要做的最接近。我构建了对象并从变量名本身获取了 Thing、Place、Type 属性。然后实际上只做一些if ($thing && $place && $type) 语句就容易多了。
  • 这看起来正是我用来编写自动填充 XML 模式的函数的逻辑。您可能刚刚让我想到了一个页面功能的好主意。
【解决方案3】:

好吧,如果您能找到一种方法来避免人们损害您的网站 - 也许通过在目标变量名称上使用前缀,那么您也许可以这样做:

$variableName = "A prefix_".$_POST['thing'].$_POST['type'].$_POST['place'];

$evaluatedVariable = $$variableName;

这些被称为“变量”。可能我会因为使用它们而被激怒,但如果你能负责任地使用它们,我发现它们在过去很有用。

当然,这不会直接适用于您的“所有类型”案例。您可以使用该建议重构为函数

【讨论】:

  • 那非常不安全,而且是一个糟糕的建议。如果您在使用之前先添加if (in_array($_POST['thing'],array("thing1","thing2"))){..},可能不会那么多。
  • 是的,这可以工作 - 当然,这就是前缀的原因 - 它限制了可以评估的可能变量
  • 对此表示赞同。我确实按照这些思路尝试了一个想法,因为我可以很容易地验证输入以确保它是安全的(而且它无论如何都不是面向网络的)。然而,由于“全部”选择​​,它变得复杂了。
  • 感谢 Biggles :) 这有点像“marmite”功能,您当然需要牢记安全,因为人们很快就会指出。当然,在某些情况下可能很有用。
猜你喜欢
  • 2013-04-02
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多