Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
/**
6
 * This file is part of the Carbon package.
7
 *
8
 * (c) Brian Nesbitt <brian@nesbot.com>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
 
14
namespace Carbon\PHPStan;
15
 
16
use Closure;
17
use InvalidArgumentException;
18
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter as AdapterReflectionParameter;
19
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionType as AdapterReflectionType;
20
use PHPStan\BetterReflection\Reflection\ReflectionClass as BetterReflectionClass;
21
use PHPStan\BetterReflection\Reflection\ReflectionFunction as BetterReflectionFunction;
22
use PHPStan\BetterReflection\Reflection\ReflectionParameter as BetterReflectionParameter;
23
use PHPStan\Reflection\Php\BuiltinMethodReflection;
24
use PHPStan\TrinaryLogic;
25
use ReflectionClass;
26
use ReflectionFunction;
27
use ReflectionMethod;
28
use ReflectionParameter;
29
use ReflectionType;
30
use stdClass;
31
use Throwable;
32
 
33
abstract class AbstractMacro implements BuiltinMethodReflection
34
{
35
    /**
36
     * The reflection function/method.
37
     *
38
     * @var ReflectionFunction|ReflectionMethod
39
     */
40
    protected $reflectionFunction;
41
 
42
    /**
43
     * The class name.
44
     *
45
     * @var class-string
46
     */
47
    private $className;
48
 
49
    /**
50
     * The method name.
51
     *
52
     * @var string
53
     */
54
    private $methodName;
55
 
56
    /**
57
     * The parameters.
58
     *
59
     * @var ReflectionParameter[]
60
     */
61
    private $parameters;
62
 
63
    /**
64
     * The is static.
65
     *
66
     * @var bool
67
     */
68
    private $static = false;
69
 
70
    /**
71
     * Macro constructor.
72
     *
73
     * @param string $className
74
     * @phpstan-param class-string $className
75
     *
76
     * @param string   $methodName
77
     * @param callable $macro
78
     */
79
    public function __construct(string $className, string $methodName, $macro)
80
    {
81
        $this->className = $className;
82
        $this->methodName = $methodName;
83
        $rawReflectionFunction = \is_array($macro)
84
            ? new ReflectionMethod($macro[0], $macro[1])
85
            : new ReflectionFunction($macro);
86
        $this->reflectionFunction = self::hasModernParser()
87
            ? $this->getReflectionFunction($macro)
88
            : $rawReflectionFunction; // @codeCoverageIgnore
89
        $this->parameters = array_map(
90
            function ($parameter) {
91
                if ($parameter instanceof BetterReflectionParameter) {
92
                    return new AdapterReflectionParameter($parameter);
93
                }
94
 
95
                return $parameter; // @codeCoverageIgnore
96
            },
97
            $this->reflectionFunction->getParameters()
98
        );
99
 
100
        if ($rawReflectionFunction->isClosure()) {
101
            try {
102
                $closure = $rawReflectionFunction->getClosure();
103
                $boundClosure = Closure::bind($closure, new stdClass());
104
                $this->static = (!$boundClosure || (new ReflectionFunction($boundClosure))->getClosureThis() === null);
105
            } catch (Throwable $e) {
106
                $this->static = true;
107
            }
108
        }
109
    }
110
 
111
    private function getReflectionFunction($spec)
112
    {
113
        if (\is_array($spec) && \count($spec) === 2 && \is_string($spec[1])) {
114
            \assert($spec[1] !== '');
115
 
116
            if (\is_object($spec[0])) {
117
                return BetterReflectionClass::createFromInstance($spec[0])
118
                    ->getMethod($spec[1]);
119
            }
120
 
121
            return BetterReflectionClass::createFromName($spec[0])
122
                ->getMethod($spec[1]);
123
        }
124
 
125
        if (\is_string($spec)) {
126
            return BetterReflectionFunction::createFromName($spec);
127
        }
128
 
129
        if ($spec instanceof Closure) {
130
            return BetterReflectionFunction::createFromClosure($spec);
131
        }
132
 
133
        throw new InvalidArgumentException('Could not create reflection from the spec given'); // @codeCoverageIgnore
134
    }
