Completed
Push — master ( 5a98e1...9d14a0 )
by Дмитрий
02:33
created

ClassMethod::run()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 3
eloc 5
c 4
b 1
f 0
nc 2
nop 2
dl 0
loc 10
ccs 0
cts 7
cp 0
crap 12
rs 9.4285
1
<?php
2
/**
3
 * @author Patsura Dmitry https://github.com/ovr <[email protected]>
4
 */
5
6
namespace PHPSA\Definition;
7
8
use PhpParser\Node;
9
use PHPSA\CompiledExpression;
10
use PHPSA\Compiler\Expression;
11
use PHPSA\Compiler\Parameter;
12
use PHPSA\Compiler\Types;
13
use PHPSA\Context;
14
15
class ClassMethod extends AbstractDefinition
16
{
17
    protected $type;
18
19
    /**
20
     * @var Node\Stmt\ClassMethod
21
     */
22
    protected $statement;
23
24
    /**
25
     * Return type
26
     *
27
     * @var int
28
     */
29
    protected $returnType = CompiledExpression::VOID;
30
31
    /**
32
     * Array of possible return values
33
     *
34
     * @var array
35
     */
36
    protected $possibleReturnValues = array();
37
38
    /**
39
     * @param $name
40
     * @param Node\Stmt\ClassMethod $statement
41
     * @param $type
42
     */
43 1
    public function __construct($name, Node\Stmt\ClassMethod $statement, $type)
44
    {
45 1
        $this->name = $name;
46 1
        $this->statement = $statement;
47 1
        $this->type = $type;
48 1
    }
49
50
    /**
51
     * @param Context $context
52
     * @return boolean|null
53
     */
54
    public function compile(Context $context)
55
    {
56
        $this->compiled = true;
57
        $context->scopePointer = $this->getPointer();
58
59
        if ($this->statement->getDocComment() === null) {
60
            $context->notice(
61
                'missing-docblock',
62
                sprintf('Missing docblock for %s() method', $this->name),
63
                $this->statement
64
            );
65
        }
66
67
        /**
68
         * It's not needed to compile empty method via it's abstract
69
         */
70
        if ($this->isAbstract()) {
71
            /** @var ClassDefinition $scope */
72
            $scope = $context->scope;
73
            if (!$scope->isAbstract()) {
74
                $context->notice(
75
                    'not-abstract-class-with-abstract-method',
76
                    'Class must be an abstract',
77
                    $this->statement
78
                );
79
            }
80
81
            return true;
82
        }
83
84
        if (count($this->statement->stmts) == 0) {
85
            return $context->notice(
86
                'not-implemented-method',
87
                sprintf('Method %s() is not implemented', $this->name),
88
                $this->statement
89
            );
90
        }
91
92
        if ($this->statement->params) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->statement->params of type PhpParser\Node\Param[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
93
            foreach ($this->statement->params as $parameter) {
94
                $type = CompiledExpression::UNKNOWN;
95
96
                if ($parameter->type) {
97
                    if (is_string($parameter->type)) {
98
                        $type = Types::getType($parameter->type);
99
                    } elseif ($parameter->type instanceof Node\Name\FullyQualified) {
100
                        $type = CompiledExpression::OBJECT;
101
                    }
102
                }
103
104
                $context->addVariable(
105
                    new Parameter($parameter->name, null, $type, $parameter->byRef)
106
                );
107
            }
108
        }
109
110
        foreach ($this->statement->stmts as $st) {
111
            \PHPSA\nodeVisitorFactory($st, $context);
112
        }
113
    }
114
115
    /**
116
     * @param Context $context
117
     * @param array|null $args
118
     * @return CompiledExpression
119
     * @throws \PHPSA\Exception\RuntimeException
120
     */
121
    public function run(Context $context, array $args = null)
122
    {
123
        if ($args) {
124
            foreach ($args as $argument) {
125
                $arguments[] = $context->getExpressionCompiler()->compile($argument->value);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$arguments was never initialized. Although not strictly required by PHP, it is generally a good practice to add $arguments = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
126
            }
127
        }
128
129
        return new CompiledExpression();
130
    }
131
132
    /**
133
     * @return bool
134
     */
135
    public function isAbstract()
136
    {
137
        return (bool) ($this->type & Node\Stmt\Class_::MODIFIER_ABSTRACT);
138
    }
139
140
    /**
141
     * @return bool
142
     */
143
    public function isStatic()
144
    {
145
        return (bool) ($this->type & Node\Stmt\Class_::MODIFIER_STATIC);
146
    }
147
148
    /**
149
     * @return bool
150
     */
151
    public function isPublic()
152
    {
153
        return ($this->type & Node\Stmt\Class_::MODIFIER_PUBLIC) !== 0 || $this->type === 0;
154
    }
155
156
    /**
157
     * @return bool
158
     */
159
    public function isProtected()
160
    {
161
        return (bool) ($this->type & Node\Stmt\Class_::MODIFIER_PROTECTED);
162
    }
163
164
    /**
165
     * @return bool
166
     */
167
    public function isPrivate()
168
    {
169
        return (bool) ($this->type & Node\Stmt\Class_::MODIFIER_PRIVATE);
170
    }
171
172
    /**
173
     * @param $newType
174
     */
175
    public function addNewType($newType)
176
    {
177
        if ($this->returnType != CompiledExpression::VOID) {
178
            $this->returnType = $this->returnType | $newType;
179
        } else {
180
            $this->returnType = $newType;
181
        }
182
    }
183
184
    /**
185
     * @return int
186
     */
187
    public function getReturnType()
188
    {
189
        return $this->returnType;
190
    }
191
192
    /**
193
     * @param $value
194
     */
195
    public function addReturnPossibleValue($value)
196
    {
197
        $this->possibleReturnValues[] = $value;
198
    }
199
200
    /**
201
     * @return array
202
     */
203
    public function getPossibleReturnValues()
204
    {
205
        return $this->possibleReturnValues;
206
    }
207
}
208