Completed
Push — master ( 8bff4b...55715d )
by Arnold
07:14
created

Helpers::descendObject()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 10
cc 3
nc 4
nop 4
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 116
    public static function &descend(&$subject, string $key, &$exists, bool $accessible = false, bool $copy = false)
25
    {
26 116
        if ($copy && is_object($subject)) {
27 11
            $subject = clone $subject;
28
        }
29
30 116
        if (\is_array($subject) || $subject instanceof \ArrayAccess) {
31 94
            return self::descendArray($subject, $key, $exists);
32
        } else {
33 38
            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 94
    private static function &descendArray(&$subject, string $key, &$exists)
44
    {
45 94
        $exists = \is_array($subject) ? \array_key_exists($key, $subject) : $subject->offsetExists($key);
46
47 94
        if ($exists) {
48 94
            $subject =& $subject[$key];
49
        }
50
51 94
        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 38
    private static function &descendObject(object &$subject, string $key, &$exists, bool $accessible)
62
    {
63 38
        $exists = $accessible
64 15
            ? self::propertyIsAccessible($subject, $key)
65 38
            : \property_exists($subject, $key);
66
67 38
        if ($exists) {
68 33
            $subject =& $subject->{$key};
69
        }
70
71 32
        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 15
    public static function propertyIsAccessible(object $object, string $property): bool
82
    {
83 15
        $exists = \property_exists($object, $property);
84
85 15
        if (!$exists || isset($object->{$property})) {
86 14
            return $exists;
87
        }
88
89
        try {
90 3
            $reflection = new \ReflectionProperty($object, $property);
91
        } catch (\ReflectionException $exception) { // @codeCoverageIgnore
92
            return false;                           // @codeCoverageIgnore
93
        }
94
95 3
        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 124
    public static function splitPath(string $path, string $delimiter): array
107
    {
108 124
        if ($delimiter === '') {
109 5
            throw new \InvalidArgumentException("Delimiter can't be an empty string");
110
        }
111
112
        /** @var array<int,string> $parts */
113 119
        $parts = \explode($delimiter, trim($path, $delimiter));
114
115 119
        return $parts;
116
    }
117
}
118