9 private function __construct(){
13 private static function parameterSatisfiedBy(\ReflectionParameter $prototype, \ReflectionParameter $given) :
bool{
16 $prototype->isPassedByReference() === $given->isPassedByReference() &&
18 !MatchTester::isCovariant($given->getType(), $prototype->getType());
21 public static function isSatisfiedBy(\Closure $prototype, \Closure $callable) :
bool{
22 $prototypeReflect = new \ReflectionFunction($prototype);
23 $callableReflect = new \ReflectionFunction($callable);
25 if($callableReflect->getNumberOfRequiredParameters() > $prototypeReflect->getNumberOfRequiredParameters()){
29 $prototypeReturn = $prototypeReflect->getReturnType();
30 $callableReturn = $callableReflect->getReturnType();
33 $callableReflect->returnsReference() !== $prototypeReflect->returnsReference() ||
34 !MatchTester::isCovariant($prototypeReturn, $callableReturn)
41 $prototypeParameters = $prototypeReflect->getParameters();
42 foreach($callableReflect->getParameters() as $position => $callableParameter){
44 if(isset($prototypeParameters[$position])){
45 $prototypeParameter = $prototypeParameters[$position];
46 if(self::parameterSatisfiedBy($prototypeParameter, $callableParameter)){
50 $last = $prototypeParameter;
55 if(!$callableParameter->isOptional() && !$callableParameter->isVariadic()){
60 if($last !==
null && $last->isVariadic() && !self::parameterSatisfiedBy($last, $callableParameter)){
68 public static function print(\Closure $closure) :
string{
69 $reflect = new \ReflectionFunction($closure);
70 $string =
'function ';
72 if($reflect->returnsReference()){
79 $parameters = $reflect->getParameters();
80 $l = count($parameters) - 1;
82 $parameter = $parameters[$i];
83 $parameterType = $parameter->getType();
85 if($parameterType !==
null){
86 $string .= self::printType($parameterType) .
' ';
89 if($parameter->isPassedByReference()){
93 if($parameter->isVariadic()){
97 $string .=
'$' . $parameter->getName();
99 if($o === 0 && !($parameters[$i + 1]->isOptional())){
108 if(isset($parameters[$l])){
109 $string .= $parameters[$i] .
' ';
113 $string .= str_repeat(
']', $o) .
' ';
118 $returnType = $reflect->getReturnType();
119 if($returnType !==
null){
120 $string .=
' : ' . self::printType($returnType);
129 private static function printTypes(
string $symbol, array $types) :
string{
130 return implode($symbol, array_map(fn(\ReflectionType $type) => self::printType($type), $types));
133 private static function printType(\ReflectionType $type) :
string{
134 if($type instanceof \ReflectionNamedType){
135 return $type->getName();
137 if($type instanceof \ReflectionUnionType){
138 return self::printTypes(
'|', $type->getTypes());
140 if($type instanceof \ReflectionIntersectionType){
141 return self::printTypes(
'&', $type->getTypes());
144 throw new \AssertionError(
"Unhandled reflection type " . get_class($type));