关于类型转换:make switch使用===比较不==比较在PHP中

make switch use === comparison not == comparison In PHP

是否有任何方法使以下代码仍然使用开关并返回b而不是a?谢谢!

1
2
3
4
5
$var = 0;
switch($var) {
    case NULL : return 'a'; break;
    default : return 'b'; break;
}

当然,使用if语句,您可以这样做:

1
2
3
$var = 0;
if($var === NULL) return 'a';
else return 'b';

但对于更复杂的例子,这就变得冗长了。


抱歉,不能在switch语句中使用===比较,因为根据switch()文档:

Note that switch/case does loose comparison.

这意味着你必须想出一个解决办法。从松散的比较表中,可以利用NULL =="0"按类型转换为假的事实:

1
2
3
4
5
6
7
8
9
<?php
$var = 0;
switch((string)$var)
{
    case"" : echo 'a'; break; // This tests for NULL or empty string  
    default : echo 'b'; break; // Everything else, including zero
}
// Output: 'b'
?>

现场演示


switch不同,它只进行所谓的"松散"比较。您可以使用===替换为if/else if块。

  • 开关文件:http://php.net/manual/en/control-structures.switch.php
  • 松散比较:http://php.net/manual/en/types.comparisons.php types.comparisions-loose


我在一个包含数字的字符串的开关中遇到了同样的问题(在一个用于PHP的开关中,"15.2"等于"15.20")。

我解决了在文本前加一个字母比较的问题

1
2
3
4
5
6
7
8
9
$var = '15.20';
switch ('#'.$var) {
    case '#15.2' :
      echo 'wrong';
    break;
    case '#15.20' :
      echo 'right';
    break;
}

假设您正在打开变量并期望整数。为什么不先用is_int($val)检查变量的整数状态呢?


以下是"strict"switch语句中的原始代码:

1
2
3
4
5
6
switch(true) {
    case $var === null:
        return 'a';
    default:
        return 'b';
}

这也可以处理更复杂的switch语句,如下所示:

1
2
3
4
5
6
7
8
9
10
11
switch(true) {
    case $var === null:
        return 'a';
        break;
    case $var === 4:
    case $var === 'foobar':
        return 'b';
    default:
        return 'c';
        break;
}

我只是用

1
2
3
4
5
6
7
8
9
$var === null and $var = -1; // since switch is not type-safe
switch ( $var ) {
    case 0:
        # this tests for zero/empty string/false
       break;
    case -1:
        # this tests for null
       break;
}

如果以//开头的评论被留下(以#开头的评论可能最好被删除),我认为这看起来仍然很可读。


PHP中的switch语句只做松散的比较(==)请参见http://www.php.net/manual/en/control-structures.switch.php

如果需要严格比较,请使用if/else if/else。


不。从手册页面:

Note that switch/case does loose comparison.

如果只有两个条件,请使用与第二个示例类似的if。否则,首先检查NULL并打开其他可能性:

1
2
3
4
5
6
7
8
9
if (is_null($var))
{
  return 'a';
}

switch ($var)
{
    // ...
}

make switch use === comparison not ==
comparison In PHP

不幸的是,switch使用了松散的比较,据我所知,没有办法改变这一点。


如果要同时测试变量的值和类型,则构建一个包含这两个信息的新字符串变量,并将其与不同的方案进行比较(通过串联),如果实现所有可能的类型(根据gettype()文档),则该变量应该适用于您的情况,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
    $var= 9999;
    $valueAndTypeOfVar = (string)$var.' '.gettype($var);
    switch($valueAndTypeOfVar) {
        case"$var boolean" : echo 'a'; break;
        case"$var integer" : echo 'b'; break;
        case"$var double" : echo 'c'; break;
        case"$var string" : echo 'd'; break;
        case"$var array" : echo 'e'; break;
        case"$var object" : echo 'f'; break;
        case"$var resource" : echo 'g'; break;
        case"$var NULL" : echo 'h'; break;
        case"$var unknown type" : echo 'i'; break;
        default: echo 'j'; break;
    }

   // Outputs: 'b'
?>

创建一个像类这样的断言,并在其中放入您想要的任何逻辑;只要"true"方法返回$this(并且没有其他方法可以避免误报)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Haystack
{
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    public function isExactly($n)
    {
        if ($n === $this->value)
            return $this;
    }
}

$var = new Haystack(null);

switch ($var) {
    case $var->isExactly(''):
        echo"the value is an empty string";
        break;

    case $var->isExactly(null):
        echo"the value is null";
        break;
}

或者您可以将开关放在实际类中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Checker
{
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    public function isExactly($n)
    {
        if ($n === $this->value)
            return $this;
    }

    public function contains($n)
    {
        if (strpos($this->value, $n) !== false)
            return $this;
    }

    public static function check($str)
    {
        $var = new self($str);

        switch ($var) {
            case $var->isExactly(''):
                return"'$str' is an empty string";
            case $var->isExactly(null):
                return"the value is null";
            case $var->contains('hello'):
                return"'$str' contains hello";
            default:
                return"'$str' did not meet any of your requirements.";
        }
    }
}

var_dump(Checker::check('hello world'));   # string(28)"'hello world' contains hello"

当然,在这一点上,您可能需要重新评估您要对正在检查的内容执行的操作,并改用真正的验证库。


从您的示例代码推断,我猜您有一些常规案例和一个特殊案例(这里是NULL)。

我能想到的最简单的方法是在切换之前处理这个案例:

1
2
3
4
5
6
7
8
9
10
11
12
if ($value === null) {
    return 'null';
}

switch ($value) {
    case 0:
        return 'zero';
    case 1:
        return 'one';
    case 2:
        return 'two';
}

也许还可以添加一条注释来记住,NULL会意外地与0案件相匹配(反之,0会与NULL案件相匹配)。


最好的方法之一是使用is_null检查空值。

1
2
3
4
5
6
7
8
9
10
11
<?php
echo getValue();
function getValue()
{
    $var = 0;  
    switch(true) {
        case is_null($var) : return 'a'; break;
        default : return 'b'; break;
    }
}
?>


您还可以打开变量类型:

1
2
3
switch (gettype($var)) {
...
}


这是不可能的。

但是,您可以将if语句放入switch中:

1
2
3
4
5
6
7
8
9
10
11
12
13
switch($var) {
    // Loose cases here

    case 0:
        if($var === NULL) {
            return 'a';
        }

        // Fall through

    default:
        return 'b';
}

或者简单地说:

1
2
3
4
5
6
7
8
9
10
switch($var) {
    // Loose cases here

    default:
        if($var === NULL) {
            return 'a';
        }

        return 'b';
}