使用多维数组调用array_diff_assoc()时出现"Array to string conversion error"错误。

85

以下代码行会导致数组转换成字符串错误:

$diff = array_diff_assoc($stockist, $arr);

这里,$arr 是从 JSON 文件解码得到的数组。使用 is_array() 函数,我能够验证两个参数都是数组。有人能指出问题吗?

$stockist = array();
while (!feof($file_handle)) {

    $line_of_text = fgetcsv($file_handle);
    $query = "SELECT * FROM reorderchart WHERE medicine = '"
        . trim($line_of_text[3])
        . "' ORDER BY medicine";
    $result = mysql_query($query);

    if (trim($line_of_text[2]) - trim($line_of_text[1]) <= 0) {
        
        while ($row = mysql_fetch_array($result)) {

            $file = "results.json";
            $arr = json_decode(file_get_contents($file),true);
            $pharmacy = trim($row['Medicine']);

            if (isset($stockist[$pharmacy])) {
                    
                $medicine = $stockist[$pharmacy];
                $medicine[] = trim($row['Stockist']);
                $stockist[$pharmacy] = $medicine;

            } else {

                $medicine = array();
                $medicine[] = trim($row['Stockist']);
                $stockist[$pharmacy] = $medicine;
            }
        }
    }
}
$diff = array();
$diff = array_diff_assoc($stockist,$arr);
ksort($diff);
foreach ($diff as $key => $value) {

    echo "<table align='center' border='1'>";
    echo "<tr><td align = 'center'> <font color = 'blue'> $key</td></tr>";
    
    foreach($value as $key1 => $value1) {

        echo "<tr><td align ='center'>$value1</td></tr><br>";
    }
    echo "</table>";
}

4
可能原因:多维数组。 - Viacheslav Kondratiuk
"两个参数都是数组"。没错,PHP 也没有说什么不同的。问题在于“数组转换为字符串”,而不是相反。问题是这些数组包含了什么。 - geomagas
1
@viakondratiuk 是的,它是多维的。但是 array_diff() 函数只评估第一层级吗? - user2963765
@user2963765 这个函数只能检查一个 n 维数组的一个维度。当然,您可以使用 array_diff($array1[0], $array2[0]) 来检查更深层次的维度。 - Viacheslav Kondratiuk
你可以使用递归数组差异。查看这个 https://gist.github.com/jondlm/7709e54f84a3f1e1b67b,它解决了我的问题... - geneowak
很遗憾,这个问题不是很清楚,因为它没有展示被比较的两个数组的样本数据(作为 [mcve] 的一部分)。 - mickmackusa
11个回答

54

据此:

php -r 'array_diff(array("a" => array("b" => 4)), array(1));'
PHP Notice:  Array to string conversion in Command line code on line 1
PHP Stack trace:
PHP   1. {main}() Command line code:0
PHP   2. array_diff() Command line code:1

你的数组是多维的。

array_diff 只检查一个 n 维数组的一维。当然,你可以使用 array_diff($array1[0], $array2[0]); 来检查更深层次的维度。


47
对我来说,这似乎是一个错误。 "将数组转换为字符串" 的信息至多是误导性的。 - Jānis Elmeris

29

array_diff 只能处理一维数组,你可以选择:


2
多维数组的展平是错误的。当第一个嵌套数组被处理时,函数会忘记原始 $arr 中的所有其他值。 - Kangur
7
好的!Unserialize 能够运作,与最受欢迎的回答相反。只需要在此之后添加 $results = array_map('unserialize', $results); 即可读取它。 - Robert Sinclair
第二个例子正是我所需要的,谢谢! - Steve Bauman

29

严格来说,答案是因为 "您的一个数组是多维的"。

另一个有用的提示可能是 - 根据您进一步解析实际差异的需求 - 考虑首先使用以下方法测试您的数组:

$diff = strcmp(json_encode($stockist), json_encode($arr));
或者
$diff = strspn(json_encode($stockist) ^ json_encode($arr), "\0");
或者
$diff = xdiff_string_diff(json_encode($stockist), json_encode($arr));

所有这些选项都将比较整个数组树,而不仅仅是顶级。


$diff = strcmp(json_encode($stockist), json_encode($arr)); 没有起作用,当两者之间存在差异时始终返回0。 - Robert Sinclair

9
您可以在array_diff()文档中看到:

当且仅当(string) $ elem1 ===(string) $ elem2时,才认为两个元素相等。换句话说:当字符串表示相同时。

所以看起来您不能使用此函数处理多维数组,或者事实上任何无法转换为字符串的值。这是因为该函数将把值强制转换为string进行比较。
您可以编写自己的函数以递归地检查数组是否有差异-实际上,下面的内容来自上面链接的文档的评论中。
您可以在此处查看评论
function arrayRecursiveDiff($aArray1, $aArray2) { 
    $aReturn = array(); 

    foreach ($aArray1 as $mKey => $mValue) { 
        if (array_key_exists($mKey, $aArray2)) { 
            if (is_array($mValue)) { 
                $aRecursiveDiff = arrayRecursiveDiff($mValue, $aArray2[$mKey]); 
                if (count($aRecursiveDiff)) { $aReturn[$mKey] = $aRecursiveDiff; } 
            } else { 
                if ($mValue != $aArray2[$mKey]) { 
                    $aReturn[$mKey] = $mValue; 
                } 
            } 
        } else { 
            $aReturn[$mKey] = $mValue; 
        } 
    } 

    return $aReturn; 
}

