比较运算符

比较运算符顾名思义,允许你比较两个值。你可能还对查看 类型比较表 感兴趣,因为它们展示了各种类型相关比较的示例。

比较运算符
示例 名称 结果
$a == $b 等于 true 如果 $a 在类型转换后等于 $b
$a === $b 全等 true 如果 $a 等于 $b,并且它们是相同类型。
$a != $b 不等于 true 如果 $a 在类型转换后不等于 $b
$a <> $b 不等于 true 如果 $a 在类型转换后不等于 $b
$a !== $b 不全等 true 如果 $a 不等于 $b,或者它们不是相同类型。
$a < $b 小于 true 如果 $a 严格小于 $b
$a > $b 大于 true 如果 $a 严格大于 $b
$a <= $b 小于或等于 true 如果 $a 小于或等于 $b
$a >= $b 大于或等于 true 如果 $a 大于或等于 $b
$a <=> $b 宇宙飞船 $a 分别小于、等于或大于 $b 时,返回一个小于、等于或大于零的 int

如果两个操作数都是 数字字符串,或者一个操作数是数字,另一个是 数字字符串,那么比较将以数字方式进行。这些规则也适用于 switch 语句。当比较是 ===!== 时,类型转换不会发生,因为这涉及到比较类型和值。

警告

在 PHP 8.0.0 之前,如果将 字符串 与数字或数字字符串进行比较,则 字符串 会在执行比较之前被转换为数字。这会导致令人惊讶的结果,如下例所示

<?php
var_dump
(0 == "a");
var_dump("1" == "01");
var_dump("10" == "1e1");
var_dump(100 == "1e2");

switch (
"a") {
case
0:
echo
"0";
break;
case
"a":
echo
"a";
break;
}
?>

以上示例在 PHP 7 中的输出

bool(true)
bool(true)
bool(true)
bool(true)
0

以上示例在 PHP 8 中的输出

bool(false)
bool(true)
bool(true)
bool(true)
a

<?php
// 整数
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// 浮点数
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// 字符串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1

echo "a" <=> "aa"; // -1
echo "zz" <=> "aa"; // 1

// 数组
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1

// 对象
$a = (object) ["a" => "b"];
$b = (object) ["a" => "b"];
echo
$a <=> $b; // 0

$a = (object) ["a" => "b"];
$b = (object) ["a" => "c"];
echo
$a <=> $b; // -1

$a = (object) ["a" => "c"];
$b = (object) ["a" => "b"];
echo
$a <=> $b; // 1

// 不仅比较值,键也必须匹配
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo
$a <=> $b; // 1

?>

对于各种类型,比较按照以下表格顺序进行。

各种类型之间的比较
操作数 1 的类型 操作数 2 的类型 结果
nullstring string null 转换为 "", 进行数值或词法比较
boolnull 任何类型 将两侧转换为 boolfalse < true
object object 内置类可以定义自己的比较方式,不同类无法比较,相同类请参考 对象比较
stringresourceintfloat stringresourceintfloat 将字符串和资源转换为数字,进行常规数学运算
array array 成员数量较少的数组更小,如果操作数 1 的键在操作数 2 中未找到,则数组无法比较,否则 - 按值逐个比较(参见以下示例)
object 任何类型 object 始终更大
array 任何类型 array 始终更大

示例 #1 布尔/null 比较

<?php
// 布尔和 null 始终作为布尔值进行比较
var_dump(1 == TRUE); // TRUE - 等同于 (bool)1 == TRUE
var_dump(0 == FALSE); // TRUE - 等同于 (bool)0 == FALSE
var_dump(100 < TRUE); // FALSE - 等同于 (bool)100 < TRUE
var_dump(-10 < FALSE);// FALSE - 等同于 (bool)-10 < FALSE
var_dump(min(-100, -10, NULL, 10, 100)); // NULL - (bool)NULL < (bool)-100 为 FALSE < TRUE
?>

示例 #2 标准数组比较的转录

<?php
// 使用标准比较运算符以及 spaceship 运算符时,数组比较的方式如下。
function standard_array_compare($op1, $op2)
{
if (
count($op1) < count($op2)) {
return -
1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return
1; // $op1 > $op2
}
foreach (
$op1 as $key => $val) {
if (!
array_key_exists($key, $op2)) {
return
1;
} elseif (
$val < $op2[$key]) {
return -
1;
} elseif (
$val > $op2[$key]) {
return
1;
}
}
return
0; // $op1 == $op2
}
?>

