Issues (10)

lib/AccessorReflection.php (6 issues)

1
<?php
2
3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ICanBoogie\Accessor;
13
14
use ReflectionClass;
15
use ReflectionException;
16
use ReflectionProperty;
17
18
use function array_merge;
19
use function get_class;
20
use function is_object;
21
use function method_exists;
22
23
/**
24
 * Provides methods to reflect on accessor.
25
 */
26
final class AccessorReflection
27
{
28
    /**
29
     * @var array<class-string, ReflectionProperty[]>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string, ReflectionProperty[]> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, ReflectionProperty[]>.
Loading history...
30
     */
31
    private static $private_properties_cache = [];
32
33
    /**
34
     * @var array<class-string, ReflectionProperty[]>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string, ReflectionProperty[]> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, ReflectionProperty[]>.
Loading history...
35
     */
36
    private static $facade_properties_cache = [];
37
38
    /**
39
     * @param class-string|object $reference
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|object at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|object.
Loading history...
40
     *
41
     * @return class-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
42
     */
43
    private static function resolve_reference($reference): string
44
    {
45
        if (is_object($reference)) {
46
            return get_class($reference);
47
        }
48
49
        return $reference;
50
    }
51
52
    /**
53
     * Returns the private properties defined by the reference, this includes the private
54
     * properties defined by the whole class inheritance.
55
     *
56
     * @param class-string|object $reference Class name or instance.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|object at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|object.
Loading history...
57
     *
58
     * @return ReflectionProperty[]
59
     *
60
     * @throws ReflectionException
61
     */
62
    public static function resolve_private_properties($reference): array
63
    {
64
        $reference = self::resolve_reference($reference);
65
        $cached = &self::$private_properties_cache[$reference];
66
67
        if ($cached) {
68
            return $cached;
69
        }
70
71
        $private_properties = [];
72
        $class_reflection = new ReflectionClass($reference);
73
74
        while ($class_reflection) {
75
            $private_properties[] = $class_reflection->getProperties(ReflectionProperty::IS_PRIVATE);
76
            $class_reflection = $class_reflection->getParentClass();
77
        }
78
79
        return $cached = $private_properties ? array_merge(...$private_properties) : []; // @phpstan-ignore-line
80
    }
81
82
    /**
83
     * Returns the façade properties implemented by the specified reference.
84
     *
85
     * A façade property is a combination of a private property with the corresponding volatile
86
     * getter and setter.
87
     *
88
     * @param class-string|HasAccessor $reference Class name or instance implementing {@link HasAccessor}.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|HasAccessor at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|HasAccessor.
Loading history...
89
     *
90
     * @return ReflectionProperty[]
91
     *
92
     * @throws ReflectionException
93
     */
94
    public static function resolve_facade_properties($reference): array
95
    {
96
        $reference = self::resolve_reference($reference);
97
        $facade_properties = &self::$facade_properties_cache[$reference];
98
99
        if ($facade_properties) {
100
            return $facade_properties;
101
        }
102
103
        $facade_properties = [];
104
105
        foreach (self::resolve_private_properties($reference) as $property) {
106
            $name = $property->name;
107
108
            if (
109
                !method_exists($reference, $reference::accessor_format($name, HasAccessor::ACCESSOR_TYPE_GETTER))
110
                || !method_exists($reference, $reference::accessor_format($name, HasAccessor::ACCESSOR_TYPE_SETTER))
111
            ) {
112
                continue;
113
            }
114
115
            $facade_properties[$name] = $property;
116
        }
117
118
        return $facade_properties;
119
    }
120
}
121