在给出这个例子的 RFC 中:
// only values are compared $a = (object) ["a" => "b"]; $b = (object) ["b" => "b"]; echo $a <=> $b; // 0
但是当我执行它时,我得到 1 作为输出:
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; //1
我现在不明白 <=> 如何比较对象?在 RFC 中,它说它仅按值进行比较。
附言我在 vagrant 下使用 PHP 7.0.4-6+deb.sury.org~trusty+1 (cli) ( NTS )
更新:
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 时,我们发现它自相矛盾:
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)
注意: 参见
==
,这意味着飞船运算符(operator)做了一个松散的比较。稍后在示例中:
// only values are compared $a = (object) ["a" => "b"]; $b = (object) ["b" => "b"]; echo $a $b; // 0
飞船操作符只是操作符
<
、 ==
和 >
的组合。它根据它的评估结果给出各自的返回值:operator(s): < = >
return value: -1 0 1
现在 arrays 和 objects 有点复杂 types 。要了解
<=>
PHP spaceship 运算符的作用,我们需要查看并了解 <
、 ==
和 >
对数组和对象的作用。因此,让我们看看每种类型的比较运算符
<
、 >
、 ==
。首先我们将查看 <
和 >
,然后我们还将查看 ==
。数组比较运算符
现在,对于数组
<
和 >
已记录 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 │ └───────────┴───────────┴──────────────────────────────────────────────────┘
这也可以用 code 来写和表示:
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 } ?>
我们可以通过一些测试轻松地测试这一点。使用 methods like in math 并且总是只改变一件事,所以我们可以确保我们在这里是正确的:
/**
/*
/* 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'";}
对于相等/恒等运算符
==
和 ===
我们找到了数组 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. │ └───────────┴──────────┴──────────────────────────────────────────────────┘
和以前一样,我们可以用一些测试代码简单地测试一下:
/**
/*
/* 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'";}
因此,我们可以看到并确认数组的比较运算符按预期和文档工作!
Full Testing File
对象比较运算符
<
的文档>
和对象被记录在案 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 │ └───────────┴───────────┴──────────────────────────────────────────────────┘
和以前一样,我们也可以对此进行测试:
/**
/*
/* 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'";}
带有对象的
==
和 ===
的文档有自己的页面 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.
这可以再次测试:
/**
/*
/* 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'";}
所以我们看到,带有对象的比较运算符的行为与预期和记录的完全一样!即使进行松散的比较,也会考虑属性和值。
Full Testing File
结论
由于此错误已报告 here ,因此错误报告可能基于 RFC 中的评论,其中说:
// only values are compared
但除了这是 RFC 中唯一带有注释的示例之外,RFC 明确指出它使用与
<
、 ==
和 >
相同的比较规则。这意味着提供的代码示例将是无与伦比的,因为它没有相同的属性/键。
至于相等,它需要相同的属性/键和值,因此它不能相等,并且对于小于或大于它是不可比较的,如上面的代码示例所示,比较如何工作:
if (!array_key_exists($key, $op2)) {
return null; // uncomparable
}
如果我们单独尝试每个比较运算符,我们也会看到这一点:
$a = (object)["b" => "b"];
$b = (object)["a" => "b"];
var_dump($a > $b); //FALSE
var_dump($a < $b); //FALSE
var_dump($a == $b); //FALSE
都返回 false,因为它是无与伦比的。
对于
StdClass
有自己的比较的情况,我们可以用我们自己的类来测试它: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
或类似的东西。 现在我会说这种行为没有正确记录。
关于php - 运算符 <=> 如何比较对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36246993/