PocketMine-MP 5.39.3 git-400eb2dddf91a9c112aa09f3b498ffc8c85e98ed
Loading...
Searching...
No Matches
MatchTester.php
1<?php declare(strict_types = 1);
2
3namespace DaveRandom\CallbackValidator;
4
5final class MatchTester
6{
10 private function __construct() { }
11
16 private static $builtInTypes = [
17 BuiltInTypes::STRING => true,
18 BuiltInTypes::INT => true,
19 BuiltInTypes::FLOAT => true,
20 BuiltInTypes::BOOL => true,
21 BuiltInTypes::ARRAY => true,
22 BuiltInTypes::CALLABLE => true,
23 BuiltInTypes::VOID => true,
24 BuiltInTypes::ITERABLE => true,
25 BuiltInTypes::OBJECT => true,
26 ];
27
32 private static $scalarTypes = [
33 BuiltInTypes::STRING => true,
34 BuiltInTypes::INT => true,
35 BuiltInTypes::FLOAT => true,
36 BuiltInTypes::BOOL => true,
37 ];
38
44 public static function isWeakScalarMatch($superTypeName, $subTypeName)
45 {
46 // Nothing else satisfies array, callable, void or iterable
47 if (!isset(self::$scalarTypes[$superTypeName])) {
48 return false;
49 }
50
51 // Scalars can all cast to each other
52 if (isset(self::$scalarTypes[$subTypeName])) {
53 return true;
54 }
55
56 // Classes with __toString() satisfy string
57 if ($superTypeName === BuiltInTypes::STRING && \method_exists($subTypeName, '__toString')) {
58 return true;
59 }
60
61 return false;
62 }
63
72 public static function isMatch($superTypeName, $superTypeNullable, $subTypeName, $subTypeNullable, $weak)
73 {
74 // If the super type is unspecified, anything is a match
75 if ($superTypeName === null) {
76 return true;
77 }
78
79 // If the sub type is unspecified, nothing is a match
80 if ($subTypeName === null) {
81 return false;
82 }
83
84 $superTypeName = (string)$superTypeName;
85 $subTypeName = (string)$subTypeName;
86
87 // Sub type cannot be nullable unless the super type is as well
88 if ($subTypeNullable && !$superTypeNullable) {
89 // nullable void doesn't really make sense but for completeness...
90 return $superTypeName === BuiltInTypes::VOID && $subTypeName === BuiltInTypes::VOID;
91 }
92
93 // If the string is an exact match it's definitely acceptable
94 if ($superTypeName === $subTypeName) {
95 return true;
96 }
97
98 // Check iterable
99 if ($superTypeName === BuiltInTypes::ITERABLE) {
100 return $subTypeName === BuiltInTypes::ARRAY
101 || $subTypeName === \Traversable::class
102 || \is_subclass_of($subTypeName, \Traversable::class);
103 }
104
105 // Check callable
106 if ($superTypeName === BuiltInTypes::CALLABLE) {
107 return $subTypeName === \Closure::class
108 || \method_exists($subTypeName, '__invoke')
109 || \is_subclass_of($subTypeName, \Closure::class);
110 }
111
112 if ($superTypeName === BuiltInTypes::OBJECT) {
113 return class_exists($subTypeName) || interface_exists($subTypeName);
114 }
115
116 // If the super type is built-in, check whether casting rules can succeed
117 if (isset(self::$builtInTypes[$superTypeName])) {
118 // Fail immediately in strict mode
119 return $weak && self::isWeakScalarMatch($superTypeName, $subTypeName);
120 }
121
122 // We now know the super type is not built-in and there's no string match, sub type must not be built-in
123 if (isset(self::$builtInTypes[$subTypeName])) {
124 return false;
125 }
126
127 return \is_subclass_of($subTypeName, $superTypeName);
128 }
129}
static isMatch($superTypeName, $superTypeNullable, $subTypeName, $subTypeNullable, $weak)
static isWeakScalarMatch($superTypeName, $subTypeName)