I encountered a strange behavior of Magento 1.8 after changing php version from 5.5 to 7.0.
This strange behavior is due to a change in the work function uasort
.
Source code:
<?php
$arr = [
"nominal" => [
"before" => ["subtotal", "grand_total"],
"after" => [],
"_code" => "nominal"
],
"subtotal" => [
"after" => ["nominal"],
"before" => ["grand_total", "shipping", "freeshipping", "tax_subtotal", "discount", "tax", "weee"],
"_code" => "subtotal"
],
"shipping" => [
"after" => ["subtotal", "freeshipping", "tax_subtotal", "nominal", "weee"],
"before" => ["grand_total", "discount", "tax_shipping", "tax"],
"_code" => "shipping"
],
"grand_total" => [
"after" => ["subtotal", "nominal", "shipping", "freeshipping", "tax_subtotal", "discount", "tax"],
"before" => [],
"_code" => "grand_total"
],
"msrp" => [
"before" => [],
"after" => [],
"_code" => "msrp"
],
"freeshipping" => [
"after" => ["subtotal", "nominal"],
"before" => ["tax_subtotal", "shipping", "grand_total", "tax", "discount"],
"_code" => "freeshipping"
],
"discount" => [
"after" => ["subtotal", "shipping", "nominal", "freeshipping", "tax_subtotal", "tax_shipping", "weee"],
"before" => ["grand_total", "tax"],
"_code" => "discount"
],
"tax_subtotal" => [
"after" => ["0" => "freeshipping", "1" => "subtotal", "3" => "nominal"],
"before" => ["tax", "discount", "shipping", "grand_total", "tax_shipping", "weee"],
"_code" => "tax_subtotal"
],
"tax_shipping" => [
"after" => ["shipping", "tax_subtotal", "subtotal", "freeshipping", "nominal"],
"before" => ["tax", "discount", "grand_total"],
"_code" => "tax_shipping"
],
"tax" => [
"after" => ["subtotal", "shipping", "discount", "tax_subtotal", "freeshipping", "tax_shipping", "nominal", "weee"],
"before" => ["grand_total"],
"_code" => "tax"
],
"weee" => [
"after" => ["subtotal", "tax_subtotal", "nominal", "freeshipping"],
"before" => ["shipping", "tax", "discount", "grand_total", "tax_shipping"],
"_code" => "weee"
]
];
function _compareTotals($a, $b)
{
$aCode = $a['_code'];
$bCode = $b['_code'];
if (in_array($aCode, $b['after']) || in_array($bCode, $a['before'])) {
$res = -1;
} elseif (in_array($bCode, $a['after']) || in_array($aCode, $b['before'])) {
$res = 1;
} else {
$res = 0;
}
echo sprintf("%s <> %s: %s", $aCode, $bCode, $res) . "\n";
return $res;
}
uasort($arr, '_compareTotals');
var_dump(array_keys($arr));
In php 5.5 result is:
freeshipping <> subtotal: 1
freeshipping <> shipping: -1
weee <> freeshipping: 1
tax <> freeshipping: 1
tax_shipping <> freeshipping: 1
tax_subtotal <> freeshipping: 1
discount <> freeshipping: 1
nominal <> freeshipping: -1
freeshipping <> grand_total: -1
msrp <> freeshipping: 0
subtotal <> msrp: 0
nominal <> subtotal: -1
tax_subtotal <> shipping: -1
weee <> tax_subtotal: 1
tax <> tax_subtotal: 1
tax_shipping <> tax_subtotal: 1
grand_total <> tax_subtotal: 1
discount <> tax_subtotal: 1
shipping <> tax_subtotal: 1
grand_total <> discount: 1
grand_total <> shipping: 1
grand_total <> tax_shipping: 1
grand_total <> tax: 1
weee <> grand_total: -1
shipping <> discount: -1
tax <> shipping: 1
tax_shipping <> shipping: 1
weee <> shipping: -1
tax_shipping <> discount: -1
tax <> tax_shipping: 1
discount <> tax_shipping: 1
tax <> discount: 1
array(11) {
[0] =>
string(7) "nominal"
[1] =>
string(8) "subtotal"
[2] =>
string(4) "msrp"
[3] =>
string(12) "freeshipping"
[4] =>
string(12) "tax_subtotal"
[5] =>
string(4) "weee"
[6] =>
string(8) "shipping"
[7] =>
string(12) "tax_shipping"
[8] =>
string(8) "discount"
[9] =>
string(3) "tax"
[10] =>
string(11) "grand_total"
}
In php 7.0 result is:
nominal <> subtotal: -1
subtotal <> shipping: -1
shipping <> grand_total: -1
grand_total <> msrp: 0
msrp <> freeshipping: 0
freeshipping <> discount: -1
discount <> tax_subtotal: 1
msrp <> tax_subtotal: 0
freeshipping <> tax_subtotal: -1
discount <> tax_shipping: 1
freeshipping <> tax_shipping: -1
tax_subtotal <> tax_shipping: -1
discount <> tax: -1
tax <> weee: 1
tax_shipping <> weee: 1
freeshipping <> weee: -1
tax_subtotal <> weee: -1
array(11) {
[0] =>
string(7) "nominal"
[1] =>
string(8) "subtotal"
[2] =>
string(8) "shipping"
[3] =>
string(11) "grand_total"
[4] =>
string(4) "msrp"
[5] =>
string(12) "freeshipping"
[6] =>
string(12) "tax_subtotal"
[7] =>
string(4) "weee"
[8] =>
string(12) "tax_shipping"
[9] =>
string(8) "discount"
[10] =>
string(3) "tax"
}
In PHP5 grand_total
is the last element, but in PHP7 - no.
The problem is related to the uncertainty of the location msrp
element. I found a research on this subject associated with php 5.
I solved this problem by indicating a relative position msrp
. But I wonder why it works in php5 and does not work in php7. These are the features of the new version of php or a bug?
addition #1
The problem not only in that the PHP7 don't knows how to sort equal elements, for example msrp
and grand_total
.
If you look at item shipping
and freeshipping
, then they are clearly defined, who should be earlier. PHP5 solves this problem, and PHP7 not.
From the usort()
documentation:
Note: If two members compare as equal, their relative order in the sorted array is undefined.
This is what you're seeing here. PHP 7 uses a different, partially stable sorting algorithm, so elements that compare equal according to your sorting function may now have a different order.
If you care about the sorting order of equal elements (and this is not just a testing issue), you should make it explicit in your comparison function.
Possible Solution
I've created a magento module to solve magento issues with totals calculation for php7. The issues I've experienced in particular were that taxes have been added twice to the grand total for pay with amazon module on the amazonpayments checkout page.
Credits
The solution was provided by archigrafix on https://magento.stackexchange.com/a/97107/35665 solved my issues - so this is simply the fix packed into a module.
Module:
来源:https://stackoverflow.com/questions/34281113/the-different-behavior-of-the-function-uasort-in-php-5-5-and-php-7-0