mirror of
https://github.com/php/doc-en.git
synced 2026-03-23 23:32:18 +01:00
536 lines
15 KiB
XML
536 lines
15 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<sect1 xml:id="language.operators.comparison">
|
|
<title>Comparison Operators</title>
|
|
<titleabbrev>Comparison</titleabbrev>
|
|
<simpara>
|
|
Comparison operators, as their name implies, allow you to compare
|
|
two values. You may also be interested in viewing
|
|
<link linkend="types.comparisons">the type comparison tables</link>,
|
|
as they show examples of various type related comparisons.
|
|
</simpara>
|
|
<table>
|
|
<title>Comparison Operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Name</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>$a == $b</entry>
|
|
<entry>Equal</entry>
|
|
<entry>&true; if <varname>$a</varname> is equal to <varname>$b</varname> after type juggling.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a === $b</entry>
|
|
<entry>Identical</entry>
|
|
<entry>
|
|
&true; if <varname>$a</varname> is equal to <varname>$b</varname>, and they are of the same
|
|
type.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a != $b</entry>
|
|
<entry>Not equal</entry>
|
|
<entry>&true; if <varname>$a</varname> is not equal to <varname>$b</varname> after type juggling.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <> $b</entry>
|
|
<entry>Not equal</entry>
|
|
<entry>&true; if <varname>$a</varname> is not equal to <varname>$b</varname> after type juggling.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a !== $b</entry>
|
|
<entry>Not identical</entry>
|
|
<entry>
|
|
&true; if <varname>$a</varname> is not equal to <varname>$b</varname>, or they are not of the same
|
|
type.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a < $b</entry>
|
|
<entry>Less than</entry>
|
|
<entry>&true; if <varname>$a</varname> is strictly less than <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a > $b</entry>
|
|
<entry>Greater than</entry>
|
|
<entry>&true; if <varname>$a</varname> is strictly greater than <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <= $b</entry>
|
|
<entry>Less than or equal to</entry>
|
|
<entry>&true; if <varname>$a</varname> is less than or equal to <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a >= $b</entry>
|
|
<entry>Greater than or equal to</entry>
|
|
<entry>&true; if <varname>$a</varname> is greater than or equal to <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <=> $b</entry>
|
|
<entry>Spaceship</entry>
|
|
<entry>
|
|
An <type>int</type> less than, equal to, or greater than zero when
|
|
<varname>$a</varname> is less than, equal to, or greater than
|
|
<varname>$b</varname>, respectively.
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<para>
|
|
If both operands are
|
|
<link linkend="language.types.numeric-strings">numeric strings</link>,
|
|
or one operand is a number and the other one is a
|
|
<link linkend="language.types.numeric-strings">numeric string</link>,
|
|
then the comparison is done numerically.
|
|
These rules also apply to the
|
|
<link linkend="control-structures.switch">switch</link> statement.
|
|
The type conversion does not take place when the comparison is
|
|
<literal>===</literal> or <literal>!==</literal> as this involves
|
|
comparing the type as well as the value.
|
|
</para>
|
|
|
|
<warning>
|
|
<para>
|
|
Prior to PHP 8.0.0, if a <type>string</type> is compared to a number
|
|
or a numeric string then the <type>string</type> was converted to a
|
|
number before performing the comparison. This can lead to surprising
|
|
results as can be seen with the following example:
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?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;
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs.7;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
bool(true)
|
|
bool(true)
|
|
bool(true)
|
|
0
|
|
]]>
|
|
</screen>
|
|
&example.outputs.8;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(false)
|
|
bool(true)
|
|
bool(true)
|
|
bool(true)
|
|
a
|
|
]]>
|
|
</screen>
|
|
</informalexample>
|
|
</para>
|
|
</warning>
|
|
|
|
<para>
|
|
<example>
|
|
<title>Comparison Operators</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Integers
|
|
echo 1 <=> 1, ' '; // 0
|
|
echo 1 <=> 2, ' '; // -1
|
|
echo 2 <=> 1, ' '; // 1
|
|
|
|
// Floats
|
|
echo 1.5 <=> 1.5, ' '; // 0
|
|
echo 1.5 <=> 2.5, ' '; // -1
|
|
echo 2.5 <=> 1.5, ' '; // 1
|
|
|
|
// Strings
|
|
echo "a" <=> "a", ' '; // 0
|
|
echo "a" <=> "b", ' '; // -1
|
|
echo "b" <=> "a", ' '; // 1
|
|
|
|
echo "a" <=> "aa", ' '; // -1
|
|
echo "zz" <=> "aa", ' '; // 1
|
|
|
|
// Arrays
|
|
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
|
|
|
|
// Objects
|
|
$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
|
|
|
|
// not only values are compared; keys must match
|
|
$a = (object) ["a" => "b"];
|
|
$b = (object) ["b" => "b"];
|
|
echo $a <=> $b, ' '; // 1
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
|
|
<para>
|
|
For various types, comparison is done according to the following
|
|
table (in order).
|
|
</para>
|
|
<table xml:id="language.operators.comparison.types">
|
|
<title>Comparison with Various Types</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Type of Operand 1</entry>
|
|
<entry>Type of Operand 2</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><type>null</type> or <type>string</type></entry>
|
|
<entry><type>string</type></entry>
|
|
<entry>Convert &null; to "", numerical or lexical comparison</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>bool</type> or <type>null</type></entry>
|
|
<entry>anything</entry>
|
|
<entry>Convert both sides to <type>bool</type>, &false; < &true;</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>object</type></entry>
|
|
<entry><type>object</type></entry>
|
|
<entry>Built-in classes can define its own comparison, different classes
|
|
are incomparable, same class see <link
|
|
linkend="language.oop5.object-comparison">Object Comparison</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>string</type>, <type>resource</type>, <type>int</type> or <type>float</type></entry>
|
|
<entry><type>string</type>, <type>resource</type>, <type>int</type> or <type>float</type></entry>
|
|
<entry>Translate strings and resources to numbers, usual math</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>array</type></entry>
|
|
<entry><type>array</type></entry>
|
|
<entry>Array with fewer members is smaller, if key from operand 1 is not
|
|
found in operand 2 then arrays are incomparable, otherwise - compare
|
|
value by value (see following example)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>object</type></entry>
|
|
<entry>anything</entry>
|
|
<entry><type>object</type> is always greater</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>array</type></entry>
|
|
<entry>anything</entry>
|
|
<entry><type>array</type> is always greater</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>
|
|
<example>
|
|
<title>Boolean/null comparison</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Bool and null are compared as bool always
|
|
var_dump(1 == TRUE); // TRUE - same as (bool) 1 == TRUE
|
|
var_dump(0 == FALSE); // TRUE - same as (bool) 0 == FALSE
|
|
var_dump(100 < TRUE); // FALSE - same as (bool) 100 < TRUE
|
|
var_dump(-10 < FALSE);// FALSE - same as (bool) -10 < FALSE
|
|
var_dump(min(-100, -10, NULL, 10, 100)); // NULL - (bool) NULL < (bool) -100 is FALSE < TRUE
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
|
|
<para>
|
|
<example>
|
|
<title>Transcription of standard array comparison</title>
|
|
<programlisting role="php" annotations="non-interactive">
|
|
<![CDATA[
|
|
<?php
|
|
// Arrays are compared like this with standard comparison operators as well as the spaceship operator.
|
|
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
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
|
|
<warning>
|
|
<title>Comparison of floating point numbers</title>
|
|
|
|
<para>
|
|
Because of the way <type>float</type>s are represented internally, you
|
|
should not test two <type>float</type>s for equality.
|
|
</para>
|
|
|
|
<para>
|
|
See the documentation for <type>float</type> for more information.
|
|
</para>
|
|
</warning>
|
|
|
|
<note>
|
|
<simpara>
|
|
Be aware that PHP's type juggling is not always obvious when comparing values of different types,
|
|
particularly comparing &integer;s to &boolean;s or &integer;s to &string;s. It is therefore generally
|
|
advisable to use <literal>===</literal> and <literal>!==</literal> comparisons rather than
|
|
<literal>==</literal> and <literal>!=</literal> in most cases.
|
|
</simpara>
|
|
</note>
|
|
|
|
<sect2 xml:id="language.operators.comparison.incomparable">
|
|
<title>Incomparable Values</title>
|
|
<simpara>
|
|
While identity comparison (<literal>===</literal> and <literal>!==</literal>)
|
|
can be applied to arbitrary values, the other comparison operators should only be
|
|
applied to comparable values. The result of comparing incomparable values is
|
|
undefined, and should not be relied upon.
|
|
</simpara>
|
|
</sect2>
|
|
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><function>strcasecmp</function></member>
|
|
<member><function>strcmp</function></member>
|
|
<member><link linkend="language.operators.array">Array operators</link></member>
|
|
<member><link linkend="language.types">Types</link></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.operators.comparison.ternary">
|
|
<title>Ternary Operator</title>
|
|
<para>
|
|
Another conditional operator is the "?:" (or ternary) operator.
|
|
<example>
|
|
<title>Assigning a default value</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Example usage for: Ternary Operator
|
|
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
|
|
|
|
// The above is identical to this if/else statement
|
|
if (empty($_POST['action'])) {
|
|
$action = 'default';
|
|
} else {
|
|
$action = $_POST['action'];
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
The expression <literal>(expr1) ? (expr2) : (expr3)</literal>
|
|
evaluates to <replaceable>expr2</replaceable> if
|
|
<replaceable>expr1</replaceable> evaluates to &true;, and
|
|
<replaceable>expr3</replaceable> if
|
|
<replaceable>expr1</replaceable> evaluates to &false;.
|
|
</para>
|
|
<para>
|
|
It is possible to leave out the middle part of the ternary operator.
|
|
Expression <literal>expr1 ?: expr3</literal> evaluates to
|
|
the result of <replaceable>expr1</replaceable> if <replaceable>expr1</replaceable>
|
|
evaluates to &true;, and <replaceable>expr3</replaceable> otherwise.
|
|
<replaceable>expr1</replaceable> is only evaluated once in this case.
|
|
</para>
|
|
<note>
|
|
<simpara>
|
|
Please note that the ternary operator is an expression, and that it
|
|
doesn't evaluate to a variable, but to the result of an expression. This
|
|
is important to know if you want to return a variable by reference.
|
|
The statement <literal>return $var == 42 ? $a : $b;</literal> in a
|
|
return-by-reference function will therefore not work and a warning is
|
|
issued.
|
|
</simpara>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
It is recommended to avoid "stacking" ternary expressions.
|
|
PHP's behaviour when using more than one unparenthesized ternary operator within a single
|
|
expression is non-obvious compared to other languages.
|
|
Indeed prior to PHP 8.0.0, ternary expressions were evaluated left-associative,
|
|
instead of right-associative like most other programming languages.
|
|
Relying on left-associativity is deprecated as of PHP 7.4.0.
|
|
As of PHP 8.0.0, the ternary operator is non-associative.
|
|
<example>
|
|
<title>Non-obvious Ternary Behaviour</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// on first glance, the following appears to output 'true'
|
|
echo (true ? 'true' : false ? 't' : 'f');
|
|
|
|
// however, the actual output of the above is 't' prior to PHP 8.0.0
|
|
// this is because ternary expressions are left-associative
|
|
|
|
// the following is a more obvious version of the same code as above
|
|
echo ((true ? 'true' : false) ? 't' : 'f');
|
|
|
|
// here, one can see that the first expression is evaluated to 'true', which
|
|
// in turn evaluates to (bool) true, thus returning the true branch of the
|
|
// second ternary expression.
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
Chaining of short-ternaries (<literal>?:</literal>), however, is stable and behaves reasonably.
|
|
It will evaluate to the first argument that evaluates to a non-falsy value. Note that undefined
|
|
values will still raise a warning.
|
|
<example>
|
|
<title>Short-ternary chaining</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?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
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</note>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.operators.comparison.coalesce">
|
|
<title>Null Coalescing Operator</title>
|
|
<para>
|
|
Another useful shorthand operator is the "??" (or null coalescing) operator.
|
|
<example>
|
|
<title>Assigning a default value</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Example usage for: Null Coalesce Operator
|
|
$action = $_POST['action'] ?? 'default';
|
|
|
|
// The above is identical to this if/else statement
|
|
if (isset($_POST['action'])) {
|
|
$action = $_POST['action'];
|
|
} else {
|
|
$action = 'default';
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
The expression <literal>(expr1) ?? (expr2)</literal> evaluates to
|
|
<replaceable>expr2</replaceable> if <replaceable>expr1</replaceable> is
|
|
&null;, and <replaceable>expr1</replaceable> otherwise.
|
|
</para>
|
|
<para>
|
|
In particular, this operator does not emit a notice or warning if the left-hand side
|
|
value does not exist, just like <function>isset</function>. This is especially
|
|
useful on array keys.
|
|
</para>
|
|
<note>
|
|
<simpara>
|
|
Please note that the null coalescing operator is an expression, and that it
|
|
doesn't evaluate to a variable, but to the result of an expression. This
|
|
is important to know if you want to return a variable by reference.
|
|
The statement <literal>return $foo ?? $bar;</literal> in a
|
|
return-by-reference function will therefore not work and a warning is
|
|
issued.
|
|
</simpara>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
The null coalescing operator has low precedence. That means if mixing it
|
|
with other operators (such as string concatenation or arithmetic operators)
|
|
parentheses will likely be required.
|
|
</para>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Raises a warning that $name is undefined.
|
|
print 'Mr. ' . $name ?? 'Anonymous';
|
|
|
|
// Prints "Mr. Anonymous"
|
|
print 'Mr. ' . ($name ?? 'Anonymous');
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
Please note that the null coalescing operator allows for simple nesting:
|
|
<example>
|
|
<title>Nesting null coalescing operator</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
$foo = null;
|
|
$bar = null;
|
|
$baz = 1;
|
|
$qux = 2;
|
|
|
|
echo $foo ?? $bar ?? $baz ?? $qux; // outputs 1
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</note>
|
|
</sect2>
|
|
</sect1>
|