135
 
136
    /**
137
     * {@inheritdoc}
138
     */
139
    public function getDeclaringClass(): ReflectionClass
140
    {
141
        return new ReflectionClass($this->className);
142
    }
143
 
144
    /**
145
     * {@inheritdoc}
146
     */
147
    public function isPrivate(): bool
148
    {
149
        return false;
150
    }
151
 
152
    /**
153
     * {@inheritdoc}
154
     */
155
    public function isPublic(): bool
156
    {
157
        return true;
158
    }
159
 
160
    /**
161
     * {@inheritdoc}
162
     */
163
    public function isFinal(): bool
164
    {
165
        return false;
166
    }
167
 
168
    /**
169
     * {@inheritdoc}
170
     */
171
    public function isInternal(): bool
172
    {
173
        return false;
174
    }
175
 
176
    /**
177
     * {@inheritdoc}
178
     */
179
    public function isAbstract(): bool
180
    {
181
        return false;
182
    }
183
 
184
    /**
185
     * {@inheritdoc}
186
     */
187
    public function isStatic(): bool
188
    {
189
        return $this->static;
190
    }
191
 
192
    /**
193
     * {@inheritdoc}
194
     */
195
    public function getDocComment(): ?string
196
    {
197
        return $this->reflectionFunction->getDocComment() ?: null;
198
    }
199
 
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function getName(): string
204
    {
205
        return $this->methodName;
206
    }
207
 
208
    /**
209
     * {@inheritdoc}
210
     */
211
    public function getParameters(): array
212
    {
213
        return $this->parameters;
214
    }
215
 
216
    /**
217
     * {@inheritdoc}
218
     */
219
    public function getReturnType(): ?ReflectionType
220
    {
221
        $type = $this->reflectionFunction->getReturnType();
222
 
223
        if ($type instanceof ReflectionType) {
224
            return $type; // @codeCoverageIgnore
225
        }
226
 
227
        return self::adaptType($type);
228
    }
229
 
230
    /**
231
     * {@inheritdoc}
232
     */
233
    public function isDeprecated(): TrinaryLogic
234
    {
235
        return TrinaryLogic::createFromBoolean(
236
            $this->reflectionFunction->isDeprecated() ||
237
            preg_match('/@deprecated/i', $this->getDocComment() ?: '')
238
        );
239
    }
240
 
241
    /**
242
     * {@inheritdoc}
243
     */
244
    public function isVariadic(): bool
245
    {
246
        return $this->reflectionFunction->isVariadic();
247
    }
248
 
249
    /**
250
     * {@inheritdoc}
251
     */
252
    public function getPrototype(): BuiltinMethodReflection
253
    {
254
        return $this;
255
    }
256
 
257
    public function getTentativeReturnType(): ?ReflectionType
258
    {
259
        return null;
260
    }
261
 
262
    public function returnsByReference(): TrinaryLogic
263
    {
264
        return TrinaryLogic::createNo();
265
    }
266
 
267
    private static function adaptType($type)
268
    {
269
        $method = method_exists(AdapterReflectionType::class, 'fromTypeOrNull')
270
            ? 'fromTypeOrNull'
271
            : 'fromReturnTypeOrNull'; // @codeCoverageIgnore
272
 
273
        return AdapterReflectionType::$method($type);
274
    }
275
 
276
    private static function hasModernParser(): bool
277
    {
278
        static $modernParser = null;
279
 
280
        if ($modernParser !== null) {
281
            return $modernParser;
282
        }
283
 
284
        $modernParser = method_exists(AdapterReflectionType::class, 'fromTypeOrNull');
285
 
286
        return $modernParser;
287
    }
288
}