php
52 lines · 8 steps
Layered config merging in PHP
A resolver folds any number of override layers onto defaults with a recursive deep merge and list deduplication.
Explained by
highlit
1final class ConfigResolver
2{
3 private array $merged;
4
5 public function __construct(array $defaults, array ...$overrides)
6 {
7 $this->merged = array_reduce(
8 $overrides,
9 fn (array $carry, array $layer): array => $this->deepMerge($carry, $layer),
10 $defaults
11 );
12 }
13
14 public function all(): array
15 {
16 return $this->merged;
17 }
18
19 private function deepMerge(array $base, array $layer): array
20 {
21 foreach ($layer as $key => $value) {
22 if (is_int($key)) {
23 $base[] = $value;
24 continue;
25 }
26
27 if (is_array($value) && isset($base[$key]) && is_array($base[$key])) {
28 $base[$key] = $this->deepMerge($base[$key], $value);
29 continue;
30 }
31
32 $base[$key] = $value;
33 }
34
35 return $this->dedupeLists($base);
36 }
37
38 private function dedupeLists(array $config): array
39 {
40 foreach ($config as $key => $value) {
41 if (!is_array($value)) {
42 continue;
43 }
44
45 $config[$key] = array_is_list($value)
46 ? array_values(array_unique($value, SORT_REGULAR))
47 : $this->dedupeLists($value);
48 }
49
50 return $config;
51 }
52}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Folding layers with array_reduce turns any number of overrides into one clean accumulation.
- 2Distinguishing integer keys from string keys lets one merge routine handle both lists and maps.
- 3Recursing into nested arrays keeps deep structures merged rather than blindly overwritten.
Related explainers
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/layered-config-merging-in-php-explained-php-81f1/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.