Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
61.29% covered (warning)
61.29%
19 / 31
25.00% covered (danger)
25.00%
1 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ReflectionUtility
61.29% covered (warning)
61.29%
19 / 31
25.00% covered (danger)
25.00%
1 / 4
30.85
0.00% covered (danger)
0.00%
0 / 1
 create
50.00% covered (danger)
50.00%
5 / 10
0.00% covered (danger)
0.00%
0 / 1
8.12
 existsMethod
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 getAllProperties
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 getTypes
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
5.03
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core;
6
7use ReflectionClass;
8use ReflectionNamedType;
9use ReflectionProperty;
10use ReflectionType;
11use ReflectionUnionType;
12use PeServer\Core\Throws\ArgumentException;
13use TypeError;
14
15/**
16 * 型とかそんなやつになんかするやつ。
17 */
18abstract class ReflectionUtility
19{
20    #region function
21
22    /**
23     * クラスオブジェクトの生成。
24     *
25     * @template TObject of object
26     * @param class-string $input 生成クラス名。
27     * @phpstan-param class-string<TObject> $input
28     * @param class-string|object $baseClass 基底クラス。オブジェクトを渡した場合は生成クラスの型チェックに使用される。
29     * @return object 生成インスタンス。
30     * @phpstan-return TObject
31     * @throws TypeError 型おかしい。
32     */
33    public static function create(string $input, string|object $baseClass, mixed ...$parameters): object
34    {
35        if (!class_exists($input)) {
36            throw new TypeError();
37        }
38
39        $input = new $input(...$parameters);
40
41        if (is_string($baseClass)) {
42            if (!is_a($input, $baseClass, false)) {
43                throw new TypeError();
44            }
45        } else {
46            $baseClassName = get_class($baseClass);
47            if (!is_a($input, $baseClassName, false)) {
48                throw new TypeError();
49            }
50        }
51
52        /** @phpstan-var TObject */
53        return $input;
54    }
55
56    /**
57     * `method_exists` ラッパー。
58     *
59     * @param class-string|object $input
60     * @param non-empty-string $method
61     */
62    public static function existsMethod(object|string $input, string $method): bool
63    {
64        if (is_string($input)) {
65            if (Text::isNullOrWhiteSpace($input)) { //@phpstan-ignore-line [DOCTYPE]
66                throw new ArgumentException('$input');
67            }
68        }
69
70        if (Text::isNullOrWhiteSpace($method)) { //@phpstan-ignore-line [DOCTYPE]
71            throw new ArgumentException('$method');
72        }
73
74        return method_exists($input, $method);
75    }
76
77    /**
78     * 対象と継承元の全てのプロパティを取得。
79     *
80     * @template T of object
81     * @param ReflectionClass $current
82     * @phpstan-param ReflectionClass<T> $current
83     * @param int $filter
84     * @return ReflectionProperty[]
85     */
86    public static function getAllProperties(ReflectionClass $current, int $filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE): array
87    {
88        $properties = $current->getProperties($filter);
89
90        $parent = $current;
91        while ($parent = $parent->getParentClass()) {
92            $parentProperties = $parent->getProperties($filter);
93            $properties = array_merge($properties, $parentProperties); //いっつもわからんくなる。何が正しいのか
94        }
95
96        return $properties;
97    }
98
99    /**
100     * 型指定から型一覧を取得。
101     *
102     * @param ReflectionType|null $parameterType
103     * @return ReflectionNamedType[]
104     */
105    public static function getTypes(?ReflectionType $parameterType): array
106    {
107        if ($parameterType instanceof ReflectionNamedType) {
108            return [$parameterType];
109        }
110
111        if ($parameterType instanceof ReflectionUnionType) {
112            $result = [];
113
114            foreach ($parameterType->getTypes() as $type) {
115                if ($type instanceof ReflectionNamedType) {
116                    $result[] = $type;
117                }
118            }
119
120            return $result;
121        }
122
123        return [];
124    }
125
126    #endregion
127}