PHP -- usort 正在修改数组中对象的内容,我该如何防止这种情况?
我使用 usort 和用户比较函数来对对象数组进行排序。对这些对象的数组运行 usort 后,我发现对象的某些值及其在数组中的位置发生了变化。我缺少什么?我不相信我的用户比较功能有任何副作用。 usort 是否以某种方式解构/重建对象?
这是我正在使用的用户比较函数:
private function SortArrayOfSegments($segments){
foreach($segments as $segment){
echo '<pre>';
var_dump($segment);
}
usort($segments, "AirObject::CompareSegments");
foreach($segments as $segment){
var_dump($segment);
echo '</pre>';
}
return $segments;
}
public static function CompareSegments($a, $b){
$interval = date_diff(date_create($a->StartDateTime->GetString()),
date_create($b->StartDateTime->GetString()));
if($interval->invert == 1){
return 1;
}else if($interval->y == 0 && $interval->m == 0 && $interval->d == 0
&& $interval->i == 0 && $interval->s == 0 && $interval->h == 0){
return 0;
}else if($interval->invert == 0){
return -1;
}
}
我正在使用的对象如下所示:
object(AirSegment)#14 (12) {
["StartDateTime"]=>
object(VDateTime)#27 (4) {
["date"]=>
string(10) "2010-12-07"
["time"]=>
string(8) "09:23:21"
["timezone"]=>
string(0) ""
["utc_offset"]=>
string(0) ""
}
["EndDateTime"]=>
object(VDateTime)#23 (4) {
["date"]=>
string(10) "2010-12-07"
["time"]=>
string(8) "13:23:21"
["timezone"]=>
string(0) ""
["utc_offset"]=>
string(0) ""
}
["start_airport_code"]=>
string(3) "SFO"
["start_city_name"]=>
string(13) "San Francisco"
["end_airport_code"]=>
string(3) "STL"
["end_city_name"]=>
string(8) "St Louis"
["operating_airline"]=>
string(15) "United Airlines"
["operating_flight_number"]=>
string(3) "335"
["duration"]=>
float(NAN)
["required_properties":protected]=>
array(9) {
["StartDateTime"]=>
bool(false)
["EndDateTime"]=>
bool(false)
["start_airport_code"]=>
bool(false)
["end_airport_code"]=>
bool(false)
["operating_airline"]=>
bool(false)
["operating_flight_number"]=>
bool(false)
["start_city_name"]=>
bool(false)
["end_city_name"]=>
bool(false)
["service_class"]=>
bool(true)
}
["service_class"]=>
string(5) "Coach"
["trip_id"]=>
string(4) "1621"
}
正在更改的属性是持续时间属性。在运行 usort 之前,每个对象都有一个有效的浮点值。 usort后,有两个为NaN。
解决方案:
date_diff 有副作用——至少在我的 PHP 构建中是这样。删除它完全解决了问题。
public static function CompareSegments($a, $b){
$adate = new DateTime($a->StartDateTime->GetString());
$bdate = new DateTime($b->StartDateTime->GetString());
$lessThan = $adate < $bdate;
$equal = $adate == $bdate;
$greaterThan = $adate > $bdate;
if($lessThan){
return -1;
}else if($equal){
return 0;
}else{
return 1;
}
}
I am using usort with a user comparison function to sort an array of objects. After running usort on an array of these objects, I've found that some of the values of the objects have changed along with their position in the array. What am I missing? I don't believe there are any side effects in my user comparison function. Does usort deconstruct/reconstruct objects some how?
Here is the the user comparison function I'm using:
private function SortArrayOfSegments($segments){
foreach($segments as $segment){
echo '<pre>';
var_dump($segment);
}
usort($segments, "AirObject::CompareSegments");
foreach($segments as $segment){
var_dump($segment);
echo '</pre>';
}
return $segments;
}
public static function CompareSegments($a, $b){
$interval = date_diff(date_create($a->StartDateTime->GetString()),
date_create($b->StartDateTime->GetString()));
if($interval->invert == 1){
return 1;
}else if($interval->y == 0 && $interval->m == 0 && $interval->d == 0
&& $interval->i == 0 && $interval->s == 0 && $interval->h == 0){
return 0;
}else if($interval->invert == 0){
return -1;
}
}
The objects I'm using look like this :
object(AirSegment)#14 (12) {
["StartDateTime"]=>
object(VDateTime)#27 (4) {
["date"]=>
string(10) "2010-12-07"
["time"]=>
string(8) "09:23:21"
["timezone"]=>
string(0) ""
["utc_offset"]=>
string(0) ""
}
["EndDateTime"]=>
object(VDateTime)#23 (4) {
["date"]=>
string(10) "2010-12-07"
["time"]=>
string(8) "13:23:21"
["timezone"]=>
string(0) ""
["utc_offset"]=>
string(0) ""
}
["start_airport_code"]=>
string(3) "SFO"
["start_city_name"]=>
string(13) "San Francisco"
["end_airport_code"]=>
string(3) "STL"
["end_city_name"]=>
string(8) "St Louis"
["operating_airline"]=>
string(15) "United Airlines"
["operating_flight_number"]=>
string(3) "335"
["duration"]=>
float(NAN)
["required_properties":protected]=>
array(9) {
["StartDateTime"]=>
bool(false)
["EndDateTime"]=>
bool(false)
["start_airport_code"]=>
bool(false)
["end_airport_code"]=>
bool(false)
["operating_airline"]=>
bool(false)
["operating_flight_number"]=>
bool(false)
["start_city_name"]=>
bool(false)
["end_city_name"]=>
bool(false)
["service_class"]=>
bool(true)
}
["service_class"]=>
string(5) "Coach"
["trip_id"]=>
string(4) "1621"
}
The property that is changing is the duration property. Before usort is run, every object has a valid float value. After usort, two of them are NaN.
RESOLUTION:
date_diff has side effects -- at least in my build of PHP. Removing it fixed the issues entirely.
public static function CompareSegments($a, $b){
$adate = new DateTime($a->StartDateTime->GetString());
$bdate = new DateTime($b->StartDateTime->GetString());
$lessThan = $adate < $bdate;
$equal = $adate == $bdate;
$greaterThan = $adate > $bdate;
if($lessThan){
return -1;
}else if($equal){
return 0;
}else{
return 1;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在我的脑海中,我没有看到任何应该修改数组元素本身内容的东西。
usort()
的工作方式是,当它确定新的顺序时元素,它将新元素添加到保存原始值的数组中,然后删除原始元素,因此严格来说,传递给函数的数组元素都不会出现,只有它们的副本出现(尽管您传入的同一数组变量的一部分)。正如您所问的,我不明白为什么
usort
会破坏和重新构造对象,但它确实对数组本身做了类似的事情。据我所知,数组元素的值不应更改,除非您在比较函数中明确执行此操作。在
CompareSegments
方法中,您调用StartDateTime->GetString()
方法。GetString()
方法是否有可能正在修改您的数据?Off the top of my head, I don't see anything in there that should be modifying the contents of the array elements themselves.
The way
usort()
works is that when it determines the new order of the elements, it adds new elements to the array which holds the value of the originals, then removes the originals, so strictly speaking, none of the elements of the array you passed into the function ever come out, only copies of them do (albeit as part of the same array variable you passed in).I don't see any reason why
usort
would destruct and re-construct objects, as you asked, but it does do a similar thing to the array itself. As far as I can tell, nothing in the value of the array elements should be changed, unless you do it explicitly in the comparison function.In your
CompareSegments
method, you make calls to aStartDateTime->GetString()
method. Is it possible that theGetString()
method is modifying your data?在应用 usort 方法或任何方法之前,对象是什么样子的?在不知道对象的原始状态的情况下,很难得出结论,但 NaN 是传递给 usort 的函数产生的错误结果。
What do the objects look like before you apply the usort method, or indeed any method? Without knowing the original state of the objects it is difficult to be conclusive, but NaN is the erroneous result produced by the function passed to usort.