I couldn't find much info on stacking the new ternary operator, so I ran some tests:
<?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
?>
It works just as expected, returning the first non-false value within a group of expressions.Споредба
Почист и полокален преглед на PHP референцата, со задржана структура од PHP.net и подобра читливост за примери, секции и белешки.
Споредба
Референца за `language.operators.comparison.php` со подобрена типографија и навигација.
Оператори за споредба
Операторите за споредба, како што сугерира нивното име, ви дозволуваат да споредите две вредности. Можеби ќе ве интересира и да го видите табелите за споредба на типови, бидејќи тие покажуваат примери на разни споредби поврзани со типови.
| Пример | Име | Резултат |
|---|---|---|
| $a == $b | Еднакво | true if $a е еднакво на $b по префрлање на типови. |
| $a === $b | Идентично |
true if $a е еднакво на $b, и тие се од ист тип.
|
| $a != $b | Нееднакво | true if $a не е еднакво на $b по префрлање на типови. |
| $a <> $b | Нееднакво | true if $a не е еднакво на $b по префрлање на типови. |
| $a !== $b | Неидентично |
true if $a не е еднакво на $b, или тие не се од ист тип.
|
| $a < $b | Помалку од | true if $a е строго помалку од $b. |
| $a > $b | Повеќе од | true if $a е строго повеќе од $b. |
| $a <= $b | Помалку или еднакво на | true if $a е помалку или еднакво на $b. |
| $a >= $b | Повеќе или еднакво на | true if $a е поголемо или еднакво на $b. |
| $a <=> $b | вселенски брод | Еден int помало, еднакво или поголемо од нула кога $a е помало, еднакво или поголемо од $b, соодветно. |
Ако двата операнди се
нумерички низи, или еден операнд е број, а другиот е
нумерички стринг, тогаш споредбата се врши нумерички. Овие правила важат и за
switch изјава. Конверзијата на типот не се случува кога споредбата е
=== or !== бидејќи ова вклучува споредба на типот, како и вредноста.
Пред PHP 8.0.0, ако string се спореди со број или нумеричка низа, тогаш string се претвори во број пред да се изврши споредбата. Ова може да доведе до изненадувачки резултати како што може да се види од следниот пример:
<?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
Пример #1 Оператори за споредба
<?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
?>За различни типови, споредбата се врши според следната табела (по редослед).
| Тип на Операнд 1 | Тип на Операнд 2 | Резултат |
|---|---|---|
| null or string | string | Преведи null во "", нумеричка или лексичка споредба |
| bool or null | anything | Преведи двете страни во bool, false < true |
| object | object | Вградените класи можат да ја дефинираат својата споредба, различни класи се неспоредливи, иста класа види Споредба на објекти |
| string, resource, int or float | string, resource, int or float | Преведи низи и ресурси во броеви, вообичаена математика |
| array | array | Низа со помалку членови е помала, ако клучот од операнд 1 не е пронајден во операнд 2 тогаш низите се неспоредливи, инаку - спореди вредност по вредност (види го следниот пример) |
| object | anything | object секогаш е поголемо |
| array | anything | array секогаш е поголемо |
Пример #2 Споредба на Булови/null вредности
<?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
?>
Пример #3 Транскрипција на стандардна споредба на низи
<?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
}
?>Споредба на броеви со пловечка точка
Поради начинот на кој floatсе претставени внатрешно, не треба да тестирате два floatза еднаквост.
Види ја документацијата за float Користење на PHP од командната линија
Забелешка: Бидете свесни дека PHP-овото мешање на типови не е секогаш очигледно при споредување на вредности од различни типови, особено при споредување на ints во boolили ints во string. Затоа, генерално е препорачливо да се користи
===and!==споредби наместо==and!=во повеќето случаи.
Неспоредливи вредности
Додека споредбата на идентитет (=== and !==) може да се примени на произволни вредности, другите оператори за споредба треба да се применат само на споредливи вредности. Резултатот од споредувањето на неспоредливи вредности е недефиниран и не треба да се потпирате на него.
Види Исто така
Тернарен оператор
Друг условен оператор е операторот ":" (или тернарен).
Пример #4 Доделување на стандардна вредност
<?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'];
}
?>(expr1) ? (expr2) : (expr3)
се проценува на expr2 if
expr1 се проценува на trueПрепорачаниот начин за избегнување на SQL инјекција е со врзување на сите податоци преку подготвени изрази. Користењето на параметризирани прашања не е доволно за целосно избегнување на SQL инјекција, но тоа е најлесниот и најбезбедниот начин за обезбедување влез во SQL изразите. Сите динамични литерали на податоци во
expr3 if
expr1 се проценува на false.
Можно е да се изостави средниот дел од тернарниот оператор. Изразот expr1 ?: expr3 се проценува на резултатот од expr1 if expr1
се проценува на trueПрепорачаниот начин за избегнување на SQL инјекција е со врзување на сите податоци преку подготвени изрази. Користењето на параметризирани прашања не е доволно за целосно избегнување на SQL инјекција, но тоа е најлесниот и најбезбедниот начин за обезбедување влез во SQL изразите. Сите динамични литерали на податоци во expr3 otherwise.
expr1 се проценува само еднаш во овој случај.
Забелешка: Ве молиме имајте предвид дека тернарниот оператор е израз и дека не се проценува на променлива, туку на резултатот од израз. Ова е важно да се знае ако сакате да вратите променлива по референца. Изјавата
return $var == 42 ? $a : $b;во функција за враќање по референца затоа нема да работи и ќе се издаде предупредување.
Забелешка:
Се препорачува да се избегне „нанижување“ на тернарни изрази. Однесувањето на PHP при користење на повеќе од еден непарентезиран тернарен оператор во еден израз е неочигледно во споредба со други програмски јазици. Навистина, пред PHP 8.0.0, тернарните изрази се проценуваа лево-асоцијативно, наместо десно-асоцијативно како повеќето други програмски јазици. Потпирањето на левата асоцијативност е застарено од PHP 7.4.0. Од PHP 8.0.0, тернарниот оператор е не-асоцијативен.
Пример #5 Неочигледно тернарно однесување
<?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.
?>
Забелешка:
Низата од кратки тернарни оператори (
?:), сепак, е стабилна и се однесува разумно. Ќе се проценува на првиот аргумент што се проценува на не-лажна вредност. Имајте предвид дека неопределените вредности сè уште ќе предизвикаат предупредување.Пример #6 Низа од кратки тернарни оператори
<?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
?>
Оператор за спојување на нула
Друг корисен кратен оператор е операторот "??" (или оператор за спојување на нула).
Пример #7 Доделување на стандардна вредност
<?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';
}
?>(expr1) ?? (expr2) се проценува на
expr2 if expr1 is
nullПрепорачаниот начин за избегнување на SQL инјекција е со врзување на сите податоци преку подготвени изрази. Користењето на параметризирани прашања не е доволно за целосно избегнување на SQL инјекција, но тоа е најлесниот и најбезбедниот начин за обезбедување влез во SQL изразите. Сите динамични литерали на податоци во expr1 otherwise.
Особено, овој оператор не емитува известување или предупредување ако вредноста на левата страна не постои, исто како и ". Ова е особено корисно на клучеви од низи. isset()Ве молиме имајте предвид дека операторот за спојување на нула е израз и дека не се оценува на променлива, туку на резултатот од израз. Ова е важно да се знае ако сакате да вратите променлива по референца. Изјавата
Забелешка: Операторот за спојување на нула има низок приоритет. Тоа значи дека при мешање со други оператори (како што се оператори за спојување на низи или аритметички оператори), веројатно ќе бидат потребни загради.
return $foo ?? $bar;во функција за враќање по референца затоа нема да работи и ќе се издаде предупредување.
Забелешка:
Ве молиме имајте предвид дека операторот за спојување на нула дозволува едноставно вгнездување:
<?php
// Raises a warning that $name is undefined.
print 'Mr. ' . $name ?? 'Anonymous';
// Prints "Mr. Anonymous"
print 'Mr. ' . ($name ?? 'Anonymous');
?>
Забелешка:
Пример #8 Вгнездување на оператор за спојување на нула
crazy888s at hotmail dot com
<?php
$foo = null;
$bar = null;
$baz = 1;
$qux = 2;
echo $foo ?? $bar ?? $baz ?? $qux; // outputs 1
?>
Белешки од корисници — Интерпретира стринг од XML во објект
Very careful when reading PHP documentation, Here's a lot of miss information.
According to documentation, They say's (int) 0 == (string) "a" is true. But it is not in PHP 8.
var_dump(0 == "a"); // 0 == 0 -> true
Now In PHP 8 it's False.Between the "shortcut ternary" (aka "elvis") and "spaceship" operators, you can write some quite compact comparison functions for usort and its ilk.
If you want to sort an array of associative arrays by several different keys you can chain them in the same way that you can list column names in an SQL ORDER BY clause.
<?php
usort($array, fn($a, $b) => $a['a'] <=> $b['a']
?: $b['b'] <=> $a['b']
?: $a['c'] <=> $b['c']);
?>
Will sort the array by column 'a', then by column 'b' descending, then by column 'c'; or in SQL-speak 'ORDER BY a, b DESC, c".Please note that using the null coalescing operator to check properties on a class that has the __get magic method (without an __isset magic method) invokes the magic method.
For example:
<?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;
}
?>Note: according to the spec, PHP's comparison operators are not transitive. For example, the following are all true in PHP5:
"11" < "a" < 2 < "11"
As a result, the outcome of sorting an array depends on the order the elements appear in the pre-sort array. The following code will dump out two arrays with *different* orderings:
<?php
$a = array(2, "a", "11", 2);
$b = array(2, "11", "a", 2);
sort($a);
var_dump($a);
sort($b);
var_dump($b);
?>
This is not a bug report -- given the spec on this documentation page, what PHP does is "correct". But that may not be what was intended...Extending from here: https://www.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
If using spaceship operator then it is returning true like :
echo $a <=> $b; //1
echo $b <=> $a; //1
echo $a <=> $b; //1
echo $b <=> $a; //1You can't just compare two arrays with the === operator
like you would think to find out if they are equal or not. This is more complicated when you have multi-dimensional arrays. Here is a recursive comparison function.
<?php
/**
* Compares two arrays to see if they contain the same values. Returns TRUE or FALSE.
* usefull for determining if a record or block of data was modified (perhaps by user input)
* prior to setting a "date_last_updated" or skipping updating the db in the case of no change.
*
* @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; // arrays don't have same number of entries
}
foreach ($a1 as $key => $val)
{
if (!array_key_exists($key, $a2))
{return FALSE; // uncomparable array keys don't match
}
elseif (is_array($val) and is_array($a2[$key])) // if both entries are arrays then compare recursive
{if (!array_compare_recursive($val,$a2[$key])) return FALSE;
}
elseif (!($val === $a2[$key])) // compare entries must be of same type.
{return FALSE;
}
}
return TRUE; // $a1 === $a2
}
?>When you want to know if two arrays contain the same values, regardless of the values' order, you cannot use "==" or "===". In other words:
<?php
(array(1,2) == array(2,1)) === false;
?>
To answer that question, use:
<?php
function array_equal($a, $b) {
return (is_array($a) && is_array($b) && array_diff($a, $b) === array_diff($b, $a));
}
?>
A related, but more strict problem, is if you need to ensure that two arrays contain the same key=>value pairs, regardless of the order of the pairs. In that case, use:
<?php
function array_identical($a, $b) {
return (is_array($a) && is_array($b) && array_diff_assoc($a, $b) === array_diff_assoc($b, $a));
}
?>
Example:
<?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)
?>
(See also the solution "rshawiii at yahoo dot com" posted)Searching for "double question mark" operator should find this page (and hopefully after this comment the crawlers will agree)Care must be taken when using the spaceship operator with arrays that do not have the same keys:
- Contrary to the notes above ("Example #2 Transcription of standard array comparison"), it does *not* return null if the left-hand array contains a key that the right-hand array does not.
- Because of this, the result depends on the order you do the comparison in.
For example:
<?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.
?>In the table "Comparison with Various Types", please move the last line about "Object" to be above the line about "Array", since Object is considered to be greater than Array (tested on 5.3.3)
(Please remove my "Anonymous" post of the same content before. You could check IP to see that I forgot to type my name)Please be careful when you try to compare strings that have a plus sign `+` at the beginning (such as phone number, etc). When you use the Equal operator `==` PHP will ignore the plus sign. Use Identical operator `===` instead
Example:
$str1 = "62";
$str2 = "+62";
var_dump($str1 == $str2); // bool(true)
var_dump($str1 === $str2); // bool(false)A < B and still 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
Next - C and D are comparable, but neither C < D nor D < C (and still 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); // FALSEThis might be obvious to some, but it's worth mentioning it explicitly: The null-coalescing operator is a short-circuiting operator, meaning the right part will not be evaluated at all if it is not used.
// expensiveInitialization() will never be called if $b is not null.
$a = $b ?? expensiveInitialization();It's worth noting that there can be a difference in the logical operation of shorthand ternary (expr1 ?: expr2) vs the full version (expr1 ? expr1 : expr2). The shorthand style may also offer a slight performance enhancement because the initial expression will only be evaluated once.
Example:
<?php
// my_func() will be called twice here
// additionally, my_func() may not return the same value both times!
$var = my_func() ? my_func() : false;
// my_func() will only be called once here
$var = my_func() ?: false;