Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Array Merge Recursive Laravel Package

rikudou/array-merge-recursive

A lightweight PHP utility for recursively merging arrays with predictable results. It combines nested structures while letting later values take precedence, making it useful for configs, defaults, and deep data composition. Framework-agnostic and easy to use.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install:

    composer require rikudou/array-merge-recursive
    
  2. Read src/ArrayMergeRecursive.php first. This is a one-class package — the entire behaviour lives in a single recursive method, so 60 seconds of reading gives you the full contract. Skim the composer.json for the PHP constraint and the (only) release tag (2021-04-22, so expect no forward-compatibility fixes).

  3. First use case — the one it was written for: replace PHP's built-in array_merge_recursive in a config loader, where duplicate string keys must overwrite instead of being turned into a nested array.

    // The problem with the built-in:
    array_merge_recursive(['db' => ['host' => 'localhost']], ['db' => ['host' => 'prod']]);
    // ['db' => ['host' => ['localhost', 'prod']]]  <-- not what anyone wants
    
    // What this package gives you:
    ArrayMergeRecursive::merge(['db' => ['host' => 'localhost']], ['db' => ['host' => 'prod']]);
    // ['db' => ['host' => 'prod']]
    

    Confirm the facade name/signature in src/ on day one (it mirrors array_merge_recursive's variadic shape: one or more arrays in, one array out).

Implementation Patterns

Config overlay (the 90% case). Layer defaults → environment → user overrides in order; later arguments win at the leaf:

$config = ArrayMergeRecursive::merge(
    require base_path('config/package.php'),   // package defaults
    require config_path('package.php'),         // published overrides
);

Laravel service provider / config repository. Because the package has no ServiceProvider and no auto-discovery, wire it manually wherever you currently call array_merge_recursive:

public function register()
{
    $this->mergeConfigFrom(base_path('config/defaults.php'), 'package');
    // replace the shallow merge with:
    config(['package' => ArrayMergeRecursive::merge(
        config('package'),
        require base_path('config/shared.php'),
    )]);
}

Merging JSON-decoded payloads before validation. When json_decode(..., true) gives you assoc arrays that share string keys but differ in nesting, this preserves structure instead of producing [old, new] pairs that then fail required|string validation unexpectedly.

DTO / SDK option resolution. Same pattern for building an options array (['retry' => ['attempts' => 2]]) from a base and a caller-supplied array — you want deep merge but scalar replacement, which is exactly the difference between this and array_merge_recursive.

Workflow rule of thumb. Use it wherever you catch yourself writing a recursive foreach that does $a[$k] = is_array($v) && isset($a[$k]) && is_array($a[$k]) ? merge($a[$k], $v) : $v;. Reach for the package instead; it's the same algorithm without the reimplementation drift.

Gotchas and Tips

  • Check array_replace_recursive first. PHP's built-in already replaces scalar string keys and recurses into arrays. The real difference shows up on numeric/list keys and on scalar↔array collisions — test those two cases explicitly against your expected output before committing to the dependency. If array_replace_recursive matches your needs, drop the dependency entirely.
  • Order is semantics. merge($base, $override) means $override wins. Reverse the arguments and you get the opposite; there's no "priority" flag, only argument order.
  • Numeric keys. Expect list-merge semantics to be the sharp edge: appending vs. positional replacement can differ from both built-ins. Write one assertion test per shape (list at root, list nested, mixed scalar/array at same key) and pin them — you cannot assume the 2021 behaviour matches your mental model.
  • Scalar vs. array collision. If one side is 'x' and the other ['y' => 1], only one type can survive. Verify which wins in src/; the built-ins disagree with each other here and this package may follow either.
  • No null/null handling, no type juggling. It's array-in, array-out; passing null or an ArrayAccess object is your problem, not the package's. Guard at the call site.
  • WTFPL + 2021 + zero dependents. No security fix pipeline, no PHP 8.x release guarantee, no issue triage. Pin the exact version in composer.lock, and if you're on a modern PHP with declare(strict_types=1) across the codebase, run the test suite once to confirm the untyped signature accepts your arguments.
  • Debugging. When output looks wrong, var_dump the inputs side by side first — the failure is almost always a numeric-key collision or a scalar/array mismatch, not the recursion itself. Then dump the merged result and diff key paths.
  • Extension point. Fork-and-own is the realistic extension strategy: the class is small enough that if you need "replace on string keys, append on numeric keys" (or the inverse), patching the single recursive method is a 10-line change — and more maintainable than wrapping the package with adapter layers.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource