【问题标题】:Strange PHP behaviour for FOR within array数组中 FOR 的奇怪 PHP 行为
【发布时间】:2019-01-23 16:41:17
【问题描述】:

我的函数出现了非常奇怪的 PHP 行为,该函数允许在关联数组的数组中搜索以查找具有可搜索值的键的数组。

我的 PHP 代码:

<?php

// Test array - results from database

$test_array[0] = array('period' => '2018', 'payment_type' => 'Direct Debit', 'value' => 0);
$test_array[1] = array('period' => '2018', 'payment_type' => 'Manual', 'value' => 20.85);
$test_array[2] = array('period' => '2018', 'payment_type' => 'Credit Debit Card', 'value' => 0);

// Function to find subarrays by payment type
function searchReportArrayForKeyValue($array, $searchvalue) {

    $result_array = Array();

    for($i = 0; $i < count($array); ++$i) {
        $array_inside = $array[$i];
        $keys = array_keys($array_inside);

        for($j = 0; $j < count($array_inside); ++$j) {
            $value = $array_inside[$keys[$j]];

            if($value == $searchvalue) {
                $result_array = $array_inside;
            }

        }
    }

    return $result_array;
}

var_dump(searchReportArrayForKeyValue($test_array, 'Direct Debit'));
var_dump(searchReportArrayForKeyValue($test_array, 'Manual'));
var_dump(searchReportArrayForKeyValue($test_array, 'Credit Debit Card'));

?>

如果我运行此代码,我应该返回 3 个不同的数组(测试数组中的 0、1、2 个键),但是所有三个函数调用都返回“信用卡借记卡”数组键:http://take.ms/hZfec(屏幕截图)。 但是,如果我将 'value' => 0 更改为某个浮点数/整数,所有这些都可以按预期工作,例如,如果我将测试数组更改为此:

$test_array[0] = array('period' => '2018', 'payment_type' => 'Direct Debit', 'value' => 11.2);
$test_array[1] = array('period' => '2018', 'payment_type' => 'Manual', 'value' => 20.85);
$test_array[2] = array('period' => '2018', 'payment_type' => 'Credit Debit Card', 'value' => 10.5);

我的三个函数调用返回了 3 个正确的不同子数组:http://take.ms/SSTu1(屏幕截图)

为什么会这样? “价值”中的零如何打破数组迭代?我的函数出了什么问题?

P.S.:以前我在代码中有“for each”,并将其更改为“for”以确保此问题与“for each”中的“for each”中的指针重置无关,但这没有帮助这种情况。

【问题讨论】:

  • 你试过===if($value === $searchvalue) {
  • 是否有充分的理由不在数据库中执行此操作?为什么要将整个表结果保存在 PHP 内存中,在那里模拟 WHERE 子句?
  • 你的实际意图是什么? (XY problem)

标签: php arrays for-loop


【解决方案1】:

最后我通过以下代码更改解决了这个问题:

我改变了这个:

if($value == $searchvalue)

到这里:

if(strval($value) == strval($searchvalue))

但我仍然不明白这是如何以及为什么会产生如此奇怪的行为。

【讨论】:

  • 如果您将任何字符串与整数进行比较,则该字符串将转换为 int。如果字符串不是数字,则结果为 0(例如,“abc” == 0 等于 0 ==0)。在您的第一个示例中,值为 0...
  • 你应该只使用 "===" 而不是 "=="
【解决方案2】:

您正在使用loose comparison 使用==

在每个循环中,最后一个比较是0 == Direct Debit,也就是true,然后你设置$result_array = $array_inside;

例如,您可以在运行时看到它:

echo "$value == $searchvalue = " . ($value == $searchvalue ? "true" : "false") . PHP_EOL;
if($value == $searchvalue) {

【讨论】:

    【解决方案3】:

    您不能直接比较浮点值,因为并非所有有理十进制数都具有等效的有理浮点数。

    见:https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems

    要正确比较浮点数,您需要执行以下操作:

    $e = 0.00001;
    
    if( abs($float_a - $float_b) < $e );
    

    其中$e 是对于特定比较而言足够小的误差范围。

    您的转换为字符串的解决方案仅适用,因为 PHP 的默认浮点格式精度为 14 位,并且不精确度小于该值。

    也就是说,出于这些确切原因等等,任何人都不应该使用浮点数来记录金额。通常,您将值存储为基本货币单位的整数,例如:1 美元 == 100 美分,1BTC == 1,000,000 聪。

    但是还有进一步的问题,例如安全地将 4 美元分配给 3 个收款人、安全地舍入金额而不损失一分钱等。因此,有 Fowler 的金钱模式和libraries that implement it

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-29
      • 2013-07-23
      • 2011-06-25
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 2011-07-28
      • 1970-01-01
      相关资源
      最近更新 更多