Navigation

Php

How to Merge Arrays with array_merge() vs +

Understand the crucial differences between array_merge() and the + operator for combining PHP arrays - they handle keys and values differently.

Table Of Contents

Here's How

Array merging behavior depends on whether you use array_merge() or the + operator. The key difference lies in how they handle duplicate keys and whether they preserve or renumber array indexes.

<?php

// Basic array_merge() - renumbers numeric keys
$array1 = ['a', 'b', 'c'];
$array2 = ['d', 'e', 'f'];

$merged = array_merge($array1, $array2);
// Result: ['a', 'b', 'c', 'd', 'e', 'f'] (keys: 0,1,2,3,4,5)

// Plus operator - preserves keys, left array wins conflicts
$combined = $array1 + $array2;
// Result: ['a', 'b', 'c'] (keys: 0,1,2 - $array2 values ignored!)

// Associative arrays with array_merge()
$config1 = ['host' => 'localhost', 'port' => 3306, 'debug' => true];
$config2 = ['port' => 5432, 'ssl' => true, 'timeout' => 30];

$mergedConfig = array_merge($config1, $config2);
// Result: ['host' => 'localhost', 'port' => 5432, 'debug' => true, 'ssl' => true, 'timeout' => 30]

// Plus operator with associative arrays
$combinedConfig = $config1 + $config2;
// Result: ['host' => 'localhost', 'port' => 3306, 'debug' => true, 'ssl' => true, 'timeout' => 30]

// Complex example showing key differences
$users1 = [
    0 => 'John',
    1 => 'Jane',
    'admin' => 'Alice'
];

$users2 = [
    0 => 'Bob',
    2 => 'Charlie',
    'admin' => 'Eve'
];

// array_merge() renumbers numeric keys, overwrites string keys
$mergedUsers = array_merge($users1, $users2);
// Result: [0 => 'John', 1 => 'Jane', 2 => 'Alice', 3 => 'Bob', 4 => 'Charlie', 'admin' => 'Eve']

// Plus operator preserves all keys, left side wins
$combinedUsers = $users1 + $users2;
// Result: [0 => 'John', 1 => 'Jane', 'admin' => 'Alice', 2 => 'Charlie']

// Practical examples

// Merging configuration with defaults
function mergeWithDefaults(array $userConfig, array $defaults): array {
    // Use array_merge to let user config override defaults
    return array_merge($defaults, $userConfig);
}

$defaults = [
    'timeout' => 30,
    'retries' => 3,
    'debug' => false
];

$userConfig = [
    'timeout' => 60,
    'debug' => true
];

$finalConfig = mergeWithDefaults($userConfig, $defaults);
// Result: ['timeout' => 60, 'retries' => 3, 'debug' => true]

// Adding fallback options
function addFallbacks(array $primary, array $fallbacks): array {
    // Use + operator to preserve primary values
    return $primary + $fallbacks;
}

$primarySettings = ['theme' => 'dark', 'language' => 'en'];
$fallbackSettings = ['theme' => 'light', 'language' => 'en', 'timezone' => 'UTC'];

$settings = addFallbacks($primarySettings, $fallbackSettings);
// Result: ['theme' => 'dark', 'language' => 'en', 'timezone' => 'UTC']

// Merging multiple arrays
$data1 = ['name' => 'John', 'age' => 30];
$data2 = ['email' => 'john@example.com', 'age' => 31];
$data3 = ['phone' => '123-456-7890', 'city' => 'New York'];

// Multiple array_merge
$allData = array_merge($data1, $data2, $data3);
// Result: ['name' => 'John', 'age' => 31, 'email' => 'john@example.com', 'phone' => '123-456-7890', 'city' => 'New York']

// Chain plus operators (order matters!)
$chainedData = $data1 + $data2 + $data3;
// Result: ['name' => 'John', 'age' => 30, 'email' => 'john@example.com', 'phone' => '123-456-7890', 'city' => 'New York']

// Working with nested arrays
$template = [
    'database' => ['host' => 'localhost', 'port' => 3306],
    'cache' => ['enabled' => true]
];

$environment = [
    'database' => ['host' => 'prod-db', 'ssl' => true],
    'logging' => ['level' => 'error']
];

// Simple merge (overwrites nested arrays completely)
$simpleConfig = array_merge($template, $environment);
// database array from $environment completely replaces template's database

// Recursive merge for nested arrays
function mergeRecursive(array $array1, array $array2): array {
    foreach ($array2 as $key => $value) {
        if (is_array($value) && isset($array1[$key]) && is_array($array1[$key])) {
            $array1[$key] = mergeRecursive($array1[$key], $value);
        } else {
            $array1[$key] = $value;
        }
    }
    return $array1;
}

$recursiveConfig = mergeRecursive($template, $environment);
// Result: database array is merged, not replaced

// Performance comparison for large arrays
function benchmarkMerging(array $arr1, array $arr2, int $iterations = 1000): array {
    // Test array_merge
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $result = array_merge($arr1, $arr2);
    }
    $mergeTime = microtime(true) - $start;
    
    // Test plus operator
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $result = $arr1 + $arr2;
    }
    $plusTime = microtime(true) - $start;
    
    return [
        'array_merge' => $mergeTime,
        'plus_operator' => $plusTime,
        'winner' => $plusTime < $mergeTime ? 'plus (+)' : 'array_merge()'
    ];
}

// Usage examples
$products = ['laptop', 'mouse', 'keyboard'];
$accessories = ['webcam', 'speakers'];

// When you want all items with renumbered keys
$allItems = array_merge($products, $accessories);
echo "All items: " . implode(', ', $allItems) . "\n";

// When you want to preserve original keys
$preservedKeys = $products + $accessories;
print_r($preservedKeys);

// Configuration merging
$defaultSettings = [
    'api_url' => 'https://api.example.com',
    'timeout' => 30,
    'retries' => 3,
    'debug' => false
];

$userSettings = [
    'timeout' => 60,
    'debug' => true,
    'api_key' => 'secret123'
];

// Override defaults with user settings
$appSettings = array_merge($defaultSettings, $userSettings);
echo "Final timeout: " . $appSettings['timeout'] . "\n"; // 60

// Add user settings but keep defaults for missing values
$fallbackSettings = $userSettings + $defaultSettings;
echo "Fallback timeout: " . $fallbackSettings['timeout'] . "\n"; // 60

Key Points

The fundamental difference is in key handling: array_merge() renumbers numeric keys sequentially and overwrites string keys with later values, while the + operator preserves all original keys and ignores duplicate keys from the right-side array.

Use array_merge() when you want to combine all values and don't care about preserving original numeric indexes. It's perfect for concatenating lists or overriding configuration values.

Use the + operator when you need to preserve keys or want left-side precedence. It's ideal for providing default values or maintaining specific array structures. Remember that with +, the left array always wins conflicts, making it perfect for fallback scenarios.

Share this article

Add Comment

No comments yet. Be the first to comment!

More from Php