运算符< =>比较对象? [英] How operator <=> compare the objects?
问题描述
在 RFC 中给出以下示例:
// only values are compared
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; // 0
但是当我执行它时,我得到1作为输出:
But when I execute it I get 1 as output back:
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; //1
我现在不了解< =>如何比较对象?在RFC中,它表示仅按值进行比较.
I don't understood now how <=> compares the objects? In the RFC it says that it is compared only by values.
P.S.我在流浪汉下使用PHP 7.0.4-6 + deb.sury.org〜trusty + 1(cli)(NTS)
UPD:
php > echo (object)["b"=>"b"] <=> (object)["b"=>"b"];
0
php > echo (object)["b"=>"b"] <=> (object)["a"=>"b"];
1
php > echo (object)["a"=>"b"] <=> (object)["b"=>"b"];
1
推荐答案
阅读 RFC 我们发现它与自己矛盾:
When reading the RFC we find out that it contradicts itself:
添加一个新的运算符(expr)< =>(expr),如果两个操作数相等,则返回0;如果左边较大,则返回1;如果右边较大,则返回-1.它使用与我们现有比较运算符完全相同的比较规则:<,< =,==,> =和>. (有关详细信息,请参见手册)
Add a new operator (expr) <=> (expr), 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 >. (See the manual for details)
注意::请参见==
,这意味着飞船操作员会进行粗略的比较.
Note: See the ==
, this means the spaceship operator does a loosely comparison.
然后是示例:
// only values are compared
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a $b; // 0
太空船操作员只是操作员<
,==
和>
的组合.并根据评估结果给出各自的返回值:
The spaceship operator is just a combination of the operators <
, ==
and >
. And it gives respective return values depending on what it evaluates to:
operator(s): < = >
return value: -1 0 1
现在数组和类型.要了解<=>
PHP飞船运算符的作用,我们需要查看并了解<
,==
和>
对于数组和对象的工作方式.
Now arrays and objects are a bit more complex types. To understand what the <=>
PHP spaceship operator does, we need to look and understand how <
, ==
and >
work for arrays and objects.
因此,让我们看一下每种类型的比较运算符<
,>
,==
.首先,我们将查看<
和>
,然后我们还将查看==
.
So let's look at the comparison operators <
, >
, ==
for each type. First we will look at <
and >
and then after that we also look at ==
.
Now as for arrays <
and >
are documented here:
┌───────────┬───────────┬──────────────────────────────────────────────────┐
│ type of │ type of │ │
│ Operand 1 │ Operand 2 │ Result │
├───────────┼───────────┼──────────────────────────────────────────────────┤
│ array │ array │ 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 │
└───────────┴───────────┴──────────────────────────────────────────────────┘
这也可以由代码:
示例2:标准数组比较的转录
Example #2 Transcription of standard array comparison
<?php
// Arrays are compared like this with standard comparison operators
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 null; // uncomparable
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
?>
我们可以通过一些测试轻松地对此进行测试.使用类似数学方法,并且始终只更改一件事,因此我们可以确保在这里更正:
We can test this easily with some testing. Using methods like in math and always change only one thing, so we can make sure we are correct here:
/**
/*
/* Testing operators: < and >
/*
*/
//Test case
//Variations: amount, values and keys (order)
//Test count: 9
// Failed: 0
// Passed: 9
{
//Test case 1.1
$a = [1];
$b = [1];
//Passed
var_dump("Same amount of elements, keys and values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.2
$a = [1];
$b = [1, 1];
//Passed
var_dump("NOT same amount of elements, but same values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.3
$a = [10];
$b = [1, 1];
//Passed
var_dump("NOT same amount of elements nor values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.4
$a = [1 => 1];
$b = [10 => 1];
//Passed
var_dump("Same amount of element and values, NOT same keys: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.5
$a = [10];
$b = [1];
//Passed
var_dump("Same amount of elements and keys, NOT same values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.6
$a = [1 => 1, 2 => 1];
$b = [2 => 1, 1 => 1];
//Passed
var_dump("Same amount of elements and keys in different order: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.7
$a = [1 => 1, 2 => 5];
$b = [2 => 5];
//Passed
var_dump("Same values, NOT same amount of elements nor keys: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.8
$a = [10 => 1];
$b = [1 => 10];
//Passed
var_dump("NOT same keys nor values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.9
$a = [1 => 1, 2 => 1];
$b = [2 => 10, 1 => 1];
//Passed
var_dump("Same amount of elements and values, NOT same keys nor order: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
}
echo PHP_EOL . PHP_EOL . PHP_EOL; //Test case separator
/**
/*
/* Test case end
/*
*/
//NULL, TRUE, FALSE 2 str func
function bool2str($v){if($v === NULL)return "NULL";elseif($v === FALSE)return "FALSE";elseif($v === TRUE)return "TRUE";else return "UNEXPECTED: '$v'";}
For the equality/identity operators ==
and ===
we find the documentation for arrays here:
┌───────────┬──────────┬──────────────────────────────────────────────────┐
│ Example │ Name │ Result │
├───────────┼──────────┼──────────────────────────────────────────────────┤
│ $a == $b │ Equality │ TRUE if $a and $b have the same key/value pairs. │
│ $a === $b │ Identity │ TRUE if $a and $b have the same key/value pairs │
│ │ │ in the same order and of the same types. │
└───────────┴──────────┴──────────────────────────────────────────────────┘
像以前一样,我们可以简单地使用一些测试代码对此进行测试:
As before we can simply test this with some testing code:
/**
/*
/* Testing operators: == and ===
/*
*/
//Test case
//Variations: amount, values and keys (order)
//Test count: 5
// Failed: 0
// Passed: 5
{
//Test case 2.1
$a = [1];
$b = [1];
//Passed
var_dump("Same amount of elements, values and keys: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.2
$a = [1];
$b = [10, 1];
//Passed
var_dump("NOT same amount of elements, but same values: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.3
$a = [10];
$b = [1];
//Passed
var_dump("Same amount of elements, but not values: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.4
$a = [1 => 1];
$b = [10 => 1];
//Passed
var_dump("Same amount of elements and values, but not keys: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.5
$a = [1 => 1, 2 => 2];
$b = [2 => 2, 1 => 1];
//Passed
var_dump("Same amount of elements, key and values, but different order: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
}
echo PHP_EOL . PHP_EOL . PHP_EOL; //Test case separator
/**
/*
/* Test case end
/*
*/
//NULL, TRUE, FALSE 2 str func
function bool2str($v){if($v === NULL)return "NULL";elseif($v === FALSE)return "FALSE";elseif($v === TRUE)return "TRUE";else return "UNEXPECTED: '$v'";}
因此,我们可以看到并确认数组的比较运算符可以按预期并按文档所述工作!
So we can see and confirm that the comparison operators for arrays work as expected and as documented!
<
的文档
和>
及其对象在此处:
The documentation for <
and >
with objects is documented here:
┌───────────┬───────────┬──────────────────────────────────────────────────┐
│ type of │ type of │ │
│ Operand 1 │ Operand 2 │ Result │
├───────────┼───────────┼──────────────────────────────────────────────────┤
│ object │ object │ Built-in classes can define its own comparison, │
│ │ │ different classes are uncomparable, │
│ │ │ same class compare properties same as arrays │
└───────────┴───────────┴──────────────────────────────────────────────────┘
像以前一样,我们也可以对此进行测试:
As before we can also test this:
/**
/*
/* Testing operators: < and >
/*
*/
//Test case
//Variations: amount, values and keys (order)
//Test count: 10
// Failed: 0
// Passed: 10
{
//Test case 1.1
$a = (object)["a" => 1];
$b = (object)["a" => 1];
//Passed
var_dump("Same amount of elements, keys and values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.2
$a = (object)["a" => 1];
$b = (object)["a" => 1, "b" => 1];
//Passed
var_dump("NOT same amount of elements, but same values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.3
$a = (object)["a" => 10];
$b = (object)["a" => 1, "b" => 1];
//Passed
var_dump("NOT same amount of elements nor values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.4
$a = (object)["a" => 1];
$b = (object)["b" => 1];
//Passed
var_dump("Same amount of element and values, NOT same keys: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.5
$a = (object)["a" => 10];
$b = (object)["a" => 1];
//Passed
var_dump("Same amount of elements and keys, NOT same values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.6
$a = (object)["a" => 1, "b" => 1];
$b = (object)["b" => 1, "a" => 1];
//Passed
var_dump("Same amount of elements and keys in different order: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.7
$a = (object)["a" => 1, "b" => 5];
$b = (object)["b" => 5];
//Passed
var_dump("Same values, NOT same amount of elements nor keys: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.8
$a = (object)["c" => 1];
$b = (object)["a" => 10];
//Passed
var_dump("NOT same keys nor values: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.9
$a = (object)["a" => 1, "b" => 1];
$b = (object)["b" => 10, "a" => 1];
//Passed
var_dump("Same amount of elements and values, NOT same keys nor order: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
//Test case 1.10
class A {public $a = 1;}
$a = new A;
class B {public $a = 1;}
$b = new B;
//Passed
var_dump("Same amount of elements and values and keys, but different not built-in class: " . "'<' -> " . bool2str($a < $b) . " '>' -> " . bool2str($a > $b));
}
echo PHP_EOL . PHP_EOL . PHP_EOL; //Test case separator
/**
/*
/* Test case end
/*
*/
//NULL, TRUE, FALSE 2 str func
function bool2str($v){if($v === NULL)return "NULL";elseif($v === FALSE)return "FALSE";elseif($v === TRUE)return "TRUE";else return "UNEXPECTED: '$v'";}
The documentation for ==
and ===
with objects has its own page here:
使用比较运算符(==)时,将以简单的方式比较对象变量,即:如果两个对象实例具有相同的属性和值,并且属于同一类,则它们是相等的.
When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values, and are instances of the same class.
使用身份运算符(===)时,对象变量只有且仅当它们引用相同类的相同实例时,它们才是相同的.
When using the identity operator (===), object variables are identical if and only if they refer to the same instance of the same class.
再次可以对此进行测试:
And again this can be tested:
/**
/*
/* Testing operators: == and ===
/*
*/
//Test case
//Variations: amount, values and keys (order)
//Test count: 7
// Failed: 0
// Passed: 7
{
//Test case 2.1
$a = (object)["a" => 1];
$b = (object)["a" => 1];
//Passed
var_dump("Same amount of elements, values and keys: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.2
$a = (object)["a" => 1];
$b = (object)["a" => 10, "b" => 1];
//Passed
var_dump("NOT same amount of elements, but same values: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.3
$a = (object)["a" => 10];
$b = (object)["a" => 1];
//Passed
var_dump("Same amount of elements, but not values: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.4
$a = (object)["a" => 1];
$b = (object)["b" => 1];
//Passed
var_dump("Same amount of elements and values, but not keys: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.5
$a = (object)["a" => 1, "b" => 2];
$b = (object)["b" => 2, "a" => 1];
//Passed
var_dump("Same amount of elements, key and values, but different order: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.6
class C {public $a = 1;}
$a = new A;
class D {public $a = 1;}
$b = new B;
//Passed
var_dump("Same amount of elements and values and keys, but different not built-in class: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
//Test case 2.7
$a = (object)["a" => 1];
$b = $a;
//Passed
var_dump("Same exact instance: " . "'==' -> " . bool2str($a == $b) . " '===' -> " . bool2str($a === $b));
}
echo PHP_EOL . PHP_EOL . PHP_EOL; //Test case separator
/**
/*
/* Test case end
/*
*/
//NULL, TRUE, FALSE 2 str func
function bool2str($v){if($v === NULL)return "NULL";elseif($v === FALSE)return "FALSE";elseif($v === TRUE)return "TRUE";else return "UNEXPECTED: '$v'";}
因此,我们看到带有对象的比较运算符的行为与预期的和记录的完全一样!即使进行粗略的比较,也会考虑属性和值.
So we see, that the comparison operators with objects behave exactly like expected and documented! Even with loose comparison the attributes and values are being considered.
由于已在此处报告了此错误,因此该错误报告可能基于关于RFC中的评论,内容为:
As this bug has been reported here, the bug report is probably based on the comment in the RFC, which says:
//仅比较值
// only values are compared
但是,除了这是RFC中唯一带有注释的示例外,RFC明确声明它使用与<
,==
和>
相同的比较规则.
But besides that this is the only example in the RFC with a comment, the RFC clearly states that it uses the same comparison rules as <
, ==
and >
.
这意味着所提供的代码示例不可比,因为它没有相同的属性/键.
This means that the code example provided would be uncomparable, because it doesn't have the same attributes/keys.
对于相等性,它需要相同的属性/键和值,因此不能相等,并且小于或大于它是不可比的,如上面的代码示例所示,比较的工作原理:
As for equality it would need same attributes/keys and values so it can't be equal, and for less- or greater- than it is uncomparable as shown in the code example above how the comparison works:
if (!array_key_exists($key, $op2)) {
return null; // uncomparable
}
如果我们单独尝试每个比较运算符,我们也会看到这一点:
We also see this if we try each comparison operator alone:
$a = (object)["b" => "b"];
$b = (object)["a" => "b"];
var_dump($a > $b); //FALSE
var_dump($a < $b); //FALSE
var_dump($a == $b); //FALSE
所有都返回false,因为它是无与伦比的.
All return false, since it's uncomparable.
对于StdClass
会有自己的比较,我们可以使用我们自己的类对其进行测试:
And just for the case StdClass
would have its own comparison, we can test it with our own class:
class A {
public $a = "";
public $b = "";
}
$a = new A;
$a->a = "b";
unset($a->b);
$b = new A;
$b->b = "b";
unset($b->a);
var_dump($a);
var_dump($b);
var_dump($a <=> $b); //1
同样的输出:1.
所以我想说因为它不可比,所以它不应该返回0
,1
或-1
.它可能应该返回FALSE
或NULL
或类似的内容.
So I would say since it is uncomparable it shouldn't return 0
, 1
nor -1
. It should probably return FALSE
or NULL
or something like this.
现在我会说这种行为没有得到正确记录.
Right now I would say this behaviour isn't documented correctly.
这篇关于运算符< =>比较对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!