Completed
Pull Request — 2.x (#216)
by Akihito
09:22
created

Normalizer::__invoke()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
c 0
b 0
f 0
rs 8.6026
cc 7
nc 6
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Compiler;
6
7
use PhpParser\Node;
8
use PhpParser\Node\Arg;
9
use PhpParser\Node\Expr;
10
use PhpParser\Node\Scalar;
11
use Ray\Compiler\Exception\InvalidInstance;
12
use Ray\Di\InjectorInterface;
13
14
/**
15
 * Value to code(Node) converter
16
 */
17
final class Normalizer
18
{
19
    /**
20
     * Normalizes a value: Converts nulls, booleans, integers,
21
     * floats, strings and arrays into their respective nodes
22
     *
23
     * @param mixed $value The value to normalize
24
     *
25
     * @return Expr The normalized value
26
     */
27
    public function __invoke($value) : Expr
28
    {
29
        if ($value === null) {
30
            return new Expr\ConstFetch(
31
                new Node\Name('null')
32
            );
33
        }
34
        if (\is_bool($value)) {
35
            return new Expr\ConstFetch(
36
                new Node\Name($value ? 'true' : 'false')
37
            );
38
        }
39
        if (\is_int($value)) {
40
            return new Scalar\LNumber($value);
41
        }
42
        if (\is_float($value)) {
43
            return new Scalar\DNumber($value);
44
        }
45
        if (\is_string($value)) {
46
            return new Scalar\String_($value);
47
        }
48
49
        return $this->noScalar($value);
50
    }
51
52
    /**
53
     * Return array or object node
54
     *
55
     * @param array<mixed>|mixed|object $value
56
     *
57
     * @return Expr\Array_|Expr\FuncCall
58
     */
59
    private function noScalar($value) : Expr
60
    {
61
        if (\is_array($value)) {
62
            return $this->arrayValue($value);
63
        }
64
        if (\is_object($value)) {
65
            return $this->normalizeObject($value);
66
        }
67
68
        throw new InvalidInstance;
69
    }
70
71
    /**
72
     * Return "unserialize($object)" node
73
     *
74
     * @param object $object
75
     */
76
    private function normalizeObject($object) : Expr\FuncCall
77
    {
78
        if ($object instanceof InjectorInterface) {
79
            return new Expr\FuncCall(new Expr\Variable('injector'));
80
        }
81
        $serialize = new Scalar\String_(\serialize($object));
82
83
        return new Expr\FuncCall(new Node\Name('unserialize'), [new Arg($serialize)]);
84
    }
85
86
    /**
87
     * Return array value node
88
     *
89
     * @param array<int, mixed> $value
90
     */
91
    private function arrayValue($value) : Expr\Array_
92
    {
93
        $items = [];
94
        $lastKey = -1;
95
        foreach ($value as $itemKey => $itemValue) {
96
            // for consecutive, numeric keys don't generate keys
97
            if (null !== $lastKey && ++$lastKey === $itemKey) {
98
                $items[] = new Expr\ArrayItem(
99
                    $this->__invoke($itemValue)
100
                );
101
            } else {
102
                $lastKey = null;
103
                $items[] = new Expr\ArrayItem(
104
                    $this->__invoke($itemValue),
105
                    $this->__invoke($itemKey)
106
                );
107
            }
108
        }
109
110
        return new Expr\Array_($items);
111
    }
112
}
113