在 PHP 中使用 = = 比较不 = = 比较

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

$var = 0;
switch($var) {
case NULL : return 'a'; break;
default : return 'b'; break;
}

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

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

但是对于更复杂的示例,这将变得冗长。

20232 次浏览

Sorry, you cannot use a === comparison in a switch statement, since according to the switch() documentation:

Note that switch/case does loose comparison.

This means you'll have to come up with a workaround. From the loose comparisons table, you could make use of the fact that NULL == "0" is false by type casting:

<?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'
?>

Live Demo

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

Unfortunately switch uses loose comparison and as far as I know there's no way to change that.

Nope. From the manual page:

Note that switch/case does loose comparison.

If you only have two conditions, use an if like your second example. Otherwise, check for NULL first and switch on the other possibilities:

if (is_null($var))
{
return 'a';
}


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

This is not possible.

You can, however, put the if statements inside the switch:

switch($var) {
// Loose cases here


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


// Fall through


default:
return 'b';
}

Or simply:

switch($var) {
// Loose cases here


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


return 'b';
}

You can also switch on the type of the variable:

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

Per comment Peter Ajtai reminds that gettype() may be considered unstable and recommends the is_* family of functions:

switch (true) {
case is_string($var):
...
case is_int($var):
...
case is_numeric($var):
...
...
}

Not with switch - it only does so called "loose" comparisons. You can always replace it with a if/else if block, using ===.

Switch statement in php does loose comparisons only (==) see http://www.php.net/manual/en/control-structures.switch.php

Use if/elseif/else if you need strict comparisons.

Presumably you are switching on the variable and expecting integers. Why not simply check the integer status of the variable beforehand using is_int($val) ?

I just use

$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;
}

I think this still looks very readable if the comment starting with // is left behind (and the ones starting with # are probably best deleted).

One of the best way is to check NULL value by using is_null

function getValue()
{
$var = 0;
switch (true) {
case is_null($var) :
return 'a';
default :
return 'b';
}
}


echo getValue();

I had the same problem in a switch with string containing numbers ("15.2" is equal to "15.20" in a switch for php)

I solved the problem adding a letter before the text to compare

$var = '15.20';
switch ('#'.$var) {
case '#15.2' :
echo 'wrong';
break;
case '#15.20' :
echo 'right';
break;
}

Extrapolating from your example code, I guess you have a bunch of regular cases and one special case (here, null).

The simplest I can figure out is to handle this case before the switch:

if ($value === null) {
return 'null';
}


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

Maybe also add a comment to remember null would unexpectedly match the 0 case (also the contrary, 0 would match a null case).

Here is your original code in a "strict" switch statement:

switch(true) {
case $var === null:
return 'a';
default:
return 'b';
}

This can also handle more complex switch statement like this:

switch(true) {
case $var === null:
return 'a';
case $var === 4:
case $var === 'foobar':
return 'b';
default:
return 'c';
}

Create an assertion-like class and put whatever logic you want in it; so long as "true" methods return $this (and nothing else to avoid false-positives.)

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;
}

Or you can put your switch inside the actual class:

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"

Of course that that point you might want to re-evaluate what you want to do with what you're checking and use a real validation library instead.

If you want to test both value and type of your variable, then build a new string variable containing both informations and compare it with your different scenarios (by concatenation) it should work for your case if you implement all possible types (according to gettype() documentation), example :

<?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'
?>

Yes, on PHP 8+ you can do it with match expression1:

echo match (0) {
NULL=> 'a',
default => 'b'
};
#~ b

The PHP documentation explicitly mentions this difference in comparison to switch statement2:

Unlike switch, the comparison is an identity check (===) rather than a weak equality check (==). Match expressions are available as of PHP 8.0.0. (from)


1 See match (PHP 8)

2 See switch (PHP 4, PHP 5, PHP 7, PHP 8)