recursive if scalar, array

I have some default configurations, and some specific configurations which would be configurable. I need to merge the specific configurations into the default configurations.

  • In the case that the specific config option does not exist, the default option will be used.
  • In the case that the value is a scalar, the specific configuration should be applied
  • In the case that the value is a scalar array, the arrays should be merged and array_unique applied.
  • In the case that the value is an associative array, We need to apply the above scalar and scalar_array rules.
  • Example:

    $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' => [
              ...
          ]
       ],
    ];
    

    Expected Output:

    $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' => [
              ...
          ]
       ],
    ];
    

    Is there a nice clean way of achieving this?


    This function obtains your desired result. It assume that specific types are coherents with default types, so no coherence check is performed. The function iterate specific configuration array and check corresponding default value1: if it is scalar, replace default value; if it is a enumerated array2, it merge unique values; otherwise function call itself with current values as arguments.

    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;
    }
    

    Calling the function in this way:

    $result = fillConfig( $defaultConfigs, $specificConfigs );
    

    $result , applied to your arrays sample, is this:

    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
                    (
                    )
            )
    )
    

    With this array couple:

    $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 is:

    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
                    (
                    )
    
            )
    
    )
    

    Notes:

    1 Yes, this is a bit incoherent: I felt was better iterate through specific array (not existent items remain untouched), but performing value check on default array, that is the reference point.

    2 The enumerated/associative array check is based on this answer.


    My case was slightly different but it might be of help. I needed to replace scalars and array_merge_recursive on arrays.

    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;
        }
    }
    

    我使用config数组重新编写了第一个答案中的函数:

    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);
    }
    
    链接地址: http://www.djcxy.com/p/32164.html

    上一篇: 有没有办法从文档中隐藏Rust宏模式?

    下一篇: 递归如果标量,数组