3
PHP语言的编写者认为不需要编写递归版本的函数很令人惊讶。他们还让数组转换成字符串时出现错误,而不是让错误信息显示“不支持多维数组”。 - ahnbizcad

8
根据PHP函数文档的说明:
注意: 仅当(string) $elem1 === (string) $elem2时,两个元素才被视为相等。换句话说:当字符串表示相同时。
有关更多信息,请参见http://php.net/manual/en/function.array-diff.php

我只需要比较键。所以我使用了array_diff_key()。但它返回一个空数组。 - user2963765
1
如果返回一个空数组,这意味着两个数组具有相同的键集。 - max
我遇到了一个错误,其中我有两个被认为是不同的数组,但它们显然看起来是相同的。这个答案帮助我比较它们的字符串表示,结果确实不同。 - misterone

3
今天在为 PHP 7.3 从 5.3 进行平台升级时,我遇到了这个问题... 因为我将存储此值以供稍后使用,所以我想确保我不会得到一个“部分”序列化的数组,这可能会导致下游出现问题。
感谢 kenorb 把我带上了正确的道路(我赞同了你的答案)。以下代码对我很有用。
代码:
$a1 = [
  'foo' => 'bar',
  'bar' => [
    'test' => 'test'
  ],
  'foobar' => 'fizzbuzz'
];

$a2 = [
  'foobar' => 'fizzbuzz',
  'herp' => [
    'derp' => 'herpderp'
  ]
];

$diff = array_diff(array_map('serialize', $a1), array_map('serialize', $a2));

$multidimensional_diff = array_map('unserialize', $diff);

print_r($multidimensional_diff);

输出:

Array
(
    [foo] => bar
    [bar] => Array
        (
            [test] => test
        )

)

1
它与kenorb提供的答案有何不同? - Dharman
使用 array_map('unserialize', $diff),以便 $diff 数组的格式保持多维且不进行任何序列化。我在评论中看到了它,但那段文字很小,容易被忽略。 - ZhuRenTongKu
稍微扩展一下你的回答: function diffMultiDim($dataLeft, $dataRight) { return array_map('unserialize', array_diff(array_map('serialize', $dataLeft), array_map('serialize', $dataRight))); } - MaKR

3

这是我针对类似问题的解决方案。我想比较两个关联数组并返回更改的值,但其中一些元素是数组。因此,如果我使用

array_diff_assoc

这段代码出现了“数组转字符串错误”。我的函数也会比较元素是否为数组,如果有差异,它将返回数组元素。这还是一个正在进行中的工作,并没有经过广泛测试。 例如:

public static $example1 = [
    'id' => 1,
    'status' => 2,
    'elements' => ['test', 'example'],
    'different' => ['old' => 5, 'new' => 9]
];

public static $example2 = [
    'id' => 1,
    'status' => 3,
    'elements' => ['test', 'example'],
    'different' => ['old' => 5, 'new' => 8]
];

public static function test(){
    die(var_dump(self::udiffAssoc(self::$example1, self::$example2)));
}

public static function udiffAssoc(array $array1, array $array2)
{
    $checkDiff = function ($a, $b) use (&$checkDiff) {
        if (is_array($a) && is_array($b)) {
            return array_udiff_assoc($a, $b, $checkDiff);
        } elseif (is_array($a)) {
            return 1;
        } elseif (is_array($b)) {
            return -1;
        } elseif ($a === $b) {
            return 0;
        } else {
            return $a > $b ? 1 : -1;
        }
    };
    return array_udiff_assoc($array1, $array2, $checkDiff);
}

如果运行::test,它将返回:

array(2) {
    ["status"]=>
    int(2)
    ["different"]=>
    array(2) {
    ["old"]=>
    int(5)
    ["new"]=>
    int(9)
  }
}

1

我遇到了同样的错误,并在php的以下bug报告中找到了解决方法:

https://bugs.php.net/bug.php?id=60198

一些比较多个数组中元素的array_*函数是通过(string)$elem1 === (string)$elem2进行比较的。如果$elem1或$elem2是一个数组,则会抛出“将数组转换为字符串”的通知。两个可能引发此问题的函数示例是array_intersect()和array_diff()。如果这些函数不希望使用其他数组作为值的数组,则应在文档页面上进行说明。该报告描述了为什么PHP在比较多维数组时会抛出错误。

0

我的解决方案怎么样:

$diff = strcmp(serialize($arr1), serialize($arr2))

你的解决方案只返回差异,但我需要返回完整级别和差异的键。 - Crustamet

0

对于任何遇到这个问题的人,array_udiff()是一个可直接替换的解决方案,它使用回调函数而不是内部字符串转换来避免警告。例如,要对比[['a' => 1, 'b' => 0]][['a' => 1, 'b' => 1]]

array_udiff([['a' => 1, 'b' => 0]], [['a' => 1, 'b' => 1]], function ($a, $b) { return $a != $b; });
// [["a" => 1,"b" => 0]]

如果使用 PHP 7.4+,也可以使用箭头函数:

array_udiff([['a' => 1, 'b' => 0]], [['a' => 1, 'b' => 1]], fn ($a, $b) => $a != $b);
// [["a" => 1,"b" => 0]]

请注意,关联数组比较会忽略键的顺序,因此 ['a' => 1, 'b' => 0] == ['b' => 0, 'a' => 1]

1
这并不是最佳实践的示范。[callback(mixed $a, mixed $b): int]意味着应该返回一个整数。之前发布的技术答案:[1],[2],[3],[4],[5],[6],[7]。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接