Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
MergePatch
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
2 / 2
8
100.00% covered (success)
100.00%
1 / 1
 apply
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 isObject
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Api;
6
7/**
8 * JSON Merge Patch (RFC 7396): objects merge member by member, null removes
9 * a member, and anything else, lists included, replaces the target.
10 */
11final class MergePatch
12{
13    public static function apply(mixed $target, mixed $patch): mixed
14    {
15        if (!self::isObject($patch)) {
16            return $patch;
17        }
18
19        $result = self::isObject($target) ? $target : [];
20
21        foreach ($patch as $key => $value) {
22            if ($value === null) {
23                unset($result[$key]);
24
25                continue;
26            }
27
28            $result[$key] = self::apply($result[$key] ?? null, $value);
29        }
30
31        return $result;
32    }
33
34    /** @phpstan-assert-if-true array<array-key, mixed> $value */
35    private static function isObject(mixed $value): bool
36    {
37        return is_array($value) && ($value === [] || !array_is_list($value));
38    }
39}