Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of sebastian/code-unit.
4
 *
5
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace SebastianBergmann\CodeUnit;
11
 
12
use function range;
13
use function sprintf;
14
use ReflectionClass;
15
use ReflectionFunction;
16
use ReflectionMethod;
17
 
18
/**
19
 * @psalm-immutable
20
 */
21
abstract class CodeUnit
22
{
23
    /**
24
     * @var string
25
     */
26
    private $name;
27
 
28
    /**
29
     * @var string
30
     */
31
    private $sourceFileName;
32
 
33
    /**
34
     * @var array
35
     * @psalm-var list<int>
36
     */
37
    private $sourceLines;
38
 
39
    /**
40
     * @psalm-param class-string $className
41
     *
42
     * @throws InvalidCodeUnitException
43
     * @throws ReflectionException
44
     */
45
    public static function forClass(string $className): ClassUnit
46
    {
47
        self::ensureUserDefinedClass($className);
48
 
49
        $reflector = self::reflectorForClass($className);
50
 
51
        return new ClassUnit(
52
            $className,
53
            $reflector->getFileName(),
54
            range(
55
                $reflector->getStartLine(),
56
                $reflector->getEndLine()
57
            )
58
        );
59
    }
60
 
61
    /**
62
     * @psalm-param class-string $className
63
     *
64
     * @throws InvalidCodeUnitException
65
     * @throws ReflectionException
66
     */
67
    public static function forClassMethod(string $className, string $methodName): ClassMethodUnit
68
    {
69
        self::ensureUserDefinedClass($className);
70
 
71
        $reflector = self::reflectorForClassMethod($className, $methodName);
72
 
73
        return new ClassMethodUnit(
74
            $className . '::' . $methodName,
75
            $reflector->getFileName(),
76
            range(
77
                $reflector->getStartLine(),
78
                $reflector->getEndLine()
79
            )
80
        );
81
    }
82
 
83
    /**
84
     * @psalm-param class-string $interfaceName
85
     *
86
     * @throws InvalidCodeUnitException
87
     * @throws ReflectionException
88
     */
89
    public static function forInterface(string $interfaceName): InterfaceUnit
90
    {
91
        self::ensureUserDefinedInterface($interfaceName);
92
 
93
        $reflector = self::reflectorForClass($interfaceName);
94
 
95
        return new InterfaceUnit(
96
            $interfaceName,
97
            $reflector->getFileName(),
98
            range(
99
                $reflector->getStartLine(),
100
                $reflector->getEndLine()
101
            )
102
        );
103
    }
104
 
105
    /**
106
     * @psalm-param class-string $interfaceName
107
     *
108
     * @throws InvalidCodeUnitException
109
     * @throws ReflectionException
110
     */
111
    public static function forInterfaceMethod(string $interfaceName, string $methodName): InterfaceMethodUnit
112
    {
113
        self::ensureUserDefinedInterface($interfaceName);
114
 
115
        $reflector = self::reflectorForClassMethod($interfaceName, $methodName);
116
 
117
        return new InterfaceMethodUnit(
118
            $interfaceName . '::' . $methodName,
119
            $reflector->getFileName(),
120
            range(
121
                $reflector->getStartLine(),
122
                $reflector->getEndLine()
123
            )
124
        );
125
    }
126
 
127
    /**
128
     * @psalm-param class-string $traitName
129
     *
130
     * @throws InvalidCodeUnitException
131
     * @throws ReflectionException
132
     */
133
    public static function forTrait(string $traitName): TraitUnit
134
    {
135
        self::ensureUserDefinedTrait($traitName);
136
 
137
        $reflector = self::reflectorForClass($traitName);
138
 
139
        return new TraitUnit(
140
            $traitName,
141
            $reflector->getFileName(),
142
            range(
143
                $reflector->getStartLine(),
144
                $reflector->getEndLine()
145
            )
146
        );
147
    }
148
 
149
    /**
150
     * @psalm-param class-string $traitName
151
     *
152
     * @throws InvalidCodeUnitException
153
     * @throws ReflectionException
154
     */
155
    public static function forTraitMethod(string $traitName, string $methodName): TraitMethodUnit
156
    {
157
        self::ensureUserDefinedTrait($traitName);
158
 
159
        $reflector = self::reflectorForClassMethod($traitName, $methodName);
160
 
161
        return new TraitMethodUnit(
162
            $traitName . '::' . $methodName,
163
            $reflector->getFileName(),
164
            range(
165
                $reflector->getStartLine(),
166
                $reflector->getEndLine()
167
            )
168
        );
169
    }
170
 
171
    /**
172
     * @psalm-param callable-string $functionName
173
     *
174
     * @throws InvalidCodeUnitException
175
     * @throws ReflectionException
176
     */
177
    public static function forFunction(string $functionName): FunctionUnit
178
    {
179
        $reflector = self::reflectorForFunction($functionName);
180
 
181
        if (!$reflector->isUserDefined()) {
182
            throw new InvalidCodeUnitException(
183
                sprintf(
184
                    '"%s" is not a user-defined function',
185
                    $functionName
186
                )
187
            );
188
        }
189
 
190
        return new FunctionUnit(
191
            $functionName,
192
            $reflector->getFileName(),
193
            range(
194
                $reflector->getStartLine(),
195
                $reflector->getEndLine()
196
            )
197
        );
198
    }
199
 
200
    /**
201
     * @psalm-param list<int> $sourceLines
202
     */
203
    private function __construct(string $name, string $sourceFileName, array $sourceLines)
204
    {
205
        $this->name           = $name;
206
        $this->sourceFileName = $sourceFileName;
207
        $this->sourceLines    = $sourceLines;
208
    }
209
 
210
    public function name(): string
211
    {
212
        return $this->name;
213
    }
214
 
215
    public function sourceFileName(): string
216
    {
217
        return $this->sourceFileName;
218
    }
219
 
220
    /**
221
     * @psalm-return list<int>
222
     */
223
    public function sourceLines(): array
224
    {
225
        return $this->sourceLines;
226
    }
227
 
228
    public function isClass(): bool
229
    {
230
        return false;
231
    }
232
 
233
    public function isClassMethod(): bool
234
    {
235
        return false;
236
    }
237
 
238
    public function isInterface(): bool
239
    {
240
        return false;
241
    }
242
 
243
    public function isInterfaceMethod(): bool
244
    {
245
        return false;
246
    }
247
 
248
    public function isTrait(): bool
249
    {
250
        return false;
251
    }
252
 
253
    public function isTraitMethod(): bool
254
    {
255
        return false;
256
    }
257
 
258
    public function isFunction(): bool
259
    {
260
        return false;
261
    }
262
 
263
    /**
264
     * @psalm-param class-string $className
265
     *
266
     * @throws InvalidCodeUnitException
267
     */
268
    private static function ensureUserDefinedClass(string $className): void
269
    {
270
        try {
271
            $reflector = new ReflectionClass($className);
272
 
273
            if ($reflector->isInterface()) {
274
                throw new InvalidCodeUnitException(
275
                    sprintf(
276
                        '"%s" is an interface and not a class',
277
                        $className
278
                    )
279
                );
280
            }
281
 
282
            if ($reflector->isTrait()) {
283
                throw new InvalidCodeUnitException(
284
                    sprintf(
285
                        '"%s" is a trait and not a class',
286
                        $className
287
                    )
288
                );
289
            }
290
 
291
            if (!$reflector->isUserDefined()) {
292
                throw new InvalidCodeUnitException(
293
                    sprintf(
294
                        '"%s" is not a user-defined class',
295
                        $className
296
                    )
297
                );
298
            }
299
            // @codeCoverageIgnoreStart
300
        } catch (\ReflectionException $e) {
301
            throw new ReflectionException(
302
                $e->getMessage(),
303
                (int) $e->getCode(),
304
                $e
305
            );
306
        }
307
        // @codeCoverageIgnoreEnd
308
    }
309
 
310
    /**
311
     * @psalm-param class-string $interfaceName
312
     *
313
     * @throws InvalidCodeUnitException
314
     */
315
    private static function ensureUserDefinedInterface(string $interfaceName): void
316
    {
317
        try {
318
            $reflector = new ReflectionClass($interfaceName);
319
 
320
            if (!$reflector->isInterface()) {
321
                throw new InvalidCodeUnitException(
322
                    sprintf(
323
                        '"%s" is not an interface',
324
                        $interfaceName
325
                    )
326
                );
327
            }
328
 
329
            if (!$reflector->isUserDefined()) {
330
                throw new InvalidCodeUnitException(
331
                    sprintf(
332
                        '"%s" is not a user-defined interface',
333
                        $interfaceName
334
                    )
335
                );
336
            }
337
            // @codeCoverageIgnoreStart
338
        } catch (\ReflectionException $e) {
339
            throw new ReflectionException(
340
                $e->getMessage(),
341
                (int) $e->getCode(),
342
                $e
343
            );
344
        }
345
        // @codeCoverageIgnoreEnd
346
    }
347
 
348
    /**
349
     * @psalm-param class-string $traitName
350
     *
351
     * @throws InvalidCodeUnitException
352
     */
353
    private static function ensureUserDefinedTrait(string $traitName): void
354
    {
355
        try {
356
            $reflector = new ReflectionClass($traitName);
357
 
358
            if (!$reflector->isTrait()) {
359
                throw new InvalidCodeUnitException(
360
                    sprintf(
361
                        '"%s" is not a trait',
362
                        $traitName
363
                    )
364
                );
365
            }
366
 
367
            // @codeCoverageIgnoreStart
368
            if (!$reflector->isUserDefined()) {
369
                throw new InvalidCodeUnitException(
370
                    sprintf(
371
                        '"%s" is not a user-defined trait',
372
                        $traitName
373
                    )
374
                );
375
            }
376
        } catch (\ReflectionException $e) {
377
            throw new ReflectionException(
378
                $e->getMessage(),
379
                (int) $e->getCode(),
380
                $e
381
            );
382
        }
383
        // @codeCoverageIgnoreEnd
384
    }
385
 
386
    /**
387
     * @psalm-param class-string $className
388
     *
389
     * @throws ReflectionException
390
     */
391
    private static function reflectorForClass(string $className): ReflectionClass
392
    {
393
        try {
394
            return new ReflectionClass($className);
395
            // @codeCoverageIgnoreStart
396
        } catch (\ReflectionException $e) {
397
            throw new ReflectionException(
398
                $e->getMessage(),
399
                (int) $e->getCode(),
400
                $e
401
            );
402
        }
403
        // @codeCoverageIgnoreEnd
404
    }
405
 
406
    /**
407
     * @psalm-param class-string $className
408
     *
409
     * @throws ReflectionException
410
     */
411
    private static function reflectorForClassMethod(string $className, string $methodName): ReflectionMethod
412
    {
413
        try {
414
            return new ReflectionMethod($className, $methodName);
415
            // @codeCoverageIgnoreStart
416
        } catch (\ReflectionException $e) {
417
            throw new ReflectionException(
418
                $e->getMessage(),
419
                (int) $e->getCode(),
420
                $e
421
            );
422
        }
423
        // @codeCoverageIgnoreEnd
424
    }
425
 
426
    /**
427
     * @psalm-param callable-string $functionName
428
     *
429
     * @throws ReflectionException
430
     */
431
    private static function reflectorForFunction(string $functionName): ReflectionFunction
432
    {
433
        try {
434
            return new ReflectionFunction($functionName);
435
            // @codeCoverageIgnoreStart
436
        } catch (\ReflectionException $e) {
437
            throw new ReflectionException(
438
                $e->getMessage(),
439
                (int) $e->getCode(),
440
                $e
441
            );
442
        }
443
        // @codeCoverageIgnoreEnd
444
    }
445
}