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++;
84 return $this->parameters;
87 public function getRequiredParameterCount() : int{
88 return $this->requiredParameterCount;
91 public function getReturnInfo() : ReturnInfo{
92 return $this->returnInfo;
95 public function isSatisfiedBy(Prototype $callable) : bool{
96 if(!$this->returnInfo->isSatisfiedBy($callable->returnInfo)){
100 if($callable->requiredParameterCount > $this->requiredParameterCount){
106 foreach($callable->parameters as $position => $parameter){
108 if(isset($this->parameters[$position])){
109 if(!$this->parameters[$position]->isSatisfiedBy($parameter)){
113 $last = $this->parameters[$position];
118 if(!$parameter->isOptional && !$parameter->isVariadic){
123 if($last !==
null && $last->isVariadic && !$last->isSatisfiedBy($parameter)){
135 $string =
'function ';
137 if($this->returnInfo->byReference){
144 $l = count($this->parameters) - 1;
145 for(; $i < $l; $i++){
146 $string .= $this->parameters[$i];
148 if($o === 0 && !($this->parameters[$i + 1]->isOptional)){
157 if(isset($this->parameters[$l])){
158 $string .= $this->parameters[$i] .
' ';
162 $string .= str_repeat(
']', $o) .
' ';
167 if($this->returnInfo->type !==
null){
168 $string .=
' : ' . $this->returnInfo->type->stringify();