Completed
Pull Request — master (#369)
by
unknown
04:33
created

AbstractProxy::getParameterCode()   F

Complexity

Conditions 13
Paths 816

Size

Total Lines 31
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 13.0159

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 21
cts 22
cp 0.9545
rs 3.0089
c 0
b 0
f 0
cc 13
eloc 23
nc 816
nop 1
crap 13.0159

How to fix   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
declare(strict_types = 1);
3
/*
4
 * Go! AOP framework
5
 *
6
 * @copyright Copyright 2012, Lisachenko Alexander <[email protected]>
7
 *
8
 * This source file is subject to the license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Go\Proxy;
13
14
use Reflection;
15
use ReflectionFunctionAbstract;
16
use ReflectionMethod;
17
use ReflectionParameter;
18
19
/**
20
 * Abstract class for building different proxies
21
 */
22
abstract class AbstractProxy
23
{
24
25
    /**
26
     * Indent for source code
27
     *
28
     * @var int
29
     */
30
    protected $indent = 4;
31
32
    /**
33
     * List of advices that are used for generation of child
34
     *
35
     * @var array
36
     */
37
    protected $advices = [];
38
39
    /**
40
     * PHP expression string for accessing LSB information
41
     *
42
     * @var string
43
     */
44
    protected static $staticLsbExpression = 'static::class';
45
46
    /**
47
     * Constructs an abstract proxy class
48
     *
49
     * @param array $advices List of advices
50
     */
51 7
    public function __construct(array $advices = [])
52
    {
53 7
        $this->advices = $this->flattenAdvices($advices);
54 7
    }
55
56
    /**
57
     * Returns text representation of class
58
     *
59
     * @return string
60
     */
61
    abstract public function __toString();
62
63
    /**
64
     * Indent block of code
65
     *
66
     * @param string $text Non-indented text
67
     *
68
     * @return string Indented text
69
     */
70 7
    protected function indent(string $text): string
71
    {
72 7
        $pad   = str_pad('', $this->indent, ' ');
73 7
        $lines = array_map(function ($line) use ($pad) {
74 7
            return $pad . $line;
75 7
        }, explode("\n", $text));
76
77 7
        return implode("\n", $lines);
78
    }
79
80
    /**
81
     * Returns list of string representation of parameters
82
     *
83
     * @param array|ReflectionParameter[] $parameters List of parameters
84
     *
85
     * @return array|string[]
86
     */
87 7
    protected function getParameters(array $parameters): array
88
    {
89 7
        $parameterDefinitions = [];
90 7
        foreach ($parameters as $parameter) {
91 4
            $parameterDefinitions[] = $this->getParameterCode($parameter);
92
        }
93
94 7
        return $parameterDefinitions;
95
    }
96
97
    /**
98
     * Return string representation of parameter
99
     *
100
     * @param ReflectionParameter $parameter Reflection parameter
101
     *
102
     * @return string
103
     */
104 4
    protected function getParameterCode(ReflectionParameter $parameter): string
105
    {
106 4
        $type = '';
107 4
        $reflectionType = $parameter->getType();
108 4
        if ($reflectionType) {
109 2
            $nullablePrefix = (PHP_VERSION_ID >= 70100 && $reflectionType->allowsNull()) ? '?' : '';
110 2
            $nsPrefix       = $reflectionType->isBuiltin() ? '' : '\\';
111 2
            $type           = $nullablePrefix . $nsPrefix . (string) $reflectionType;
112
            // prevent double "\\" prefix for global namespace type hints:
113 2
            if (substr($type, 0, 2) === '\\\\') {
114 1
                $type = substr($type, 1);
115
            }
116
        }
117 4
        $defaultValue = null;
118 4
        $isDefaultValueAvailable = $parameter->isDefaultValueAvailable();
119 4
        if ($isDefaultValueAvailable) {
120 3
            $defaultValue = var_export($parameter->getDefaultValue(), true);
121 4
        } elseif ($parameter->isOptional() && !$parameter->isVariadic()) {
122
            $defaultValue = 'null';
123
        }
124
        $code = (
125 4
            ($type ? "$type " : '') . // Typehint
126 4
            ($parameter->isPassedByReference() ? '&' : '') . // By reference sign
127 4
            ($parameter->isVariadic() ? '...' : '') . // Variadic symbol
128 4
            '$' . // Variable symbol
129 4
            $parameter->name . // Name of the argument
130 4
            ($defaultValue !== null ? (' = ' . $defaultValue) : '') // Default value if present
131
        );
132
133 4
        return $code;
134
    }
135
136
    /**
137
     * Replace concrete advices with list of ids
138
     *
139
     * @param array $advices List of advices
140
     *
141
     * @return array flatten list of advices
142
     */
143 7
    private function flattenAdvices(array $advices): array
144
    {
145 7
        $flattenAdvices = [];
146 7
        foreach ($advices as $type => $typedAdvices) {
147 7
            foreach ($typedAdvices as $name => $concreteAdvices) {
148 7
                if (is_array($concreteAdvices)) {
149 7
                    $flattenAdvices[$type][$name] = array_keys($concreteAdvices);
150
                }
151
            }
152
        }
153
154 7
        return $flattenAdvices;
155
    }
156
157
    /**
158
     * Prepares a line with args from the method definition
159
     *
160
     * @param ReflectionFunctionAbstract $functionLike
161
     *
162
     * @return string
163
     */
164 7
    protected function prepareArgsLine(ReflectionFunctionAbstract $functionLike): string
165
    {
166 7
        $argumentsPart = [];
167 7
        $arguments     = [];
168 7
        $hasOptionals  = false;
169
170 7
        foreach ($functionLike->getParameters() as $parameter) {
171 4
            $byReference  = ($parameter->isPassedByReference() && !$parameter->isVariadic()) ? '&' : '';
172 4
            $hasOptionals = $hasOptionals || $parameter->isOptional();
173
174 4
            $arguments[] = $byReference . '$' . $parameter->name;
175
        }
176
177 7
        $isVariadic = $functionLike->isVariadic();
178 7
        if ($isVariadic) {
179 1
            $argumentsPart[] = array_pop($arguments);
180
        }
181 7
        if (!empty($arguments)) {
182
            // Unshifting to keep correct order
183 4
            $argumentLine = '[' . implode(', ', $arguments) . ']';
184 4
            if ($hasOptionals) {
185 3
                $argumentLine = "\\array_slice($argumentLine, 0, \\func_num_args())";
186
            }
187 4
            array_unshift($argumentsPart, $argumentLine);
188
        }
189
190 7
        return implode(', ', $argumentsPart);
191
    }
192
193
    /**
194
     * Creates a function code from Reflection
195
     *
196
     * @param ReflectionFunctionAbstract $functionLike Reflection for method
197
     * @param string $body Body of method
198
     *
199
     * @return string
200
     */
201 7
    protected function getOverriddenFunction(ReflectionFunctionAbstract $functionLike, string $body): string
202
    {
203 7
        $reflectionReturnType = $functionLike->getReturnType();
204 7
        $modifiersLine        = '';
205 7
        if ($reflectionReturnType) {
206 1
            $nullablePrefix = $reflectionReturnType->allowsNull() ? '?' : '';
207 1
            $nsPrefix       = $reflectionReturnType->isBuiltin() ? '' : '\\';
208
209 1
            $reflectionReturnType = $nullablePrefix . $nsPrefix . (string) $reflectionReturnType;
210
        }
211 7
        if ($functionLike instanceof ReflectionMethod) {
212 7
            $modifiersLine = implode(' ', Reflection::getModifierNames($functionLike->getModifiers()));
213
        }
214
215
        $code = (
216 7
            preg_replace('/ {4}|\t/', '', $functionLike->getDocComment()) . "\n" . // Original Doc-block
217 7
            $modifiersLine . // List of modifiers (for methods)
218 7
            ' function ' . // 'function' keyword
219 7
            ($functionLike->returnsReference() ? '&' : '') . // By reference symbol
220 7
            $functionLike->name . // Name of the function
221 7
            '(' . // Start of parameters list
222 7
            implode(', ', $this->getParameters($functionLike->getParameters())) . // List of parameters
223 7
            ')' . // End of parameters list
224 7
            ($reflectionReturnType ? " : $reflectionReturnType" : '') . // Return type, if present
225 7
            "\n" .
226 7
            "{\n" . // Start of method body
227 7
            $this->indent($body) . "\n" . // Method body
228 7
            "}\n" // End of method body
229
        );
230
231 7
        return $code;
232
    }
233
}
234