警告

浮点数的比较

由于 float 的内部表示方式,不应测试两个 float 的相等性。

有关更多信息,请参阅 float 文档。

注意: 请注意,比较不同类型的值时,PHP 的类型强制转换并不总是显而易见的,特别是比较 intboolintstring。因此,在大多数情况下,建议使用 ===!== 比较,而不是 ==!=

无法比较的值

虽然身份比较(===!==)可以应用于任意值,但其他比较运算符只应应用于可比较的值。比较不可比较的值的结果是未定义的,不应依赖于它。

三元运算符

另一个条件运算符是“?:”(或三元)运算符。

示例 #3 分配默认值

<?php
// 示例用法:三元运算符
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

// 以上等同于此 if/else 语句
if (empty($_POST['action'])) {
$action = 'default';
} else {
$action = $_POST['action'];
}
?>
表达式 (expr1) ? (expr2) : (expr3) 如果 expr1 评估为 true,则评估为 expr2,如果 expr1 评估为 false,则评估为 expr3

可以省略三元运算符的中间部分。表达式 expr1 ?: expr3 如果 expr1 评估为 true,则评估为 expr1 的结果,否则评估为 expr3。在这种情况下,expr1 只评估一次。

注意 请注意,三元运算符是一个表达式,它不评估为变量,而评估为表达式的结果。如果您想通过引用返回变量,这一点很重要。因此,在按引用返回的函数中,语句 return $var == 42 ? $a : $b; 将不起作用,并且会发出警告。

注意:

建议避免“堆叠”三元表达式。与其他语言相比,PHP 在同一个表达式中使用多个不带括号的三元运算符时的行为并不明显。事实上,在 PHP 8.0.0 之前,三元表达式是左结合的,而不是像大多数其他编程语言那样右结合的。从 PHP 7.4.0 开始,依赖于左结合已被弃用。从 PHP 8.0.0 开始,三元运算符是非结合的。

示例 #4 不明显的 Ternary 行为

<?php
// 乍一看,以下代码似乎输出 'true'
echo (true ? 'true' : false ? 't' : 'f');

// 但是,在 PHP 8.0.0 之前,上面的代码的实际输出是 't'
// 这是因为三元表达式是左结合的

// 以下是与上面代码相同代码的更明显的版本
echo ((true ? 'true' : false) ? 't' : 'f');

// 在这里,可以看出第一个表达式被评估为 'true',它
// 反过来被评估为 (bool)true,因此返回第二个三元表达式的 true 分支。
?>

注意:

但是,短三元运算符 (?:) 的链接是稳定的,并且表现合理。它将评估为第一个评估为非假值的实参。请注意,未定义的值仍将引发警告。

示例 #5 短三元链接

<?php
echo 0 ?: 1 ?: 2 ?: 3, PHP_EOL; //1
echo 0 ?: 0 ?: 2 ?: 3, PHP_EOL; //2
echo 0 ?: 0 ?: 0 ?: 3, PHP_EOL; //3
?>

空合并运算符

另一个有用的简写运算符是“??”(或空合并)运算符。

示例 #6 分配默认值

<?php
// 示例用法:空合并运算符
$action = $_POST['action'] ?? 'default';

// 以上等同于此 if/else 语句
if (isset($_POST['action'])) {
$action = $_POST['action'];
} else {
$action = 'default';
}
?>
表达式 (expr1) ?? (expr2) 如果 expr1null,则评估为 expr2,否则评估为 expr1

特别是,此运算符不会像 isset() 一样,如果左侧的值不存在,则不会发出通知或警告。这在数组键上特别有用。

注意 请注意,空合并运算符是一个表达式,它不评估为变量,而评估为表达式的结果。如果您想通过引用返回变量,这一点很重要。因此,在按引用返回的函数中,语句 return $foo ?? $bar; 将不起作用,并且会发出警告。

注意:

空合并运算符的优先级很低。这意味着如果与其他运算符(如字符串连接或算术运算符)混合使用,则可能需要括号。

<?php
// 发出警告,$name 未定义。
print 'Mr. ' . $name ?? 'Anonymous';

// 打印 "Mr. Anonymous"
print 'Mr. ' . ($name ?? 'Anonymous');
?>

