PocketMine-MP 5.18.2 git-00e39821f06a4b6d728d35053c2621dbb19369ff
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 ];
26
31 private static $scalarTypes = [
32 BuiltInTypes::STRING => true,
33 BuiltInTypes::INT => true,
34 BuiltInTypes::FLOAT => true,
35 BuiltInTypes::BOOL => true,
36 ];
37
43 public static function isWeakScalarMatch($superTypeName, $subTypeName)
44 {
45 // Nothing else satisfies array, callable, void or iterable
46 if (!isset(self::$scalarTypes[$superTypeName])) {
47 return false;
48 }
49
50 // Scalars can all cast to each other
51 if (isset(self::$scalarTypes[$subTypeName])) {
52 return true;
53 }
54
55 // Classes with __toString() satisfy string
56 if ($superTypeName === BuiltInTypes::STRING && \method_exists($subTypeName, '__toString')) {
57 return true;
58 }
59
60 return false;
61 }
62
71 public static function isMatch($superTypeName, $superTypeNullable, $subTypeName, $subTypeNullable, $weak)
72 {
73 // If the super type is unspecified, anything is a match
74 if ($superTypeName === null) {
75 return true;
76 }
77
78 // If the sub type is unspecified, nothing is a match
79 if ($subTypeName === null) {
80 return false;
81 }
82
83 $superTypeName = (string)$superTypeName;
84 $subTypeName = (string)$subTypeName;
85
86 // Sub type cannot be nullable unless the super type is as well
87 if ($subTypeNullable && !$superTypeNullable) {
88 // nullable void doesn't really make sense but for completeness...
89 return $superTypeName === BuiltInTypes::VOID && $subTypeName === BuiltInTypes::VOID;
90 }
91
92 // If the string is an exact match it's definitely acceptable
93 if ($superTypeName === $subTypeName) {
94 return true;
95 }
96
97 // Check iterable
98 if ($superTypeName === BuiltInTypes::ITERABLE) {
99 return $subTypeName === BuiltInTypes::ARRAY
100 || $subTypeName === \Traversable::class
101 || \is_subclass_of($subTypeName, \Traversable::class);
102 }
103
104 // Check callable
105 if ($superTypeName === BuiltInTypes::CALLABLE) {
106 return $subTypeName === \Closure::class
107 || \method_exists($subTypeName, '__invoke')
108 || \is_subclass_of($subTypeName, \Closure::class);
109 }
110
111 // If the super type is built-in, check whether casting rules can succeed
112 if (isset(self::$builtInTypes[$superTypeName])) {
113 // Fail immediately in strict mode
114 return $weak && self::isWeakScalarMatch($superTypeName, $subTypeName);
115 }
116
117 // We now know the super type is not built-in and there's no string match, sub type must not be built-in
118 if (isset(self::$builtInTypes[$subTypeName])) {
119 return false;
120 }
121
122 return \is_subclass_of($subTypeName, $superTypeName);
123 }
124}
static isMatch($superTypeName, $superTypeNullable, $subTypeName, $subTypeNullable, $weak)
Definition: MatchTester.php:71
static isWeakScalarMatch($superTypeName, $subTypeName)
Definition: MatchTester.php:43