How does <=> in php 7 responsed in situations that check bool values? - php

Looking into php 7 on the way, but <=> confuses me.
Most of the time I use conditional operators, they are used in boolean situations (which <=> almost is, but not quite, being able to return -1 as well). (If X <=> Y). So I'm not sure what will happen in the following cases...
if ($x <=> $y) {
// Do all the 1 things
} else {
// Do all the 2 things
}
What can I expect if it's preceded by...
$x = 0; $y = 1;
or
$x = "Carrot"; $y = "Carrot Juice";
or
$x = "Carrot Juice"; $y = "Carrot";
or
$x = array(carrot, juice); $y = "carrot juice";
There's definitely enough cases about this that it's confusing me as to what it'll do.

The spaceship operator (and other PHP 7 additions) is explained in plain language here:
https://blog.engineyard.com/2015/what-to-expect-php-7
It's mostly useful in the comparison function supplied to functions like usort.
// Pre PHP 7
function order_func($a, $b) {
return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
}
// Post PHP 7
function order_func($a, $b) {
return $a <=> $b;
}
It's not very useful in if, because if only checks whether the value is truthy or falsey, the different truthy values representing the ordering are not distinguished. If you do use it in a boolean context, it will be considered true when the values are different (because 1 and -1 are bother truthy), false when they're equal (because 0 is falsey). This is similar to trying to use strcmp() and stricmp() in a boolean context, which is why you often see
if (stricmp($x, $y) == 0)
The rules for using arrays with comparison operators is given here (scroll down to the table labeled Comparison with Various Types). When comparing an array with another array, the rule is:
Array with fewer members is smaller, if key from operand 1 is not found in operand 2 then arrays are uncomparable, otherwise - compare value by value
When comparing an array with another type, the array is always greater. So array('carrot', 'juice') <=> 'carrot juice' will be 1.

Why not just try it out for yourself and play around with that new spaceship you got?
Demo
Also if you are wondering how the comparison of the spaceship operator works, see: http://php.net/manual/en/types.comparisons.php
But now if we want to go into a bit more detail about your test data:
First case:
//Test data
$x = 0;
$y = 1;
//operator
0 <=> 1 //0 is smaller than 1, so result: -1
//-1 evaluates to TRUE in the if statement
Second case:
//Test data
$x = "Carrot";
$y = "Carrot Juice";
//operator
"Carrot" <=> "Carrot Juice" //"Carrot" is smaller than "Carrot Juice", so result: -1
//-1 evaluates to TRUE in the if statement
Third case:
//Test data
$x = "Carrot Juice";
$y = "Carrot";
//operator
"Carrot Juice" <=> "Carrot" //"Carrot Juice" is bigger than "Carrot", so result: 1
//1 evaluates to TRUE in the if statement
Fourth case:
//Test data
$x = array("carrot", "juice");
$y = "carrot juice";
//operator
array("carrot", "juice") <=> "carrot juice" //array("carrot", "juice") is bigger than "carrot juice", so result: 1
//1 evaluates to TRUE in the if statement

Introduction
The spaceship operator <=> is a non-associative binary operator with the same precedence as equality operators (==, !=, ===, !==).
The purpost of this operator, is to allow for simpler three-way comparison between left-hand and right-hand operands.
Possible outcomes
The operator can produce any of the following results :
0 : when both operands are equal
-1 : when the left-hand operand is less than the right-hand operand
1 : when the left-hand operand is greater than the right-hand operand.
So, that means :
1 <=> 1; // output : 0
1 <=> 2; // output : -1
2 <=> 1; // output : 1
Practical application
A good practical application of using this operator would be in comparison type callbacks that are expected to return a zero, negative, or positive integer based on a three-way comparison between two values. The comparison function passed to usort is one such example.
Before PHP 7, you would write this :
$arr = [4,2,1,3];
usort($arr, function ($a, $b) {
if ($a < $b) {
return -1;
} elseif ($a > $b) {
return 1;
} else {
return 0;
}
});
Since PHP 7, you can write this :
$arr = [4,2,1,3];
usort($arr, function ($a, $b) {
return $a <=> $b;
});

Related

sort array by length and then alphabetically

