【问题标题】:PHP switch, why doesn't this work?PHP开关,为什么这不起作用?
【发布时间】:2012-03-26 19:54:07
【问题描述】:

我有一个似乎无法解决的奇怪问题。我编写了相当复杂的代码,但我已经简化了它,问题仍然存在。

请参阅以下内容:

<?php
$meta = array('meta_title' => 'correct');

switch (true) {
    case empty($meta['meta_description']):
        $meta['meta_description'] = 'incorrect';
    case empty($meta['meta_keywords']):
        $meta['meta_keywords'] = 'incorrect';
    case empty($meta['meta_title']):
        $meta['meta_title'] = 'incorrect';
}

print_r($meta);

现在由于某种原因,他返回的 meta_title 是不正确的,尽管它已明确设置在数组中。就好像它忽略了这个案子,直接掉了下来。

我在 http://codepad.org/mQH9Kf1L 上设置了一个示例

提前致谢!

更新

看看我在哪里使用它可能更有意义。请参阅以下内容: http://codepad.org/WnxBp8Nt(从第 43 行开始)

只是出于兴趣,我改变了我添加了一个快速微计时器并测试了这个版本和一个用单独的 ifs 编写的版本。 if 版本出来的速度有点慢。

【问题讨论】:

  • +1 用于将您的代码简化为可用示例。
  • 您忘记在每个案例结束时break
  • 同意 Nanne - 人们没有意识到这有多重要 :)
  • 尽管人们的评论可能是对的,但您可以通过各种方式进行评论,这让我很感兴趣。为什么这不起作用?如果您删除其他 2 种情况,true == empty(blah) 确实可以按预期工作,但是当其他人空着时,它不会.. 困扰我 ;)
  • 正是我的想法。我实际上是用另一种方式写的,但只是在试图获得更短的代码。有趣的是,如果您将 meta_description 和 meta_keywords 添加到数组中,它们都不会触发。

标签: php arrays switch-statement


【解决方案1】:

它没有做你想做的事情的原因是,如果情况 1 为真,情况 2 和 3 会自动触发(如果情况 2 为真,情况 3 总是会触发)。这不是switch 的用途。你真的只需要 3 个单独的 if 子句:

<?php
$meta = array('meta_title' => 'correct');

if (empty($meta['meta_description']))
        $meta['meta_description'] = 'incorrect';
if (empty($meta['meta_keywords']))
        $meta['meta_keywords'] = 'incorrect';
if (empty($meta['meta_title']))
        $meta['meta_title'] = 'incorrect';

print_r($meta);

【讨论】:

  • 所以你的意思是如果你不破坏下面的每一个代码将被执行而不检查他们的情况? ..这...出乎意料...
  • 啊,我以为是问题所在。不过,这似乎并不奇怪吗?我原以为它会不停地下降并测试下一个案例!
  • 并不意外 - 这正是 switch 的用途。如果你不是故意的,你不应该使用switch。用来代替长长的if/elseif/elseif/else,而不是一系列独立的if语句
  • 现在完全说得通了,并解释了微型计时器的结果!
【解决方案2】:

引用PHP Documentation for Switch:

了解switch语句是如何执行的很重要 为了避免错误。 switch语句逐行执行 (实际上,逐个声明)。一开始,没有代码 执行。仅当找到具有以下值的 case 语句时 匹配 switch 表达式的值 PHP 是否开始执行 声明。 PHP 继续执行语句直到结束 的 switch 块,或者它第一次看到一个 break 语句。如果 你不会在 case 语句的末尾写一个 break 语句 列表中,PHP 会继续执行以下 case 的语句。

你真正想做的是:

<?php
$meta = array('meta_title' => 'correct');

switch (true) {
    case empty($meta['meta_description']):
        $meta['meta_description'] = 'incorrect';
}
switch (true) {
    case empty($meta['meta_keywords']):
        $meta['meta_keywords'] = 'incorrect';
}
switch (true) {
    case empty($meta['meta_title']):
        $meta['meta_title'] = 'incorrect';
}

print_r($meta);

