Completed
Push — master ( 85b5ae...49cec2 )
by Дмитрий
02:50
created

FunctionCall   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 12

Test Coverage

Coverage 36.75%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
c 6
b 0
f 0
dl 0
loc 226
ccs 61
cts 166
cp 0.3675
rs 8.295
wmc 42
lcom 0
cbo 12

2 Methods

Rating   Name   Duplication   Size   Complexity  
F compile() 0 201 40
A parseArgs() 0 10 2

How to fix   Complexity   

Complex Class

Complex classes like FunctionCall often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FunctionCall, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * PHP Smart Analysis project 2015-2016
4
 *
5
 * @author Patsura Dmitry https://github.com/ovr <[email protected]>
6
 */
7
8
namespace PHPSA\Compiler\Expression;
9
10
use Ovr\PHPReflection\Reflector;
11
use PHPSA\CompiledExpression;
12
use PHPSA\Context;
13
use PHPSA\Compiler\Expression;
14
15
class FunctionCall extends AbstractExpressionCompiler
16
{
17
    protected $name = 'PhpParser\Node\Expr\FuncCall';
18
19
    /**
20
     * @param \PhpParser\Node\Expr\FuncCall $expr
21
     * @param Context $context
22
     * @return CompiledExpression
23
     */
24 6
    protected function compile($expr, Context $context)
0 ignored issues
show
Complexity introduced by
This operation has 43488 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

You can also find more information in the “Code” section of your repository.

Loading history...
25
    {
26 6
        $expressionCompiler = $context->getExpressionCompiler();
27 6
        $fNameExpression = $expressionCompiler->compile($expr->name);
28
29 6
        if ($fNameExpression->isString() && $fNameExpression->isCorrectValue()) {
30 6
            $name = $fNameExpression->getValue();
31 6
        } else {
32
            $context->debug(
33
                'Unexpected function name type ' . $fNameExpression->getTypeName(),
34
                $expr->name
35
            );
36
37
            return new CompiledExpression;
38
        }
39
40 6
        $compiler = $context->application->compiler;
41
42 6
        $exists = false;
43 6
        $namespace = null;
44
45 6
        if ($context->scope) {
46 6
            $namespace = $context->scope->getNamespace();
47 6
        }
48
49 6
        if ($namespace === null) {
50
            $functionDefinition = $compiler->getFunction($name);
51
        } else {
52 6
            $functionDefinition = $compiler->getFunctionNS($name, $namespace);
53
        }
54
55 6
        if (!$functionDefinition) {
56 6
            $exists = function_exists($name);
57 6
        }
58
59 6
        if ($functionDefinition) {
60
            if (!$functionDefinition->isCompiled()) {
61
                $functionDefinition->compile(clone $context);
62
            }
63
64
            $exists = true;
65
        }
66
67 6
        $arguments = $this->parseArgs($expr, clone $context);
68
69 6
        if (!$functionDefinition) {
70 6
            $reflector = new Reflector(Reflector::manuallyFactory());
71 6
            $functionReflection = $reflector->getFunction($name);
72 6
            if ($functionReflection) {
73 3
                $argumentsSuccessPass = true;
74
75 3
                if (count($arguments) > 0) {
76 3
                    foreach ($arguments as $key => $argument) {
77 3
                        $parameter = $functionReflection->getParameter($key);
78 3
                        if (!$parameter) {
79
                            /**
80
                             * @todo Think a little bit more about it
81
                             */
82
                            continue;
83
                        }
84
85 3
                        switch ($parameter->getType()) {
86 3
                            case CompiledExpression::MIXED:
87
                                //continue
88 2
                                break;
89 1
                            case CompiledExpression::INTEGER:
90 1
                                switch ($argument->getType()) {
91 1
                                    case CompiledExpression::INTEGER:
92 1
                                        break;
93
                                    default:
94
                                        $argumentsSuccessPass = false;
95
                                        break;
96 1
                                }
97 1
                                break;
98
                            case CompiledExpression::DOUBLE:
99
                                switch ($argument->getType()) {
100
                                    case CompiledExpression::DOUBLE:
101
                                        break;
102
                                    default:
103
                                        $argumentsSuccessPass = false;
104
                                        break;
105
                                }
106
                                break;
107
                            case CompiledExpression::NUMBER:
108
                                switch ($argument->getType()) {
109
                                    case CompiledExpression::INTEGER:
110
                                    case CompiledExpression::STRING:
111
                                    case CompiledExpression::NUMBER:
112
                                        break;
113
                                    default:
114
                                        $argumentsSuccessPass = false;
115
                                        break;
116
                                }
117
                                break;
118
                            case CompiledExpression::RESOURCE:
119
                                switch ($argument->getType()) {
120
                                    case CompiledExpression::RESOURCE:
121
                                        break;
122
                                    default:
123
                                        $argumentsSuccessPass = false;
124
                                        break;
125
                                }
126
                                break;
127
                            case CompiledExpression::ARR:
128
                                switch ($argument->getType()) {
129
                                    case CompiledExpression::ARR:
130
                                        break;
131
                                    default:
132
                                        $argumentsSuccessPass = false;
133
                                        break;
134
                                }
135
                                break;
136
                            case CompiledExpression::STRING:
137
                                switch ($argument->getType()) {
138
                                    case CompiledExpression::STRING:
139
                                        break;
140
                                    default:
141
                                        $argumentsSuccessPass = false;
142
                                        break;
143
                                }
144
                                break;
145
                            case CompiledExpression::OBJECT:
146
                                switch ($argument->getType()) {
147
                                    case CompiledExpression::OBJECT:
148
                                        break;
149
                                    default:
150
                                        $argumentsSuccessPass = false;
151
                                        break;
152
                                }
153
                                break;
154
                            case CompiledExpression::BOOLEAN:
155
                                switch ($argument->getType()) {
156
                                    case CompiledExpression::OBJECT:
157
                                        break;
158
                                    default:
159
                                        $argumentsSuccessPass = false;
160
                                        break;
161
                                }
162
                                break;
163
                            case CompiledExpression::CALLABLE_TYPE:
164
                                switch ($argument->getType()) {
165
                                    case CompiledExpression::CALLABLE_TYPE:
166
                                        break;
167
                                    case CompiledExpression::STRING:
168
                                        /**
169
                                         * @todo We need additional check on it
170
                                         */
171
                                        break;
172
                                    /**
173
                                     * array($this, 'method')
174
                                     */
175
                                    case CompiledExpression::ARR:
176
                                        /**
177
                                         * @todo We need additional check on it
178
                                         */
179
                                        break;
180
                                    default:
181
                                        $argumentsSuccessPass = false;
182
                                        break;
183
                                }
184
                                break;
185
                            default:
186
                                $argumentsSuccessPass = false;
187
                                break;
188 3
                        }
189 3
                    }
190 3
                }
191
192 3
                if (count($arguments) < $functionReflection->getNumberOfRequiredParameters()) {
193
                    $argumentsSuccessPass = false;
194
                }
195
196 3
                if ($argumentsSuccessPass && $functionReflection->isRunnable()) {
197 3
                    array_walk(
198 3
                        $arguments,
199 3
                        function (&$item) {
200
                            /** @var CompiledExpression $item */
201 3
                            $item = $item->getValue();
202 3
                        }
203 3
                    );
204
205 3
                    return new CompiledExpression(
206 3
                        $functionReflection->getReturnType(),
207 3
                        $functionReflection->run($arguments)
208 3
                    );
209
                }
210
211
                return new CompiledExpression($functionReflection->getReturnType());
212
            }
213 5
        }
214
215 5
        if (!$exists) {
216
            $context->notice(
217
                'undefined-fcall',
218
                sprintf('Function %s() does not exist', $expr->name->parts[0]),
219
                $expr
220
            );
221
        }
222
223 5
        return new CompiledExpression();
224
    }
225
226
    /**
227
     * @param \PhpParser\Node\Expr\FuncCall $expr
228
     * @return CompiledExpression[]
229
     */
230 6
    protected function parseArgs($expr, Context $context)
231
    {
232 6
        $arguments = array();
233
234 6
        foreach ($expr->args as $argument) {
235 5
            $arguments[] = $context->getExpressionCompiler()->compile($argument->value);
236 6
        }
237
238 6
        return $arguments;
239
    }
240
}
241