Helpers::descendArray()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
cc 3
nc 4
nop 3
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Jasny\DotKey\Internal;
6
7
/**
8
 * Static class with helper functions.
9
 * @internal
10
 */
11
final class Helpers
12
{
13
    /**
14
     * Make subject a child of the subject.
15
     * If `$exists` is false, it wasn't possible to decent and subject is returned.
16
     *
17
     * @param object|array<string,mixed> $subject
18
     * @param string                     $key
19
     * @param mixed                      $exists      output as bool
20
     * @param bool                       $accessible  Check not only if property exists, but also is accessible.
21
     * @param bool                       $copy        Copy objects
22
     * @return mixed
23
     */
24 126
    public static function &descend(&$subject, string $key, &$exists, bool $accessible = false, bool $copy = false)
25
    {
26 126
        if ($copy && is_object($subject)) {
27 12
            $subject = clone $subject;
28
        }
29
30 126
        if (\is_array($subject) || $subject instanceof \ArrayAccess) {
31 100
            return self::descendArray($subject, $key, $exists);
32
        } else {
33 42
            return self::descendObject($subject, $key, $exists, $accessible);
34
        }
35
    }
36
37
    /**
38
     * @param array<string,mixed>|\ArrayAccess<string,mixed> $subject
39
     * @param string                                         $key
40
     * @param mixed                                          $exists
41
     * @return mixed
42
     */
43 100
    private static function &descendArray(&$subject, string $key, &$exists)
44
    {
45 100
        $exists = \is_array($subject) ? \array_key_exists($key, $subject) : $subject->offsetExists($key);
46
47 100
        if ($exists) {
48 100
            $subject =& $subject[$key];
49
        }
50
51 100
        return $subject;
52
    }
53
54
    /**
55
     * @param object $subject
56
     * @param string $key
57
     * @param mixed  $exists
58
     * @param bool   $accessible
59
     * @return mixed
60
     */
61 42
    private static function &descendObject(object &$subject, string $key, &$exists, bool $accessible)
62
    {
63 42
        $exists = $accessible
64 17
            ? self::propertyIsAccessible($subject, $key)
65 34
            : \property_exists($subject, $key);
66
67 42
        if ($exists) {
68 37
            $subject =& $subject->{$key};
69
        }
70
71 36
        return $subject;
72
    }
73
74
    /**
75
     * Check if property exists and is accessible.
76
     *
77
     * @param object $object
78
     * @param string $property
79
     * @return bool
80
     */
81 17
    public static function propertyIsAccessible(object $object, string $property): bool
82
    {
83 17
        $exists = \property_exists($object, $property);
84
85 17
        if (!$exists || isset($object->{$property})) {
86 16
            return $exists;
87
        }
88
89
        try {
90 4
            $reflection = new \ReflectionProperty($object, $property);
91
        } catch (\ReflectionException $exception) { // @codeCoverageIgnore
92
            return false;                           // @codeCoverageIgnore
93
        }
94
95 4
        return $reflection->isPublic() && !$reflection->isStatic();
96
    }
97
98
    /**
99
     * Explode with trimming and check.
100
     * @see explode()
101
     *
102
     * @param string $path
103
     * @param string $delimiter
104
     * @return string[]
105
     */
106 134
    public static function splitPath(string $path, string $delimiter): array
107
    {
108 134
        if ($delimiter === '') {
109 5
            throw new \InvalidArgumentException("Delimiter can't be an empty string");
110
        }
111
112
        /** @var array<int,string> $parts */
113 129
        $parts = \explode($delimiter, trim($path, $delimiter));
114
115 129
        return $parts;
116
    }
117
}
118