Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP array_replace_recursive if scalar, array_merge_recursive if 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?

like image 458
Gravy Avatar asked Feb 22 '16 11:02

Gravy


1 Answers

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.

like image 158
fusion3k Avatar answered Oct 20 '22 04:10

fusion3k