I'm trying to make a way to sort words first by length, then alphabetically.
// from
$array = ["dog", "cat", "mouse", "elephant", "apple"];
// to
$array = ["cat", "dog", "apple", "mouse", "elephant"];
I've seen this answer, but it's in Java, and this answer, but it only deals with the sorting by length. I've tried sorting by length, using the code provided in the answer, and then sorting alphabetically, but then it sorts only alphabetically.
How can I sort it first by length, and then alphabetically?
You can put both of the conditions into a usort comparison function.
usort($array, function($a, $b) {
return strlen($a) - strlen($b) ?: strcmp($a, $b);
});
The general strategy for sorting by multiple conditions is to write comparison expressions for each of the conditions that returns the appropriate return type of the comparison function (an integer, positive, negative, or zero depending on the result of the comparison), and evaluate them in order of your desired sort order, e.g. first length, then alphabetical.
If an expression evaluates to zero, then the two items are equal in terms of that comparison, and the next expression should be evaluated. If not, then the value of that expression can be returned as the value of the comparison function.
The other answer here appears to be implying that this comparison function does not return an integer greater than, less than, or equal to zero. It does.
Note: I didn`t post my answer early,because #Don't Panic faster then me. However,I want to add some explanation to his answer ( hope, it will be useful for more understanding).
usort($array, function($a, $b) {
return strlen($a) - strlen($b) ?: strcmp($a, $b);
});
Ok. Function usort waits from custom comparison function next (from docs):
The comparison function must return an integer less than, equal to, or
greater than zero if the first argument is considered to be
respectively less than, equal to, or greater than the second.
Ok, rewrite #Don't Panic code to this view (accoding the condition above):
usort($array, function($a, $b) {
// SORT_ORDER_CONDITION_#1
// equals -> going to next by order sort-condition
// in our case "sorting alphabetically"
if (strlen($a) == strlen($b)){
// SORT_ORDER_CONDITION_#2
if (strcmp($a,$b)==0) // equals - last sort-condition? Return 0 ( in our case - yes)
return 0; //
return (strcmp($a,$b)) ? -1 : 1;
}else{
return (strlen($a) < strlen ($b) ) ? - 1 : 1;
}
});
"Common sort strategy" (abstract) with multi sort-conditions in order like (CON_1,CON_2... CON_N) :
usort($array, function(ITEM_1, ITEM_2) {
// SORT_ORDER_CONDITION_#1
if (COMPARING_1_EQUALS){
// SORT_ORDER_CONDITION_#2
if (COMPARING_2_EQUALS){ // If last con - return 0, else - going "deeper" ( to next in order)
//...
// SORT_ORDER_CONDITION_#N
if (COMPARING_N_EQUALS) // last -> equals -> return 0;
return 0;
return ( COMPARING_N_NOT_EQUALS) ? -1 : 1;
//...
}
return ( COMPARING_2_NOT_EQUALS) ? -1 : 1;
}else{
return ( COMPARING_1_NOT_EQUALS ) ? - 1 : 1;
}
});
In practise (from my exp), it's sorting unordered multidimensional-array by several conditions. You can use usort like above.
This is not as short as other methods, but I would argue that it's clearer, and can be easily extended to cover other use cases:
$f = function ($s1, $s2) {
$n = strlen($s1) <=> strlen($s2);
if ($n != 0) {
return $n;
}
return $s1 <=> $s2;
};
usort($array, $f);

Spaceship operator confusion in PHP7 (return -1)

I am pretty new to PHP7 and so far it seems great and powerful. I have been using PHP5.6 so I started understanding the usage of spaceship operator <=>. But somehow I couldn't get the logic that statement returns -1. I know the point of returning to 0 or 1 which are false or true. Can anyone clarify the usage of return -1?
Function normal_sort($a, $b) : int
{
if( $a == $b )
return 0;
if( $a < $b )
return -1;
return 1;
}
function space_sort($a, $b) : int
{
return $a <=> $b;
}
$normalArray = [1,34,56,67,98,45];
//Sort the array in asc
usort($normalArray, 'normal_sort');
foreach($normalArray as $k => $v)
{
echo $k.' => '.$v.'<br>';
}
$spaceArray = [1,34,56,67,98,45];
//Sort it by spaceship operator
usort($spaceArray, 'space_sort');
foreach($spaceArray as $key => $value)
{
echo $key.' => '.$value.'<br>';
}
You have three possibilities when comparing the two values that are passed to a comparison function: $a < $b, $a == $b, or $a > $b. So you need three distinct return values and PHP has chosen the integers: -1, 0, and 1. I guess it could just as easily be strings lesser, equal and greater or integers 5, 7 and 9 or any combination, but it's not.
From the manual usort()
The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
$a < $b return -1
$a == $b return 0
$a > $b return 1
This is NOT how types work in PHP, but you can think of it like this: is $a > $b? where -1 means false, 1 means true and 0 means neither (equal).

How exactly php spaceship operator compare strings, arrays and objects

I am wondering how the php spaceship operator compares strings, objects and arrays. For example, the below code.
echo "Its Me at SO" <=> "Its Me at SO";
will return 0, as i know all characters are same, count is same. But if i have a code like below:
echo "Its me at SO" <=> "its Me at so";
It will return 1, means that left side is greater than right side, but how? Is it comparing the ASCII values?
Now lets come to arrays. The below code will return 0, as both arrays are equal by count, values and values at each index.
echo [1,2,3] <=> [1,2,3];
But the below code returns -1
echo [1,2,3] <=> [3,2,1];
And i dont understand why? How this operator compares the arrays and how it calculates that the array on left is smaller than the array on right?
And the same goes for the objects.
Can anybody give a detailed answer that how it works with strings, arrays and objects?
Thank you
"Comparisons are performed according to PHP's usual type comparison rules (http://php.net/manual/en/types.comparisons.php)".
1) Yes, it uses the ASCII values
2) If the arrays are different lengths, the Array with fewer values is smaller.
Otherwise it compares the arrays key by key, giving "earlier" values priority. For example comparing $arr1[0] to $arr2[0] first. If $arr1 has a key that doesn't exist in $arr2, the arrays aren't comparable (eg if we're using non-numeric arrays).
// Arrays are compared like this with standard comparison operators
// $arr1 and $arr2 are arrays
function standard_array_compare($arr1, $arr2)
{
// If either array has more values, that array is considered "larger"
if (count($arr1) < count($arr2)) {
return -1; // $arr1 < $arr2
} elseif (count($arr1) > count($arr2)) {
return 1; // $arr1 > $arr2
}
//Otherwise compare the array values directly
foreach ($arr1 as $key => $val) {
if (!array_key_exists($key, $arr2)) {
return null; // uncomparable, these arrays do not have the same keys
} elseif ($val < $arr2[$key]) {
return -1; // $arr1 < $arr2
} elseif ($val > $arr2[$key]) {
return 1; // $arr1 > $arr2
}
}
return 0; // $arr1 == $arr2
}
Note, the above is not PHP's actual code, just an approximate representation of the logic used.
Essentially, then, it treats an array in a similar way to comparing a big-endian number. It compares $arr1[0] to $arr2[0]. If they are the different it returns -1 or 1 depending which is larger. If they are the same it moves on to $arr1[1] and $arr2[1]. If all values are the same it returns 0 (arrays are equal)
While not exactly the same, it might be simpler to consider [1,2,3] <=> [3,2,1] as basically equivalent to 123 <=> 321...
According to the new features documentation
Comparisons are performed according to PHP's usual type comparison rules.
<?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
Spaceship Arrays php8
<?php
echo [] <=> []; // result is 0
echo [1, 2, 3] <=> [1, 2, 3]; // result is 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1
echo [1,2,3,1] <=> [1,2,4];//1 //thats mean index first piority,1st array index number getter then 2nd array so its positive answer 1
echo [1,2,4] <=> [1,2,3,1]//-1

What is <=> (the 'Spaceship' Operator) in PHP 7? [duplicate]

This question already has answers here:
Reference Guide: What does this symbol mean in PHP? (PHP Syntax)
(24 answers)
Closed 7 years ago.
The community reviewed whether to reopen this question last month and left it closed:
Original close reason(s) were not resolved
PHP 7 introduced the Spaceship (<=>) operator. What is it and how does it work?
The <=> ("Spaceship") operator will offer combined comparison in that it will :
Return 0 if values on either side are equal
Return 1 if the value on the left is greater
Return -1 if the value on the right is greater
The rules used by the combined comparison operator are the same as the currently used comparison operators by PHP viz. <, <=, ==, >= and >. Those who are from Perl or Ruby programming background may already be familiar with this new operator proposed for PHP7.
//Comparing Integers
echo 1 <=> 1; //output 0
echo 3 <=> 4; //output -1
echo 4 <=> 3; //output 1
//String Comparison
echo "x" <=> "x"; //output 0
echo "x" <=> "y"; //output -1
echo "y" <=> "x"; //output 1
According to the RFC that introduced the operator, $a <=> $b evaluates to:
0 if $a == $b
-1 if $a < $b
1 if $a > $b
which seems to be the case in practice in every scenario I've tried, although strictly the official docs only offer the slightly weaker guarantee that $a <=> $b will return
an integer less than, equal to, or greater than zero when $a is respectively less than, equal to, or greater than $b
Regardless, why would you want such an operator? Again, the RFC addresses this - it's pretty much entirely to make it more convenient to write comparison functions for usort (and the similar uasort and uksort).
usort takes an array to sort as its first argument, and a user-defined comparison function as its second argument. It uses that comparison function to determine which of a pair of elements from the array is greater. The comparison function needs to return:
an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
The spaceship operator makes this succinct and convenient:
$things = [
[
'foo' => 5.5,
'bar' => 'abc'
],
[
'foo' => 7.7,
'bar' => 'xyz'
],
[
'foo' => 2.2,
'bar' => 'efg'
]
];
// Sort $things by 'foo' property, ascending
usort($things, function ($a, $b) {
return $a['foo'] <=> $b['foo'];
});
// Sort $things by 'bar' property, descending
usort($things, function ($a, $b) {
return $b['bar'] <=> $a['bar'];
});
More examples of comparison functions written using the spaceship operator can be found in the Usefulness section of the RFC.
Its a new operator for combined comparison. Similar to strcmp() or version_compare() in behavior, but it can be used on all generic PHP values with the same semantics as <, <=, ==, >=, >. It returns 0 if both operands are equal, 1 if the left is greater, and -1 if the right is greater. It uses exactly the same comparison rules as used by our existing comparison operators: <, <=, ==, >= and >.
click here to know more

Operator precedence issue in Perl and PHP

PHP:
$a = 2;
$b = 3;
if($b=1 && $a=5)
{
$a++;
$b++;
}
echo $a.'-'.$b;
$a = 2;
$b = 3;
if($a=5 and $b=1)
{
$a++;
$b++;
}
echo $a.'-'.$b;
Output 6-16-2.I don't understand the 1 here.
Perl :
$a = 2;
$b = 3;
if($b=1 && $a=5)
{
$a++;
$b++;
}
print $a.'-'.$b;
$a = 2;
$b = 3;
if($a=5 and $b=1)
{
$a++;
$b++;
}
print $a.'-'.$b;
Output 6-66-2, I don't understand the second 6 here.
Anyone knows the reason?
Actually I know && has higher precedence than and,but I still has the doubt when knowing this before hand.
UPDATE
Now I understand the PHP one,what about the Perl one?
Regarding Perl:
Unlike PHP (but like Python, JavaScript, etc.) the boolean operators don't return a boolean value but the value that made the expression true (or the last value) determines the final result of the expression† (source).
$b=1 && $a=5
is evaluated as
$b = (1 && $a=5) // same as in PHP
which is the same as $b = (1 && 5) (assignment "returns" the assigned value) and assigns 5 to $b.
The bottom line is: The operator precedence is the same in Perl and PHP (at least in this case), but they differ in what value is returned by the boolean operators.
FWIW, PHP's operator precedence can be found here.
What's more interesting (at least this was new to me) is that PHP does not perform type conversion for the increment/decrement operators.
So if $b is true, then $b++ leaves the value as true, while e.g. $b += 1 assigns 2 to $b.
†: What I mean with this is that it returns the first (leftmost) value which
evaluates to false in case of &&
evaluates to true in case of ||
or the last value of the expression.
First example
$a = 2;
$b = 3;
if($b=1 && $a=5) // means $b = (1 && $a=5)
{
var_dump($b); //bool(true) because of &&
$a++;
$b++; //bool(true)++ ==true, ok
}
echo $a.'-'.$b;
hope you will not use those codes in production)
I'm noob in perl but i can suggest a&&b returns a or b (last of them if all of them converted to bool), not boolean, then $b = (1 && $a=5) returns $b=5 (is 5)
here's the issue: 1 && 5 returns 5 in perl. you get the result you expect if you code the conditional as if(($b=1) && ($a=5))
For Perl, fig. 2: and has a very low priority in perl, it's not a synonym of &&'s. Therefore the sample is executed as (($a = 5) and ($b = 1)) which sets $a and $b to 5 and 1 respectively and returns a value of the last argument (i.e. 1).
After ++'s you get 6-2.
refer to http://sillythingsthatmatter.in/PHP/operators.php for good examples

Categories