fromFullyQualifiedString() public static method

public static fromFullyQualifiedString ( string $fully_qualified_string ) : Type
$fully_qualified_string string A fully qualified type name
return Type
Example #1
0
 /**
  * @param string $fully_qualified_string
  * A '|' delimited string representing a type in the form
  * 'int|string|null|ClassName'.
  *
  * @param Context $context
  * The context in which the type string was
  * found
  *
  * @return UnionType
  */
 public static function fromFullyQualifiedString(string $fully_qualified_string) : UnionType
 {
     if (empty($fully_qualified_string)) {
         return new UnionType();
     }
     return new UnionType(array_map(function (string $type_name) {
         return Type::fromFullyQualifiedString($type_name);
     }, explode('|', $fully_qualified_string)));
 }
Example #2
0
 private function visitClassNode(Node $node) : UnionType
 {
     // Things of the form `new $class_name();`
     if ($node->kind == \ast\AST_VAR) {
         return new UnionType();
     }
     // Anonymous class of form `new class { ... }`
     if ($node->kind == \ast\AST_CLASS && $node->flags & \ast\flags\CLASS_ANONYMOUS) {
         // Generate a stable name for the anonymous class
         $anonymous_class_name = (new ContextNode($this->code_base, $this->context, $node))->getUnqualifiedNameForAnonymousClass();
         // Turn that into a fully qualified name
         $fqsen = FullyQualifiedClassName::fromStringInContext($anonymous_class_name, $this->context);
         // Turn that into a union type
         return Type::fromFullyQualifiedString((string) $fqsen)->asUnionType();
     }
     // Things of the form `new $method->name()`
     if ($node->kind !== \ast\AST_NAME) {
         return new UnionType();
     }
     // Get the name of the class
     $class_name = $node->children['name'];
     // If this is a straight-forward class name, recurse into the
     // class node and get its type
     if (!Type::isSelfTypeString($class_name)) {
         // TODO: does anyone else call this method?
         return self::unionTypeFromClassNode($this->code_base, $this->context, $node);
     }
     // This is a self-referential node
     if (!$this->context->isInClassScope()) {
         Log::err(Log::ESTATIC, "Cannot access {$class_name} when not in a class scope", $this->context->getFile(), $node->lineno);
         return new UnionType();
     }
     // Reference to a parent class
     if ($class_name === 'parent') {
         $class = $this->context->getClassInScope($this->code_base);
         if (!$class->hasParentClassFQSEN()) {
             Log::err(Log::ESTATIC, "Reference to parent of parentless class {$class->getFQSEN()}", $this->context->getFile(), $node->lineno);
             return new UnionType();
         }
         return Type::fromFullyQualifiedString((string) $class->getParentClassFQSEN())->asUnionType();
     }
     return Type::fromFullyQualifiedString((string) $this->context->getClassFQSEN())->asUnionType();
 }
Example #3
0
File: Type.php Project: etsy/phan
 /**
  * @param string $fully_qualified_string
  * A fully qualified type name
  *
  * @param Context $context
  * The context in which the type string was
  * found
  *
  * @return UnionType
  */
 public static function fromFullyQualifiedString(string $fully_qualified_string) : Type
 {
     assert(!empty($fully_qualified_string), "Type cannot be empty");
     if (0 !== strpos($fully_qualified_string, '\\')) {
         return self::fromInternalTypeName($fully_qualified_string);
     }
     $tuple = self::typeStringComponents($fully_qualified_string);
     $namespace = $tuple->_0;
     $type_name = $tuple->_1;
     $template_parameter_type_name_list = $tuple->_2;
     // Map the names of the types to actual types in the
     // template parameter type list
     $template_parameter_type_list = array_map(function (string $type_name) {
         return Type::fromFullyQualifiedString($type_name)->asUnionType();
     }, $template_parameter_type_name_list);
     if (0 !== strpos($namespace, '\\')) {
         $namespace = '\\' . $namespace;
     }
     assert(!empty($namespace) && !empty($type_name), "Type was not fully qualified");
     return self::make($namespace, $type_name, $template_parameter_type_list);
 }
 /**
  * @return Type
  * The type of this class
  */
 public function asType() : Type
 {
     return Type::fromFullyQualifiedString((string) $this);
 }
Example #5
0
 /**
  * @param CodeBase $code_base
  * The code base within which we're operating
  *
  * @param $context $context
  * The context of the parser at the node for which we'd
  * like to determine a type
  *
  * @param Node|mixed $node
  * The node for which we'd like to determine its type
  *
  * @return UnionType
  * The UnionType associated with the given node
  * in the given Context within the given CodeBase
  *
  * @throws IssueException
  * An exception is thrown if we can't find a class for
  * the given type
  */
 public static function unionTypeFromClassNode(CodeBase $code_base, Context $context, $node) : UnionType
 {
     // For simple nodes or very complicated nodes,
     // recurse
     if (!$node instanceof \ast\Node || $node->kind != \ast\AST_NAME) {
         return self::unionTypeFromNode($code_base, $context, $node);
     }
     $class_name = $node->children['name'];
     if ('parent' === $class_name) {
         if (!$context->isInClassScope()) {
             throw new IssueException(Issue::fromType(Issue::ContextNotObject)($context->getFile(), $node->lineno ?? 0, [$class_name]));
         }
         $class = $context->getClassInScope($code_base);
         if ($class->isTrait()) {
             throw new IssueException(Issue::fromType(Issue::TraitParentReference)($context->getFile(), $node->lineno ?? 0, [(string) $context->getClassFQSEN()]));
         }
         if (!$class->hasParentType()) {
             throw new IssueException(Issue::fromType(Issue::ParentlessClass)($context->getFile(), $node->lineno ?? 0, [(string) $context->getClassFQSEN()]));
         }
         $parent_class_fqsen = $class->getParentClassFQSEN();
         if (!$code_base->hasClassWithFQSEN($parent_class_fqsen)) {
             throw new IssueException(Issue::fromType(Issue::UndeclaredClass)($context->getFile(), $node->lineno ?? 0, [(string) $parent_class_fqsen]));
         } else {
             $parent_class = $code_base->getClassByFQSEN($parent_class_fqsen);
             return $parent_class->getUnionType();
         }
     }
     // We're going to convert the class reference to a type
     $type = null;
     // Check to see if the name is fully qualified
     if (!($node->flags & \ast\flags\NAME_NOT_FQ)) {
         if (0 !== strpos($class_name, '\\')) {
             $class_name = '\\' . $class_name;
         }
         $type = Type::fromFullyQualifiedString($class_name);
     } else {
         $type = Type::fromStringInContext($class_name, $context);
     }
     return $type->asUnionType();
 }
Example #6
0
 public function testGenericArrayTypeFromString()
 {
     $type = Type::fromFullyQualifiedString("int[][]");
     $this->assertEquals($type->genericArrayElementType()->__toString(), "int[]");
 }
Example #7
0
 /**
  * As per the Serializable interface
  *
  * @param string $serialized
  * A serialized UnionType
  *
  * @return void
  *
  * @see \Serializable
  */
 public function unserialize($serialized)
 {
     $this->type_set = new Set(array_map(function (string $type_name) {
         return Type::fromFullyQualifiedString($type_name);
     }, explode('|', $serialized ?? '')));
 }