schemator-php

Форк
0
/
ContainerAccessHelper.php 
333 строки · 9.8 Кб
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Smoren\Schemator\Helpers;
6

7
use ArrayAccess;
8
use Smoren\Schemator\Interfaces\ProxyInterface;
9
use Smoren\Schemator\Structs\ObjectPropertyProxy;
10
use stdClass;
11

12
/**
13
 * Tool for map-like accessing of different containers by string keys.
14
 *
15
 * Can access:
16
 *  - properties of objects (by name or by getter);
17
 *  - elements of arrays and ArrayAccess objects (by key).
18
 *
19
 * @template TKey of string|int
20
 * @template TValue of mixed
21
 */
22
class ContainerAccessHelper
23
{
24
    /**
25
     * Returns value from the container by key or default value if key does not exist or not accessible.
26
     *
27
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object|mixed $container
28
     * @param TKey $key
29
     * @param TValue|null $defaultValue
30
     *
31
     * @return TValue|null
32
     *
33
     * @throws \InvalidArgumentException
34
     */
35
    public static function get($container, $key, $defaultValue = null)
36
    {
37
        switch (true) {
38
            case is_array($container):
39
                return static::getFromArray($container, $key, $defaultValue);
40
            case $container instanceof ArrayAccess:
41
                return static::getFromArrayAccess($container, $key, $defaultValue);
42
            case is_object($container):
43
                return static::getFromObject($container, $key, $defaultValue);
44
        }
45

46
        return $defaultValue;
47
    }
48

49
    /**
50
     * Returns value from the container by key (sets and returns default value if key does not exist).
51
     *
52
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object|mixed $container
53
     * @param TKey $key
54
     * @param TValue|null $defaultValue
55
     *
56
     * @return TValue|ProxyInterface<TValue>|null
57
     *
58
     * @throws \InvalidArgumentException
59
     */
60
    public static function &getRef(&$container, $key, $defaultValue = null)
61
    {
62
        switch (true) {
63
            case is_array($container):
64
                return static::getRefFromArray($container, $key, $defaultValue);
65
            case $container instanceof ArrayAccess:
66
                return static::getRefFromArrayAccess($container, $key, $defaultValue);
67
            case is_object($container):
68
                return static::getRefFromObject($container, $key, $defaultValue);
69
        }
70

71
        $type = gettype($container);
72
        throw new \InvalidArgumentException("Cannot get ref to key '{$key}' from container of type '{$type}'");
73
    }
74

75
    /**
76
     * Sets value to the container by key.
77
     *
78
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object $container
79
     * @param TKey $key
80
     * @param TValue $value
81
     *
82
     * @return void
83
     *
84
     * @throws \InvalidArgumentException
85
     */
86
    public static function set(&$container, $key, $value): void
87
    {
88
        switch (true) {
89
            case is_array($container):
90
            case $container instanceof ArrayAccess:
91
                $container[$key] = $value;
92
                break;
93
            case is_object($container):
94
                static::setToObject($container, $key, $value);
95
                break;
96
            default:
97
                $type = gettype($container);
98
                throw new \InvalidArgumentException("Cannot set value to variable of type '{$type}'");
99
        }
100
    }
101

102
    /**
103
     * Deletes key from the container.
104
     *
105
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object $container
106
     * @param TKey $key
107
     *
108
     * @return void
109
     *
110
     * @throws \InvalidArgumentException
111
     */
112
    public static function delete(&$container, $key): void
113
    {
114
        switch (true) {
115
            case is_array($container):
116
                if (array_key_exists($key, $container)) {
117
                    unset($container[$key]);
118
                }
119
                break;
120
            case $container instanceof ArrayAccess:
121
                if ($container->offsetExists($key)) {
122
                    $container->offsetUnset($key);
123
                }
124
                break;
125
            case $container instanceof stdClass:
126
                unset($container->{$key});
127
                break;
128
            default:
129
                $type = gettype($container);
130
                throw new \InvalidArgumentException("Cannot delete key from variable of type '{$type}'");
131
        }
132
    }
133

134
    /**
135
     * Returns true if the accessible key exists in the container.
136
     *
137
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object|mixed $container
138
     * @param TKey $key
139
     *
140
     * @return bool
141
     */
142
    public static function exist($container, $key): bool
143
    {
144
        switch (true) {
145
            case is_array($container):
146
                return static::existsInArray($container, $key);
147
            case $container instanceof ArrayAccess:
148
                return static::existsInArrayAccess($container, $key);
149
            case is_object($container):
150
                return static::existsInObject($container, $key);
151
        }
152
        return false;
153
    }
154

155
    /**
156
     * @param mixed $container
157
     * @return bool
158
     */
159
    public static function isArrayAccessible($container): bool
160
    {
161
        return is_array($container) || ($container instanceof ArrayAccess);
162
    }
163

164
    /**
165
     * Returns value from the array by key or default value if key does not exist.
166
     *
167
     * @param array<TKey, TValue> $container
168
     * @param TKey $key
169
     * @param TValue|null $defaultValue
170
     *
171
     * @return TValue|null
172
     */
173
    protected static function getFromArray(array $container, $key, $defaultValue)
174
    {
175
        if (static::existsInArray($container, $key)) {
176
            return $container[$key];
177
        }
178

179
        return $defaultValue ?? null;
180
    }
181

182
    /**
183
     * Returns reference to value from the array by key (sets and returns default value if key does not exist).
184
     *
185
     * @param array<TKey, TValue> $container
186
     * @param TKey $key
187
     * @param TValue|null $defaultValue
188
     *
189
     * @return TValue|null
190
     */
191
    protected static function &getRefFromArray(array &$container, $key, $defaultValue)
192
    {
193
        if (!static::existsInArray($container, $key)) {
194
            $container[$key] = $defaultValue;
195
        }
196

197
        return $container[$key];
198
    }
199

200
    /**
201
     * Returns true if the key exists in the array.
202
     *
203
     * @param array<TKey, TValue> $container
204
     * @param TKey $key
205
     *
206
     * @return bool
207
     */
208
    protected static function existsInArray(array $container, $key): bool
209
    {
210
        return array_key_exists($key, $container);
211
    }
212

213
    /**
214
     * Returns value from the ArrayAccess object by key or default value if key does not exist.
215
     *
216
     * @param ArrayAccess<TKey, TValue> $container
217
     * @param TKey $key
218
     * @param TValue|null $defaultValue
219
     *
220
     * @return TValue|null
221
     */
222
    protected static function getFromArrayAccess(ArrayAccess $container, $key, $defaultValue)
223
    {
224
        if (static::existsInArrayAccess($container, $key)) {
225
            return $container[$key];
226
        }
227

228
        return $defaultValue ?? null;
229
    }
230

231
    /**
232
     * Returns reference to value from the ArrayAccess object by key
233
     * (sets and returns default value if key does not exist).
234
     *
235
     * @param ArrayAccess<TKey, TValue> $container
236
     * @param TKey $key
237
     * @param TValue|null $defaultValue
238
     *
239
     * @return TValue|null
240
     */
241
    protected static function &getRefFromArrayAccess(ArrayAccess &$container, $key, $defaultValue)
242
    {
243
        if (!static::existsInArrayAccess($container, $key)) {
244
            /** @var TValue $defaultValue */
245
            $container[$key] = $defaultValue;
246
        }
247

248
        return $container[$key];
249
    }
250

251
    /**
252
     * Returns true if the key exists in the ArrayAccess object.
253
     *
254
     * @param ArrayAccess<TKey, TValue> $container
255
     * @param TKey $key
256
     *
257
     * @return bool
258
     */
259
    protected static function existsInArrayAccess(ArrayAccess $container, $key): bool
260
    {
261
        return $container->offsetExists($key);
262
    }
263

264
    /**
265
     * Returns value from the object by key or default value if key does not exist.
266
     *
267
     * @param object $container
268
     * @param TKey $key
269
     * @param TValue|null $defaultValue
270
     *
271
     * @return TValue|null
272
     *
273
     * @throws \InvalidArgumentException
274
     */
275
    protected static function getFromObject(object $container, $key, $defaultValue)
276
    {
277
        if (ObjectAccessHelper::hasReadableProperty($container, strval($key))) {
278
            return ObjectAccessHelper::getPropertyValue($container, strval($key));
279
        }
280

281
        return $defaultValue;
282
    }
283

284
    /**
285
     * Returns value from the object by key or default value if key does not exist.
286
     *
287
     * @param object $container
288
     * @param TKey $key
289
     * @param TValue|null $defaultValue
290
     *
291
     * @return TValue|ProxyInterface<TValue>|null
292
     *
293
     * @throws \InvalidArgumentException
294
     */
295
    protected static function &getRefFromObject(object &$container, $key, $defaultValue)
296
    {
297
        return ObjectAccessHelper::getPropertyRef($container, strval($key), $defaultValue);
298
    }
299

300
    /**
301
     * Sets property value to the object if it is writable by name or by setter.
302
     *
303
     * @param object $container
304
     * @param TKey $key
305
     * @param TValue $value
306
     *
307
     * @return void
308
     *
309
     * @throws \InvalidArgumentException
310
     */
311
    protected static function setToObject(object $container, $key, $value): void
312
    {
313
        if (!ObjectAccessHelper::hasWritableProperty($container, strval($key)) && !($container instanceof stdClass)) {
314
            $className = get_class($container);
315
            throw new \InvalidArgumentException("Property '{$className}::{$key}' is not writable");
316
        }
317

318
        ObjectAccessHelper::setPropertyValue($container, strval($key), $value);
319
    }
320

321
    /**
322
     * Returns true if the key exists in the object.
323
     *
324
     * @param object $container
325
     * @param TKey $key
326
     *
327
     * @return bool
328
     */
329
    protected static function existsInObject(object $container, $key): bool
330
    {
331
        return ObjectAccessHelper::hasReadableProperty($container, strval($key));
332
    }
333
}
334

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.