1: | <?php declare(strict_types=1); |
2: | |
3: | namespace Salient\Core\Reflection; |
4: | |
5: | use Salient\Utility\Reflect; |
6: | use Closure; |
7: | use DateTimeInterface; |
8: | use ReflectionException; |
9: | use ReflectionMethod; |
10: | use ReflectionNamedType; |
11: | use ReflectionParameter; |
12: | |
13: | |
14: | |
15: | |
16: | class MethodReflection extends ReflectionMethod |
17: | { |
18: | |
19: | private string $ClassUnderReflection; |
20: | |
21: | |
22: | |
23: | |
24: | |
25: | |
26: | public function __construct($objectOrClass, string $method) |
27: | { |
28: | $this->ClassUnderReflection = is_object($objectOrClass) |
29: | ? get_class($objectOrClass) |
30: | : $objectOrClass; |
31: | |
32: | parent::__construct($objectOrClass, $method); |
33: | } |
34: | |
35: | |
36: | |
37: | |
38: | |
39: | |
40: | |
41: | |
42: | |
43: | |
44: | public function accepts(string $typeName, bool $isBuiltin = false, int $position = 0): bool |
45: | { |
46: | $types = Reflect::normaliseType($this->getParameter($position)->getType()); |
47: | foreach ($types as $type) { |
48: | if ( |
49: | !is_array($type) |
50: | && $type->isBuiltin() === $isBuiltin |
51: | && ( |
52: | !strcasecmp($name = $type->getName(), $typeName) |
53: | || (!$isBuiltin && is_a($typeName, $name, true)) |
54: | ) |
55: | ) { |
56: | return true; |
57: | } |
58: | } |
59: | return false; |
60: | } |
61: | |
62: | |
63: | |
64: | |
65: | |
66: | |
67: | |
68: | |
69: | public function returns(string $typeName, bool $isBuiltin = false, bool $allowNull = true): bool |
70: | { |
71: | $types = Reflect::normaliseType($this->getReturnType()); |
72: | if (!$types) { |
73: | return false; |
74: | } |
75: | foreach ($types as $type) { |
76: | if (is_array($type) || !( |
77: | ( |
78: | ($builtin = $type->isBuiltin()) === $isBuiltin |
79: | && ( |
80: | !strcasecmp($name = $type->getName(), $typeName) |
81: | || (!$isBuiltin && is_a($name, $typeName, true)) |
82: | ) |
83: | ) || ( |
84: | $allowNull |
85: | && $builtin |
86: | && !strcasecmp($type->getName(), 'null') |
87: | ) |
88: | )) { |
89: | return false; |
90: | } |
91: | } |
92: | return true; |
93: | } |
94: | |
95: | |
96: | |
97: | |
98: | |
99: | |
100: | |
101: | public function getParameter(int $position): ReflectionParameter |
102: | { |
103: | if ($position >= $this->getNumberOfParameters()) { |
104: | throw new ReflectionException(sprintf( |
105: | 'Method %s does not have a parameter at position %d', |
106: | $this->name, |
107: | $position, |
108: | )); |
109: | } |
110: | return $this->getParameters()[$position]; |
111: | } |
112: | |
113: | |
114: | |
115: | |
116: | |
117: | |
118: | public function getParameterIndex(?Closure $normaliser = null): ParameterIndex |
119: | { |
120: | $class = new ClassReflection($this->ClassUnderReflection); |
121: | $normaliser ??= $class->getNormaliser(); |
122: | |
123: | foreach ($this->getParameters() as $param) { |
124: | $name = $normaliser |
125: | ? $normaliser($param->name, false) |
126: | : $param->name; |
127: | $type = $param->getType(); |
128: | $isOptional = $param->isOptional(); |
129: | |
130: | $names[$name] = $param->name; |
131: | |
132: | if (!$param->isVariadic()) { |
133: | $defaultArgs[] = $isOptional && $param->isDefaultValueAvailable() |
134: | ? $param->getDefaultValue() |
135: | : null; |
136: | } |
137: | |
138: | if (!$param->allowsNull()) { |
139: | $notNullable[$name] = $param->name; |
140: | if (!$isOptional) { |
141: | $required[$name] = $param->name; |
142: | } |
143: | } |
144: | |
145: | if ($param->isPassedByReference()) { |
146: | $byRef[$name] = $param->name; |
147: | } |
148: | |
149: | if ($type instanceof ReflectionNamedType) { |
150: | $typeName = $type->getName(); |
151: | if ($type->isBuiltin()) { |
152: | $builtins[$name] = $typeName; |
153: | } else { |
154: | |
155: | $services[$name] = $typeName; |
156: | if (!strcasecmp($typeName, DateTimeInterface::class)) { |
157: | $date[$name] = $param->name; |
158: | } |
159: | } |
160: | } |
161: | } |
162: | |
163: | return new ParameterIndex( |
164: | $names ?? [], |
165: | array_flip(array_values($names ?? [])), |
166: | $defaultArgs ?? [], |
167: | $notNullable ?? [], |
168: | $required ?? [], |
169: | $byRef ?? [], |
170: | $date ?? [], |
171: | $builtins ?? [], |
172: | $services ?? [], |
173: | $this->getNumberOfRequiredParameters(), |
174: | ); |
175: | } |
176: | } |
177: | |