【讨论】:

    【解决方案3】:

    记得break:

    $meta = array('meta_title' => 'correct');
    
    switch (true) {
        case empty($meta['meta_description']):
            $meta['meta_description'] = 'incorrect';
            break;
        case empty($meta['meta_keywords']):
            $meta['meta_keywords'] = 'incorrect';
            break;
        case empty($meta['meta_title']):
            $meta['meta_title'] = 'incorrect';
            break;
    }
    
    print_r($meta);
    

    以上内容也使 没有意义

    不应对上述情况使用 switch 语句。

    尝试使用if...elseif...

    if(empty($meta['meta_description']))
        $meta['meta_description'] = 'incorrect';
    elseif(empty($meta['meta_keywords']))
        $meta['meta_keywords'] = 'incorrect';
    elseif(empty($meta['meta_title']))
        $meta['meta_title'] = 'incorrect';
    

    【讨论】:

    • 如果我打破了,它打破了逻辑。我真的将每个案例用作 3 个单独的 if,并且只是在寻找一种缩短代码的方法。
    【解决方案4】:

    中断并不能解决问题。 If/else 不起作用,因为有很多需求。你的代码也没有意义。你听说过 foreach 吗?

    <?php
    $MetaDefault = array('meta_description', 'meta_title', 'meta_keywords');
    
    $Meta = array('meta_title' => 'correct');
    
    foreach($MetaDefault as $Row){
        if(!isset($Meta[$Row])){
            $Meta[$Row] = 'incorrect';
        }
    }
    
    print_r($Meta);
    ?>
    

    如果你打破,它将退出开关。 您的其他变量不会被测试。 if/else 也会这样做。

    【讨论】:

    • 我可以这样做,但那是很多行。并不是说我不能再做一次,我只是想知道为什么第三种情况验证为真并运行下一行(如果这有意义的话)。
    【解决方案5】:

    一旦单个 case 为真,则执行 switch 块中的所有其他以下代码除了其他 case 语句。见php documentation for the switch statement

    switch 语句逐行执行(实际上是逐语句执行)。一开始,没有代码被执行。只有当 case 语句的值与 switch 表达式的值匹配时,PHP 才会开始执行语句。 PHP 继续执行语句,直到 switch 块结束,或者它第一次看到 break 语句。如果你不在一个case语句列表的末尾写一个break语句,PHP会继续执行下一个case的语句。

    所以这里发生的情况如下:

    switch (true) {
        case empty($meta['meta_description']): // MATCH
            $meta['meta_description'] = 'incorrect';  // EXECUTE
        case empty($meta['meta_keywords']): // SKIP
            $meta['meta_keywords'] = 'incorrect'; // EXECUTE
        case empty($meta['meta_title']): // SKIP
            $meta['meta_title'] = 'incorrect'; // EXECUTE
    }
    

    请注意,以下case 语句体完全执行:

    switch(true) {
        case false:
            echo "Not Executed\n";
        case true:
            echo "Executed\n";
        case print("Condition Not Executed\n"):
            echo "Also Executed\n";
    }
    

    这将打印:

    Executed
    Also Executed
    

    【讨论】:

      【解决方案6】:

      您没有任何break 语句。为每个案例添加一个,它会起作用。

      发生的情况是第一个案例 (empty($meta['meta_description'])) 正在评估 true 并且没有任何 break 语句,其余案例的代码也会执行,因此 meta_keywords 设置为不正确meta_title 也是如此。

      鉴于这是switch 语句的工作方式,您可能不想使用switch 语句。您可能正在寻找更像这样的东西:

      $meta = array('meta_title' => 'correct');
      
      if (empty($meta['meta_description']))
          $meta['meta_description'] = 'incorrect';
      if (empty($meta['meta_keywords']))
          $meta['meta_keywords'] = 'incorrect';
      if (empty($meta['meta_title']))
          $meta['meta_title'] = 'incorrect';
      
      print_r($meta);
      

      或者你可以使用循环:

      $meta = array('meta_title' => 'correct');
      
      $properties = array('meta_description', 'meta_keywords', 'meta_title');
      foreach ($properties as $property)
      {
          if (empty($meta[$property]))
              $meta[$property] = 'incorrect';
      }
      
      print_r($meta);
      

      这两个应该产生相同的结果,但如果你有更多的属性,循环会更容易和更短。

      【讨论】:

      • 如果我这样做了,那么我会感兴趣的是一个循环进入等式,然后是一个 if,这不能提高性能吗?
      • 为什么其他情况的代码会触发,如果他们的条件不应该触发你需要休息而不执行其他“腿”的事实是显而易见的,但这不是答案,是吗?如果它不评估其他“腿”,而只是执行所有代码,那看起来像一个错误,不是吗?
      • @JamesLeckenby:循环不是坏事。这正是循环的目的。在这种情况下,使用循环对性能造成的任何影响都绝对可以忽略不计。
      • @Nanne:您应该阅读switch 语句的工作原理。这不仅仅是它在 PHP 中的工作方式,它在大多数(如果不是全部)C 派生语言中都是这样工作的。这通常被称为“失败”。在到达break 语句之前,以下“腿”上的所有代码都将执行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多