ReflectiveHydrator   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 50
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 9
eloc 17
c 3
b 0
f 0
dl 0
loc 50
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A writeTo() 0 8 3
A __construct() 0 2 1
A default() 0 3 1
A write() 0 16 4
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\Hydrator;
5
6
use ReflectionClass;
7
use ReflectionException;
8
use ReflectionObject;
9
use Throwable;
10
11
/**
12
 * Hydrator an inheriting object from array input.
13
 *
14
 * Slower than the default object hydrator, but useful in the context of
15
 * inheritance, when some of the properties are private to the parent class and
16
 * therefore inaccessible through simple closure binding.
17
 * @todo it can be done, by binding the closure with a class scope.
18
 * @todo find out if that improves performance
19
 *
20
 * @author  Stratadox
21
 */
22
final class ReflectiveHydrator implements Hydrator
23
{
24
    private function __construct()
25
    {
26
    }
27
28
    /**
29
     * Produce a reflective hydrator.
30
     *
31
     * @return Hydrator A hydrator that uses reflection to write properties.
32
     */
33
    public static function default(): Hydrator
34
    {
35
        return new ReflectiveHydrator;
36
    }
37
38
    /** @inheritdoc */
39
    public function writeTo(object $target, array $data): void
40
    {
41
        $object = new ReflectionObject($target);
42
        foreach ($data as $name => $value) {
43
            try {
44
                $this->write($object, $target, $name, $value);
45
            } catch (Throwable $exception) {
46
                throw HydrationFailed::encountered($exception, $target);
47
            }
48
        }
49
    }
50
51
    /**
52
     * @param mixed $value
53
     * @var ReflectionClass|bool $class
54
     * @throws ReflectionException
55
     */
56
    private function write(
57
        ReflectionClass $class,
58
        object $target,
59
        string $name,
60
        $value
61
    ): void {
62
        while ($class && !$class->hasProperty($name)) {
63
            $class = $class->getParentClass();
64
        }
65
        if (!$class) {
66
            $target->$name = $value;
67
            return;
68
        }
69
        $property = $class->getProperty($name);
70
        $property->setAccessible(true);
71
        $property->setValue($target, $value);
72
    }
73
}
74