17 private array $parameters;
19 private int $requiredParameterCount;
26 private static function convertReflectionTypeArray(array $types) : array{
27 return array_map(fn(\ReflectionType $innerType) => self::convertReflectionTypeInner($innerType), $types);
30 private static function convertReflectionTypeInner(\ReflectionType $type) :
BaseType{
32 $type instanceof \ReflectionNamedType =>
36 $type->allowsNull() && $type->getName() !== BuiltInType::MIXED->value ?
39 $type instanceof \ReflectionUnionType =>
new UnionType(self::convertReflectionTypeArray($type->getTypes())),
40 $type instanceof \ReflectionIntersectionType =>
new IntersectionType(self::convertReflectionTypeArray($type->getTypes())),
41 default =>
throw new \AssertionError(
"Unhandled reflection type " . get_class($type))
45 private static function convertReflectionType(?\ReflectionType $type) : ?
BaseType{
46 return $type ===
null ? null : self::convertReflectionTypeInner($type);
49 public static function fromClosure(\Closure $callable) :
Prototype{
50 $reflection = new \ReflectionFunction($callable);
52 $returnType =
new ReturnInfo(self::convertReflectionType($reflection->getReturnType()), $reflection->returnsReference());
56 foreach($reflection->getParameters() as $parameterReflection){
58 $parameterReflection->getName(),
59 self::convertReflectionType($parameterReflection->getType()),
60 $parameterReflection->isPassedByReference(),
61 $parameterReflection->isOptional(),
62 $parameterReflection->isVariadic()
66 return new Prototype($returnType, ...$parameters);
70 $this->returnInfo = $returnType;
71 $this->parameters = $parameters;
72 $this->requiredParameterCount = 0;
73 foreach($parameters as $parameter){
74 if(!$parameter->isOptional && !$parameter->isVariadic){
75 $this->requiredParameterCount++;
80 public function isSatisfiedBy(
Prototype $callable) :
bool{
81 if(!$this->returnInfo->isSatisfiedBy($callable->returnInfo)){
85 if($callable->requiredParameterCount > $this->requiredParameterCount){
91 foreach($callable->parameters as $position => $parameter){
93 if(isset($this->parameters[$position])){
94 if(!$this->parameters[$position]->isSatisfiedBy($parameter)){
98 $last = $this->parameters[$position];
103 if(!$parameter->isOptional && !$parameter->isVariadic){
108 if($last !==
null && $last->isVariadic && !$last->isSatisfiedBy($parameter)){
120 $string =
'function ';
122 if($this->returnInfo->byReference){
129 $l = count($this->parameters) - 1;
130 for(; $i < $l; $i++){
131 $string .= $this->parameters[$i];
133 if($o === 0 && !($this->parameters[$i + 1]->isOptional)){
142 if(isset($this->parameters[$l])){
143 $string .= $this->parameters[$i] .
' ';
147 $string .= str_repeat(
']', $o) .
' ';
152 if($this->returnInfo->type !==
null){
153 $string .=
' : ' . $this->returnInfo->type->stringify();