MethodDefinitionPass::renderParams()   D
last analyzed

Complexity

Conditions 9
Paths 35

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 9

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 31
ccs 24
cts 24
cp 1
rs 4.909
cc 9
eloc 20
nc 35
nop 2
crap 9
1
<?php
2
/**
3
 * Mockery
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://github.com/padraic/mockery/blob/master/LICENSE
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to [email protected] so we can send you a copy immediately.
14
 *
15
 * @category   Mockery
16
 * @package    Mockery
17
 * @copyright  Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
18
 * @license    http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
19
 */
20
21
namespace Mockery\Generator\StringManipulation\Pass;
22
23
use Mockery\Generator\Method;
24
use Mockery\Generator\Parameter;
25
use Mockery\Generator\MockConfiguration;
26
27
class MethodDefinitionPass implements Pass
28
{
29 397
    public function apply($code, MockConfiguration $config)
30
    {
31 397
        foreach ($config->getMethodsToMock() as $method) {
32 109
            if ($method->isPublic()) {
33 105
                $methodDef = 'public';
34 109
            } elseif ($method->isProtected()) {
35 12
                $methodDef = 'protected';
36 12
            } else {
37 2
                $methodDef = 'private';
38
            }
39
40 109
            if ($method->isStatic()) {
41 9
                $methodDef .= ' static';
42 9
            }
43
44 109
            $methodDef .= ' function ';
45 109
            $methodDef .= $method->returnsReference() ? ' & ' : '';
46 109
            $methodDef .= $method->getName();
47 109
            $methodDef .= $this->renderParams($method, $config);
48 109
            $methodDef .= $this->renderReturnType($method);
49 109
            $methodDef .= $this->renderMethodBody($method, $config);
50
51 109
            $code = $this->appendToClass($code, $methodDef);
52 397
        }
53
54 397
        return $code;
55
    }
56
57 109
    protected function renderParams(Method $method, $config)
58
    {
59 109
        $class = $method->getDeclaringClass();
60 109
        if ($class->isInternal()) {
61 24
            $overrides = $config->getParameterOverrides();
62
63 24
            if (isset($overrides[strtolower($class->getName())][$method->getName()])) {
64 3
                return '(' . implode(',', $overrides[strtolower($class->getName())][$method->getName()]) . ')';
65
            }
66 24
        }
67
68 109
        $methodParams = array();
69 109
        $params = $method->getParameters();
70 109
        foreach ($params as $param) {
71 41
            $paramDef = $this->renderTypeHint($param);
72 41
            $paramDef .= $param->isPassedByReference() ? '&' : '';
73 41
            $paramDef .= $param->isVariadic() ? '...' : '';
74 41
            $paramDef .= '$' . $param->getName();
75
76 41
            if (!$param->isVariadic()) {
77 41
                if (false !== $param->isDefaultValueAvailable()) {
78 5
                    $paramDef .= ' = ' . var_export($param->getDefaultValue(), true);
79 41
                } elseif ($param->isOptional()) {
80 14
                    $paramDef .= ' = null';
81 14
                }
82 41
            }
83
84 41
            $methodParams[] = $paramDef;
85 109
        }
86 109
        return '(' . implode(', ', $methodParams) . ')';
87
    }
88
89 109
    protected function renderReturnType(Method $method)
90
    {
91 109
        $type = $method->getReturnType();
92 109
        return $type ? sprintf(': %s', $type) : '';
93
    }
94
95 109
    protected function appendToClass($class, $code)
96
    {
97 109
        $lastBrace = strrpos($class, "}");
98 109
        $class = substr($class, 0, $lastBrace) . $code . "\n    }\n";
99 109
        return $class;
100
    }
101
102 41
    protected function renderTypeHint(Parameter $param)
103
    {
104
        $languageTypeHints = array(
105 41
            'self',
106 41
            'array',
107 41
            'callable',
108
            // Up to php 7
109 41
            'bool',
110 41
            'float',
111 41
            'int',
112 41
            'string',
113 41
            'iterable',
114 41
        );
115 41
        $typeHint = trim($param->getTypeHintAsString());
116
117 41
        if (!empty($typeHint)) {
118
           
119 10
            if (!in_array($typeHint, $languageTypeHints)) {
120 8
                $typeHint = '\\'.$typeHint;
121 8
            }
122
123 10
            if (version_compare(PHP_VERSION, '7.1.0-dev') >= 0 && $param->allowsNull()) {
0 ignored issues
show
Documentation Bug introduced by
The method allowsNull does not exist on object<Mockery\Generator\Parameter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
124
                $typeHint = "?".$typeHint;
125
            }
126 10
        }
127
128 41
        return $typeHint .= ' ';
129
    }
130
131 109
    private function renderMethodBody($method, $config)
132
    {
133 109
        $invoke = $method->isStatic() ? 'static::_mockery_handleStaticMethodCall' : '$this->_mockery_handleMethodCall';
134
        $body = <<<BODY
135
{
136
\$argc = func_num_args();
137
\$argv = func_get_args();
138
139 109
BODY;
140
141
        // Fix up known parameters by reference - used func_get_args() above
142
        // in case more parameters are passed in than the function definition
143
        // says - eg varargs.
144 109
        $class = $method->getDeclaringClass();
145 109
        $class_name = strtolower($class->getName());
146 109
        $overrides = $config->getParameterOverrides();
147 109
        if (isset($overrides[$class_name][$method->getName()])) {
148 3
            $params = array_values($overrides[$class_name][$method->getName()]);
149 3
            $paramCount = count($params);
150 3
            for ($i = 0; $i < $paramCount; ++$i) {
151 3
                $param = $params[$i];
152 3
                if (strpos($param, '&') !== false) {
153
                    $body .= <<<BODY
154
if (\$argc > $i) {
155 3
    \$argv[$i] = {$param};
156
}
157
158 3
BODY;
159 3
                }
160 3
            }
161 3
        } else {
162 109
            $params = array_values($method->getParameters());
163 109
            $paramCount = count($params);
164 109
            for ($i = 0; $i < $paramCount; ++$i) {
165 41
                $param = $params[$i];
166 41
                if (!$param->isPassedByReference()) {
167 39
                    continue;
168
                }
169
                $body .= <<<BODY
170
if (\$argc > $i) {
171 6
    \$argv[$i] =& \${$param->getName()};
172
}
173
174 6
BODY;
175 6
            }
176
        }
177
178 109
        $body .= "\$ret = {$invoke}(__FUNCTION__, \$argv);\n";
179
180 109
        if ($method->getReturnType() !== "void") {
181 109
            $body .= "return \$ret;\n";
182 109
        }
183
184 109
        $body .= "}\n";
185 109
        return $body;
186
    }
187
}
188