注意:

请注意,空合并运算符允许简单的嵌套

示例 #7 嵌套空合并运算符

<?php

$foo
= null;
$bar = null;
$baz = 1;
$qux = 2;

echo
$foo ?? $bar ?? $baz ?? $qux; // 输出 1

?>

添加注释

用户贡献的注释 13 条注释

crazy888s at hotmail dot com
14 年前
我在堆叠新的三元运算符方面没有找到太多信息,所以我做了一些测试

<?php
echo 0 ?: 1 ?: 2 ?: 3; //1
echo 1 ?: 0 ?: 3 ?: 2; //1
echo 2 ?: 1 ?: 0 ?: 3; //2
echo 3 ?: 2 ?: 1 ?: 0; //3

echo 0 ?: 1 ?: 2 ?: 3; //1
echo 0 ?: 0 ?: 2 ?: 3; //2
echo 0 ?: 0 ?: 0 ?: 3; //3
?>

它按预期工作,返回一组表达式中第一个非假值。
Sumon Mahmud
4 年前
从这里扩展: https://php.net/manual/en/language.operators.comparison.php#121907

$a = ['a' => 1, 'b' => 2, 'c' => 3, 'e' => 4];
$b = ['a' => 1, 'b' => 2, 'd' => 3, 'e' => 4];

echo $a > $b; // 0
echo $b > $a; // 0
echo $a <$b; // 0
echo $b < $a; // 0

如果使用 spaceship 运算符,则它将返回 true,如下所示

echo $a <=> $b; //1
echo $b <=> $a; //1
echo $a <=> $b; //1
echo $b <=> $a; //1
adam at caucho dot com
18 年前
注意:根据规范,PHP 的比较运算符不具有传递性。例如,以下所有在 PHP5 中都是真的

"11" < "a" < 2 < "11"

因此,对数组排序的结果取决于元素在排序前数组中的出现顺序。以下代码将输出两个具有*不同*顺序的数组

<?php
$a
= array(2, "a", "11", 2);
$b = array(2, "11", "a", 2);
sort($a);
var_dump($a);
sort($b);
var_dump($b);
?>

这不是一个错误报告——鉴于此文档页面上的规范,PHP 的行为是“正确的”。但这可能不是预期的结果……
admin at zeros dot co dot id
2 年前
当您尝试比较开头带有加号 `+` 的字符串(如电话号码等)时,请务必小心。当您使用等号运算符 `==` 时,PHP 会忽略加号。请改用恒等运算符 `===`

示例

$str1 = "62";
$str2 = "+62";

var_dump($str1 == $str2); // bool(true)
var_dump($str1 === $str2); // bool(false)
Tahazzot
3 年前
阅读 PHP 文档时要非常小心,这里有很多错误信息。

根据文档,他们说 (int) 0 == (string) "a" 为真。但在 PHP 8 中并非如此。

var_dump(0 == "a"); // 0 == 0 -> true

现在在 PHP 8 中为假。
rshawiii at yahoo dot com
18 年前
您不能只用 === 运算符比较两个数组
就像您想找出它们是否相等一样。当您有多维数组时,这会更加复杂。这是一个递归比较函数。

<?php
/**
* 比较两个数组,查看它们是否包含相同的值。返回 TRUE 或 FALSE。
* 用于确定记录或数据块是否被修改(可能由用户输入)
* 在设置“date_last_updated”或在没有更改的情况下跳过更新数据库之前。
*
* @param array $a1
* @param array $a2
* @return boolean
*/
function array_compare_recursive($a1, $a2)
{
if (!(
is_array($a1) and (is_array($a2)))) { return FALSE;}

if (!
count($a1) == count($a2))
{
return
FALSE; // 数组没有相同数量的条目
}

foreach (
$a1 as $key => $val)
{
if (!
array_key_exists($key, $a2))
{return
FALSE; // 不可比较的数组键不匹配
}
elseif (
is_array($val) and is_array($a2[$key])) // 如果两个条目都是数组,则递归比较
{if (!array_compare_recursive($val,$a2[$key])) return FALSE;
}
elseif (!(
$val === $a2[$key])) // 比较条目必须是相同类型。
{return FALSE;
}
}
return
TRUE; // $a1 === $a2
}
?>
bishop
17 年前
当您想了解两个数组是否包含相同的值,而不管值的顺序如何,您不能使用“==”或“===”。换句话说

