I was trying to filter date from a form down to only what a user has changed, and started using array_filter
as is it seemed to do exactly what I wanted. I tested a few forms and ran into this unexpected behavior. When the "new" value is 1, it is not detected by array_diff
. Also unexpected when running this on 3v4l.org, was that the foreach loop was actually faster than array_filter
while returning the expected result. I've read the man-page for the functions and understand that it does a string comparison, but all array values are strings to start with so I wouldn't expect it to be a type conversion issue.
I've solved my initial issue and will gladly use the faster foreach loop, but I am interested if anyone can explain why this works this way.
<?php
$array_1 = [
'id' => '42',
'base_id' => '23',
'role_id' => '1',
'title' => 'Manage Account',
'slug' => 'manage_account',
'parent' => '31',
'order' => '1',
'visibility' => '1'
];
$array_2 = [
'id' => '42',
'base_id' => '23',
'role_id' => '99999',
'title' => 'Manage Account',
'slug' => 'manage_account',
'parent' => '31',
'order' => '1',
'visibility' => '1'
];
var_dump(array_diff($array_1, $array_2));
// Result (unexpected)
// array (size=0)
// empty
$diff = [];
foreach ($array_1 as $key => $value) {
if ((string) $array_1[$key] !== (string) $array_2[$key]) {
$diff[$key] = $value;
}
}
var_dump($diff);
// Result (expected)
// array (size=1)
// 'role_id' => string '1' (length=1)
array_diff()
looks for exact duplicates for each value of array 1 in array 2, ignoring the keys.
1
has a duplicate in array 2, e.g. under key order
. That's why it's not listed as difference.
Whether or not this behavior is optimal or obvious is debatable, but that's how it works.
If you change the 1
to a 3
, it will be reported, as array 2 does not contain a value 3
:
$array_1 = [
'id' => '42',
'base_id' => '23',
'role_id' => '3',
'title' => 'Manage Account',
'slug' => 'manage_account',
'parent' => '31',
'order' => '1',
'visibility' => '1'
];
$array_2 = [
'id' => '42',
'base_id' => '23',
'role_id' => '99999',
'title' => 'Manage Account',
'slug' => 'manage_account',
'parent' => '31',
'order' => '1',
'visibility' => '1'
];
var_dump(array_diff($array_1, $array_2));
// Result (unexpected)
// array (size=1)
// 'role_id' => string '3' (length=1)
If you want the keys to be taken into account, use array_diff_assoc()
instead.