PHP array_replace_recursive如果是标量,则array_merge_recursive如果是数组

时间:2016-02-22 11:40:25

标签: php arrays recursion array-merge scalar

我有一些默认配置,以及一些可配置的特定配置。我需要将特定配置合并到默认配置中。

  • 如果特定配置选项不存在,则 将使用默认选项。
  • 如果value是标量,则应应用特定配置
  • 如果value是标量数组,则应合并数组并应用array_unique。
  • 如果value是关联数组,我们需要应用上述scalarscalar_array规则。

示例:

$defaultConfigs = [
   'scalar1' => 1,
   'scalar2' => "Apple",
   'array_scalar' => [3,4,5],
   'array_associative' => [
      'scalar' => 1,
      'array_scalar' => [1,2,3],
      'array_associative' => [
          ...
      ]
   ],
];

$specificConfigs = [
   'scalar1' => "A",                          
   'array_scalar' => [3,4,5],   
   'array_associative' => [
      'scalar' => 1,
      'array_scalar' => [1,2,3],
      'array_associative' => [
          ...
      ]
   ],
];

预期产出:

$expectedConfigs = [
   'scalar1' => "A",                  // Overridden
   'scalar2' => "Apple",              // Default used
   'array_scalar' => [1,2,3,4,5],     // Scalar merged and array_unique
   'array_associative' => [
      'scalar' => "B",                // Overridden
      'array_scalar' => [1,2,3,4,5],  // Scalar merged and array_unique
      'array_associative' => [
          ...
      ]
   ],
];

有没有一个很好的清洁方法来实现这个目标?

3 个答案:

答案 0 :(得分:3)

此功能可获得所需的结果。它假设特定类型是具有默认类型的相干,因此不执行相干性检查。该函数迭代特定的配置数组并检查相应的默认值 1 :如果是标量,则替换默认值;如果它是枚举数组 2 ,它会合并唯一值;否则函数调用自身,当前值为参数。

function fillConfig( $default, $specific )
{
    foreach( $specific as $key=> $val )
    {
        if( isset( $default[$key] ) )
        {
            if( ! is_array( $default[$key] ) )
            {
                $default[$key] = $val;
            }
            elseif( array_keys($default[$key]) === range(0, count($default[$key]) - 1) )
            {
                $default[$key] = array_unique( array_merge( $default[$key], $val ) );
            }
            else
            {
                $default[$key] = fillConfig( $default[$key], $val );
            }
        }
        else
        {
            // This happens when a specific key doesn't exists in default configuration.
            // I think that in this case the value must be omitted,
            // otherwise you can un-comment following line:
            // $default[$key] = $val;
        }
    }
    return $default;
}

以这种方式调用函数:

$result = fillConfig( $defaultConfigs, $specificConfigs );
适用于您的数组示例的

$result是:

Array
(
    [scalar1] => A
    [scalar2] => Apple
    [array_scalar] => Array
        (
            [0] => 3
            [1] => 4
            [2] => 5
        )
    [array_associative] => Array
        (
            [scalar] => 1
            [array_scalar] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                )
            [array_associative] => Array
                (
                )
        )
)

使用这个数组:

$defaultConfigs = [
   'scalar1' => 1,
   'scalar2' => "Apple",
   'array_scalar' => [3,4,5],
   'array_associative' => [
      'scalar' => 1,
      'array_scalar' => [1,2,3],
      'array_associative' => [

      ]
   ],
];

$specificConfigs = [
   'scalar1' => "A",                          
   'array_scalar' => [3,4,5],   
   'array_associative' => [
      'scalar' => B,
      'array_scalar' => [3,4,5],
      'array_associative' => [

      ]
   ],
];

$result是:

Array
(
    [scalar1] => A
    [scalar2] => Apple
    [array_scalar] => Array
        (
            [0] => 3
            [1] => 4
            [2] => 5
        )

    [array_associative] => Array
        (
            [scalar] => B
            [array_scalar] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                    [4] => 4
                    [5] => 5
                )

            [array_associative] => Array
                (
                )

        )

)

注意:

1 是的,这有点不连贯:我觉得更好地迭代特定的数组(不存在的项目保持不变),但是对默认数组执行值检查,即参考点。 / p>

2 枚举/关联数组检查基于this answer

答案 1 :(得分:1)

我的情况略有不同,但可能会有所帮助。我需要在数组上替换标量和array_merge_recursive。

class ArrayUtil {

    public static function mergeRecursive(array $array1, $array2) {
        if($array2 && is_array($array2)) {
            foreach($array2 as $key => $val2) {
                if (is_array($val2) && (null!==($val1 = isset($array1[$key]) ? $array1[$key] : null)) && is_array($val1)) {
                    $array1[$key] = self::mergeRecursive($val1,$val2);
                } else {
                    $array1[$key] = $val2;
                }
            }
        }
        return $array1;
    }
}

答案 2 :(得分:0)

我用第一个答案重写了函数,用于配置数组:

private function mergeConfigs(array $configs): array
{
    $default = array_shift($configs);
    return array_reduce($configs, function (array $result, array $config) {
        foreach ($config as $key => $val) {
            if (!isset($result[$key]) || !is_array($result[$key])) {
                $result[$key] = $val;
                continue;
            }
            $result[$key] = array_keys($result[$key]) === range(0, count($result[$key]) - 1)
                ? array_unique(array_merge($result[$key], $val))
                : $this->mergeConfigs([$result[$key], $val]);
        }
        return $result;
    }, $default);
}