<?php
(array(1,2) == array(2,1)) === false;
?>

要回答这个问题,请使用

<?php
function array_equal($a, $b) {
return (
is_array($a) && is_array($b) && array_diff($a, $b) === array_diff($b, $a));
}
?>

一个相关但更严格的问题是,如果您需要确保两个数组包含相同的键=>值对,而不管对的顺序如何。在这种情况下,请使用

<?php
function array_identical($a, $b) {
return (
is_array($a) && is_array($b) && array_diff_assoc($a, $b) === array_diff_assoc($b, $a));
}
?>

示例
<?php
$a
= array (2, 1);
$b = array (1, 2);
// true === array_equal($a, $b);
// false === array_identical($a, $b);

$a = array ('a' => 2, 'b' => 1);
$b = array ('b' => 1, 'a' => 2);
// true === array_identical($a, $b)
// true === array_equal($a, $b)
?>

(另请参阅“rshawiii at yahoo dot com”发布的解决方案)
Hayley Watson
11 个月前
在“快捷三元运算符”(又名“Elvis”)和“宇宙飞船”运算符之间,您可以为 usort 及其同类编写一些非常紧凑的比较函数。

如果您想按几个不同的键对关联数组数组进行排序,您可以在同一个地方对它们进行链式操作,就像您可以在 SQL ORDER BY 子句中列出列名一样。

<?php
usort
($array, fn($a, $b) => $a['a'] <=> $b['a']
?:
$b['b'] <=> $a['b']
?:
$a['c'] <=> $b['c']);
?>
将按列“a”、然后按列“b”降序、然后按列“c”对数组进行排序;或用 SQL 的说法“ORDER BY a, b DESC, c”。
gfilippakis at sleed dot gr
1 年前
请注意,使用空值合并运算符检查具有 __get 魔术方法(没有 __isset 魔术方法)的类的属性会调用魔术方法。

例如

<?php

class A
{
public function
__get($property)
{
echo
'Called __get for ' . $property . PHP_EOL;
}
}

$a = new A();

echo
'Trying null coalescing operator' . PHP_EOL;
$b = $a->test ?? 5;

echo
'Trying isset()' . PHP_EOL;
if (isset(
$a->test)) {
$b = $a->test;
} else {
$b = 5;
}

?>
niall at maranelda dot org
6 年前
在对没有相同键的数组使用宇宙飞船运算符时,必须谨慎

- 与上面的注释相反(“示例 #2 标准数组比较的转录”),如果左侧数组包含右侧数组没有的键,它*不会*返回 null。
- 因此,结果取决于您进行比较的顺序。

例如

<?php
$a
= ['a' => 1, 'b' => 2, 'c' => 3, 'e' => 4];
$b = ['a' => 1, 'b' => 2, 'd' => 3, 'e' => 4];

var_dump($a <=> $b); // int(1) : $a > $b because $a has the 'c' key and $b doesn't.

var_dump($b <=> $a); // int(1) : $b > $a because $b has the 'd' key and $a doesn't.
?>
Ryan Mott
4 年前
搜索“双问号”运算符应该能找到此页面(希望在此评论之后,爬虫会同意)
Cuong Huy To
13 年前
在“与各种类型比较”表中,请将最后一行关于“对象”的内容移到关于“数组”内容的上面,因为对象被认为大于数组(在 5.3.3 上测试)

(请删除我之前发布的相同内容的“匿名”帖子。您可以检查 IP 以查看我忘记输入我的名字)
Marcin Kuzawiski
9 年前
A < B 且 B < A...

$A = [1 => 1, 2 => 0, 3 => 1];
$B = [1 => 1, 3 => 0, 2 => 1];

var_dump($A < $B); // TRUE
var_dump($B < $A); // TRUE

var_dump($A > $B); // TRUE
var_dump($B > $A); // TRUE

接下来 - C 和 D 可比较,但 C < D 或 D < C 都不成立(并且仍然 C != D)...

$C = [1 => 1, 2 => 1, 3 => 0];
$D = [1 => 1, 3 => 1, 2 => 0];

var_dump($C < $D); // FALSE
var_dump($D < $C); // FALSE

var_dump($C > $D); // FALSE
var_dump($D > $C); // FALSE

var_dump($D == $C); // FALSE
To Top