Let's say I want to do this:
$a = array_intersect_assoc( array( 'key1' => array( 'key2' => 'value2' ), 'key3' => 'value3', 'key4' => 'value4' ), array( 'key1' => array( 'key2' => 'some value not in the first parameter' ), 'key3' => 'another value' ) ); var_dump( $a );
The printed result is:
array 'key1' => array 'key2' => string 'value2' (length=6)
It's clear that values associated with 'key2' in both arrays are not the same, however array_intersect_assoc()
still return 'key2' => 'value2'
as the intersected value.
Is this the expected behavior of array_intersect_assoc()
?
Thank开发者_Go百科s!
Yes, it's the expected behavior, because the comparison is done using string representations, and the function does not recurse down nested arrays. From the manual:
The two values from the key => value pairs are considered equal only if (string) $elem1 === (string) $elem2 . In other words a strict type check is executed so the string representation must be the same.
If you tried to intersect with an array with 'key1' => 'Array'
, you'd get the same result because the string representation of an array is always 'Array'
.
One of the user-contributed notes, by nleippe, contains a recursive implementation that looks promising (I modified the third line to do string comparison on any non-array values):
function array_intersect_assoc_recursive(&$arr1, &$arr2) {
if (!is_array($arr1) || !is_array($arr2)) {
// return $arr1 == $arr2; // Original line
return (string) $arr1 == (string) $arr2;
}
$commonkeys = array_intersect(array_keys($arr1), array_keys($arr2));
$ret = array();
foreach ($commonkeys as $key) {
$ret[$key] =& array_intersect_assoc_recursive($arr1[$key], $arr2[$key]);
}
return $ret;
}
function array_key_match_recursive(array $main, array $other, $i = 0, &$result = []) {
foreach($main as $key => $value) {
$k = sprintf('%s%s', str_repeat('=', $i), $key);
if (!isset($other[$key])) {
$result[$k][] = 'not key';
}
if (!is_array($value) && empty($other[$key])) {
$result[$k][] = 'value empty';
}
if (is_array($value) && isset($other[$key])) {
array_key_match_recursive($value, $other[$key], ++$i, $result);
}
}
//return (bool) !$result;
return $result;
}
A function that does what you need:
/**
* Get array intersect assoc recursive.
*
* @param mixed $value1
* @param mixed $value2
*
* @return array|bool
*/
function getArrayIntersectAssocRecursive(&$value1, &$value2)
{
if (!is_array($value1) || !is_array($value1)) {
return $value1 === $value2;
}
$intersectKeys = array_intersect(array_keys($value1), array_keys($value2));
$intersectValues = [];
foreach ($intersectKeys as $key) {
if (getArrayIntersectAssocRecursive($value1[$key], $value2[$key])) {
$intersectValues[$key] = $value1[$key];
}
}
return $intersectValues;
}
My version based on @BoltClock version:
function array_intersect_assoc_recursive($arr1, $arr2) {
if (!is_array($arr1) || !is_array($arr2)) {
return $arr1;
}
$commonkeys = array_keys($arr1);
if (!array_key_exists('$', $arr2)){
$commonkeys = array_intersect(array_keys($arr1), array_keys($arr2));
}
$ret = array();
foreach ($commonkeys as $key) {
$ret[$key] = array_intersect_assoc_recursive($arr1[$key], array_key_exists('$', $arr2) ? $arr2['$'] : $arr2[$key]);
}
return $ret;
}
I use this code to filter data inside complex array
example:
$filter = [
'channels' => [
'$' => [
'id' => 1,
'type' => 1,
'count' => 1
]
],
'user' => [
'id' => 1,
'type' => 1
]
];
$data = [
'user' => [
'id' => '1234',
'type' => true,
'counter' => 14,
],
'filteredField' => 4,
'channels' => [
['id' => '567', 'type' => 'other', 'count' => 1345, 'filteredField' => 5,],
['id' => '890', 'type' => 'other', 'count' => 5456, 'filteredField' => 7,],
],
];
print_r(array_intersect_assoc_recursive($data, $filter));
test online: https://onlinephp.io/c/3be04
精彩评论