Passed
Push — master ( 893d1e...31005e )
by Kirill
03:35
created

ReflectionArgument::locateArguments()   C

Complexity

Conditions 12
Paths 36

Size

Total Lines 57
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 34
c 0
b 0
f 0
dl 0
loc 57
rs 6.9666
cc 12
nc 36
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Tokenizer\Reflection;
13
14
use Spiral\Tokenizer\Exception\ReflectionException;
15
16
/**
17
 * Represent argument using in method or function invocation with it's type and value.
18
 */
19
final class ReflectionArgument
20
{
21
    /**
22
     * Argument types.
23
     */
24
    public const CONSTANT   = 'constant';   //Scalar constant and not variable.
25
    public const VARIABLE   = 'variable';   //PHP variable
26
    public const EXPRESSION = 'expression'; //PHP code (expression).
27
    public const STRING     = 'string';     //Simple scalar string, can be fetched using stringValue().
28
29
    /** @var string */
30
    private $type;
31
32
    /** @var string */
33
    private $value;
34
35
    /**
36
     * New instance of ReflectionArgument.
37
     *
38
     * @param string $type  Argument type (see top constants).
39
     * @param string $value Value in a form of php code.
40
     */
41
    public function __construct($type, string $value)
42
    {
43
        $this->type = $type;
44
        $this->value = $value;
45
    }
46
47
    /**
48
     * @return string
49
     */
50
    public function getType(): string
51
    {
52
        return $this->type;
53
    }
54
55
    /**
56
     * @return string
57
     */
58
    public function getValue(): string
59
    {
60
        return $this->value;
61
    }
62
63
    /**
64
     * Convert argument value into valid string. Can be applied only for STRING type arguments.
65
     *
66
     * @return string
67
     *
68
     * @throws ReflectionException When value can not be converted into string.
69
     */
70
    public function stringValue(): string
71
    {
72
        if ($this->type != self::STRING) {
73
            throw new ReflectionException(
74
                "Unable to represent value as string, value type is '{$this->type}'"
75
            );
76
        }
77
78
        //The most reliable way
79
        return eval("return {$this->value};");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
80
    }
81
82
    /**
83
     * Create Argument reflections based on provided set of tokens (fetched from invoke).
84
     *
85
     * @param array $tokens
86
     * @return self[]
87
     */
88
    public static function locateArguments(array $tokens): array
89
    {
90
        $definition = null;
91
        $level = 0;
92
93
        $result = [];
94
        foreach ($tokens as $token) {
95
            if ($token[ReflectionFile::TOKEN_TYPE] == T_WHITESPACE) {
96
                continue;
97
            }
98
99
            if (empty($definition)) {
100
                $definition = ['type' => self::EXPRESSION, 'value' => '', 'tokens' => []];
101
            }
102
103
            if (
104
                $token[ReflectionFile::TOKEN_TYPE] == '('
105
                || $token[ReflectionFile::TOKEN_TYPE] == '['
106
            ) {
107
                ++$level;
108
                $definition['value'] .= $token[ReflectionFile::TOKEN_CODE];
109
                continue;
110
            }
111
112
            if (
113
                $token[ReflectionFile::TOKEN_TYPE] == ')'
114
                || $token[ReflectionFile::TOKEN_TYPE] == ']'
115
            ) {
116
                --$level;
117
                $definition['value'] .= $token[ReflectionFile::TOKEN_CODE];
118
                continue;
119
            }
120
121
            if ($level) {
122
                $definition['value'] .= $token[ReflectionFile::TOKEN_CODE];
123
                continue;
124
            }
125
126
            if ($token[ReflectionFile::TOKEN_TYPE] == ',') {
127
                $result[] = self::createArgument($definition);
128
                $definition = null;
129
                continue;
130
            }
131
132
            $definition['tokens'][] = $token;
133
            $definition['value'] .= $token[ReflectionFile::TOKEN_CODE];
134
        }
135
136
        //Last argument
137
        if (is_array($definition)) {
138
            $definition = self::createArgument($definition);
139
            if (!empty($definition->getType())) {
140
                $result[] = $definition;
141
            }
142
        }
143
144
        return $result;
145
    }
146
147
    /**
148
     * Create Argument reflection using token definition. Internal method.
149
     *
150
     * @see locateArguments
151
     * @param array $definition
152
     * @return self
153
     */
154
    private static function createArgument(array $definition): ReflectionArgument
155
    {
156
        $result = new static(self::EXPRESSION, $definition['value']);
157
158
        if (count($definition['tokens']) == 1) {
159
            //If argument represent by one token we can try to resolve it's type more precisely
160
            switch ($definition['tokens'][0][0]) {
161
                case T_VARIABLE:
162
                    $result->type = self::VARIABLE;
163
                    break;
164
                case T_LNUMBER:
165
                case T_DNUMBER:
166
                    $result->type = self::CONSTANT;
167
                    break;
168
                case T_CONSTANT_ENCAPSED_STRING:
169
                    $result->type = self::STRING;
170
                    break;
171
            }
172
        }
173
174
        return $result;
175
    }
176
}
177