/** * Compare the supplied types for equivalence. * * @param Type $left The left-hand type. * @param Type $right The right-hand type. * * @return integer The comparison result. */ public function compare(Type $left, Type $right) { return $right->accept(new TypeEquivalenceComparatorVisitor($this, $left)); }
/** * Render the supplied type. * * @api * * @param Type $type The type. * * @return string The rendered type. */ public function render(Type $type) { return $type->accept($this); }
/** * @param RuntimeConfiguration $configuration * @param Type $documentedType * @param Type $nativeType * @param integer $depth * * @return boolean */ protected function typeIsCompatible(RuntimeConfiguration $configuration, Type $documentedType, Type $nativeType, $depth = 0) { $this->typeCheck->typeIsCompatible(func_get_args()); // callable if ($this->useNativeCallable($configuration) && $documentedType instanceof CallableType) { return $nativeType instanceof CallableType; } // null if ($documentedType instanceof NullType) { if ($depth < 1) { return $nativeType instanceof MixedType; } return $nativeType instanceof NullType; } // traversable if ($documentedType instanceof TraversableType) { return !$documentedType->primaryType() instanceof ArrayType || $nativeType instanceof TraversableType; } // tuple if ($documentedType instanceof TupleType) { return $nativeType instanceof TraversableType; } // object of type if ($documentedType instanceof ObjectType && null !== $documentedType->ofType()) { if (!$nativeType instanceof ObjectType) { return false; } if ($nativeType->ofType()->isRuntimeEquivalentTo($documentedType->ofType())) { return true; } $documentedClassReflector = new ReflectionClass($documentedType->ofType()->string()); return $documentedClassReflector->isSubclassOf($nativeType->ofType()->string()); } // or type if ($documentedType instanceof OrType) { if ($nativeType instanceof OrType) { foreach ($documentedType->types() as $documentedSubType) { $compatible = false; foreach ($nativeType->types() as $nativeSubType) { $compatible = $this->typeIsCompatible($configuration, $documentedSubType, $nativeSubType, $depth + 1); if ($compatible) { break; } } if (!$compatible) { return false; } } return $compatible; } if (!$nativeType instanceof MixedType) { return false; } $hasArray = false; $hasCallable = false; $hasNull = false; $hasObjectOfType = false; $impossibleNatively = false; foreach ($documentedType->types() as $documentedSubType) { if ($documentedSubType instanceof TraversableType && $documentedSubType->primaryType() instanceof ArrayType) { $hasArray = true; } elseif ($documentedSubType instanceof CallableType) { $hasCallable = true; } elseif ($documentedSubType instanceof NullType) { $hasNull = true; } elseif ($documentedSubType instanceof ObjectType && null !== $documentedSubType->ofType()) { $hasObjectOfType = true; } else { return true; } } return !$this->useNativeCallable($configuration) && $hasCallable || $hasArray && $hasCallable || $hasArray && $hasObjectOfType || $hasCallable && $hasObjectOfType; } // and type if ($documentedType instanceof AndType) { foreach ($documentedType->types() as $documentedSubType) { $compatible = $this->typeIsCompatible($configuration, $documentedSubType, $nativeType, $depth + 1); if ($compatible) { return true; } } return false; } return $nativeType instanceof MixedType; }
/** * @param Type $type * * @return string */ protected function renderTypeName(Type $type) { $this->typeCheck->renderTypeName(func_get_args()); if ($type instanceof NullifiedType) { return $type->originalType()->accept($this->typeRenderer()); } return $type->accept($this->typeRenderer()); }