public static fromFullyQualifiedString ( string $fully_qualified_string ) : |
||
$fully_qualified_string | string | A '|' delimited string representing a type in the form 'int|string|null|ClassName'. |
return |
/** * @param array * A map from column name to value * * @return Model * An instance of the model derived from row data */ public static function fromRow(array $row) : Clazz { $parent_fqsen = $row['parent_class_fqsen'] ? FullyQualifiedClassName::fromFullyQualifiedString($row['parent_class_fqsen']) : null; $interface_fqsen_list = array_map(function (string $fqsen_string) { return FullyQualifiedClassName::fromFullyQualifiedString($fqsen_string); }, array_filter(explode('|', $row['interface_fqsen_list']))); $trait_fqsen_list = array_map(function (string $fqsen_string) { return FullyQualifiedClassName::fromFullyQualifiedString($fqsen_string); }, array_filter(explode('|', $row['trait_fqsen_list']))); $clazz = new ClazzElement(unserialize(base64_decode($row['context'])), $row['name'], UnionType::fromFullyQualifiedString($row['type']), (int) $row['flags'], $parent_fqsen, $interface_fqsen_list, $trait_fqsen_list); return new Clazz($clazz); }
/** * @return null */ public function addTraitFQSEN(FQSEN $fqsen) { $this->trait_fqsen_list[] = $fqsen; // Add the trait to the union type of this class $this->getUnionType()->addUnionType(UnionType::fromFullyQualifiedString((string) $fqsen)); }
/** * @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 * * @return UnionType * The union type for a node of type \ast\AST_CLASS */ 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']; // 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; } return UnionType::fromFullyQualifiedString($class_name); } if ('parent' === $class_name) { $class = $context->getClassInScope($code_base); $parent_class_fqsen = $class->getParentClassFQSEN(); $parent_class = $code_base->getClassByFQSEN($parent_class_fqsen); return $parent_class->getUnionType(); } return UnionType::fromStringInContext($class_name, $context); }
/** * @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']; // 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; } return UnionType::fromFullyQualifiedString($class_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->hasParentClassFQSEN()) { 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(); } } return UnionType::fromStringInContext($class_name, $context); }
/** * @param array * A map from column name to value * * @return Model * An instance of the model derived from row data */ public static function fromRow(array $row) : Method { list($scope, $name) = explode('|', $row['scope_name']); return new Method(new MethodElement(unserialize(base64_decode($row['context'])), $row['name'], UnionType::fromFullyQualifiedString($row['type']), (int) $row['flags'], $row['number_of_required_parameters'], $row['number_of_optional_parameters'], (bool) $row['is_dynamic']), $scope, $name); }
/** * @return UnionType|null * Returns UnionType (Possible with empty set) if and only if isHardcodedGlobalVariableWithName is true. * Returns null otherwise. */ public static function getUnionTypeOfHardcodedGlobalVariableWithName(string $name, Context $context) { if (array_key_exists($name, self::_BUILTIN_SUPERGLOBAL_TYPES)) { // More efficient than using context. return UnionType::fromFullyQualifiedString(self::_BUILTIN_SUPERGLOBAL_TYPES[$name]); } if (array_key_exists($name, Config::get()->globals_type_map) || in_array($name, Config::get()->runkit_superglobals)) { $type_string = Config::get()->globals_type_map[$name] ?? ''; return UnionType::fromStringInContext($type_string, $context); } return null; }
/** * @param array * A map from column name to value * * @return Model * An instance of the model derived from row data */ public static function fromRow(array $row) : Parameter { if (false !== strpos($row['method_fqsen'], '::')) { $method_fqsen = FullyQualifiedMethodName::fromFullyQualifiedString($row['method_fqsen']); } else { $method_fqsen = FullyQualifiedFunctionName::fromFullyQualifiedString($row['method_fqsen']); } $primary_key_value = $row['id'] ?? null; $parameter = new Parameter(new ParameterElement(unserialize(base64_decode($row['context'])), $row['name'], UnionType::fromFullyQualifiedString($row['type']), (int) $row['flags']), $method_fqsen, $primary_key_value); return $parameter; }
/** * Get a fully qualified name form a node * * @return string * * @see \Phan\Deprecated\Util::qualified_name * From `function qualified_name` */ public static function qualifiedName(Context $context, $node) : string { if (!$node instanceof \ast\Node || $node->kind != \ast\AST_NAME) { return (string) self::varUnionType($context, $node); } $type_name = $node->children['name']; $type = null; // Check to see if the name is fully qualified if (!($node->flags & \ast\flags\NAME_NOT_FQ)) { if (0 !== strpos($type_name, '\\')) { $type_name = '\\' . $type_name; } return (string) UnionType::fromFullyQualifiedString($type_name); } $type = UnionType::fromStringInContext($type_name, $context); return (string) $type; }
/** * Look at elements of the form `is_array($v)` and modify * the type of the variable. * * @param Node $node * A node to parse * * @return Context * A new or an unchanged context resulting from * parsing the node */ public function visitCall(Node $node) : Context { // Only look at things of the form // `is_string($variable)` if (count($node->children['args']->children) !== 1 || !$node->children['args']->children[0] instanceof Node || $node->children['args']->children[0]->kind !== \ast\AST_VAR || !$node->children['expr'] instanceof Node || empty($node->children['expr']->children['name'] ?? null) || !is_string($node->children['expr']->children['name'])) { return $this->context; } // Translate the function name into the UnionType it asserts $map = array('is_array' => 'array', 'is_bool' => 'bool', 'is_callable' => 'callable', 'is_double' => 'float', 'is_float' => 'float', 'is_int' => 'int', 'is_integer' => 'int', 'is_long' => 'int', 'is_null' => 'null', 'is_numeric' => 'string|int|float', 'is_object' => 'object', 'is_real' => 'float', 'is_resource' => 'resource', 'is_scalar' => 'int|float|bool|string|null', 'is_string' => 'string', 'empty' => 'null'); $functionName = $node->children['expr']->children['name']; if (!isset($map[$functionName])) { return $this->context; } $type = UnionType::fromFullyQualifiedString($map[$functionName]); $context = $this->context; try { // Get the variable we're operating on $variable = (new ContextNode($this->code_base, $this->context, $node->children['args']->children[0]))->getVariable(); if ($variable->getUnionType()->isEmpty()) { $variable->getUnionType()->addType(NullType::instance()); } // Make a copy of the variable $variable = clone $variable; $variable->setUnionType(clone $variable->getUnionType()); // Change the type to match the is_a relationship if ($type->isType(ArrayType::instance()) && $variable->getUnionType()->hasGenericArray()) { // If the variable is already a generic array, // note that it can be an arbitrary array without // erasing the existing generic type. $variable->getUnionType()->addUnionType($type); } else { // Otherwise, overwrite the type for any simple // primitive types. $variable->setUnionType($type); } // Overwrite the variable with its new type in this // scope without overwriting other scopes $context = $context->withScopeVariable($variable); } catch (\Exception $exception) { // Swallow it } return $context; }
/** * @param array * A map from column name to value * * @return Constant * An instance of the model derived from row data */ public static function fromRow(array $row) : Constant { list($scope, $name) = explode('|', $row['scope_name']); $constant = new Constant(new ConstantElement(unserialize(base64_decode($row['context'])), $row['name'], UnionType::fromFullyQualifiedString($row['type']), (int) $row['flags']), $scope, $name); if (false !== strpos($row['fqsen'], '::')) { $fqsen = FullyQualifiedClassConstantName::fromFullyQualifiedString($row['fqsen']); } else { $fqsen = FullyQualifiedGlobalConstantName::fromFullyQualifiedString($row['fqsen']); } $constant->getConstant()->setFQSEN($fqsen); return $constant; }
/** * @param array * A map from column name to value * * @return Model * An instance of the model derived from row data */ public static function fromRow(array $row) : Property { list($scope, $name) = explode('|', $row['scope_name']); $property = new Property(new PropertyElement(unserialize(base64_decode($row['context'])), $row['name'], UnionType::fromFullyQualifiedString($row['type']), (int) $row['flags']), $scope, $name); return $property; }
/** * @param array * A map from column name to value * * @return Model * An instance of the model derived from row data */ public static function fromRow(array $row) : Method { list($scope, $name) = explode('|', $row['scope_name']); $method_element = new MethodElement(unserialize(base64_decode($row['context'])), $row['name'], UnionType::fromFullyQualifiedString($row['type']), (int) $row['flags']); $method_element->setNumberOfRequiredParameters($row['number_of_required_parameters']); $method_element->setNumberOfOptionalParameters($row['number_of_optional_parameters']); $method = new Method($method_element, $scope, $name); if (false !== strpos($row['fqsen'], '::')) { $fqsen = FullyQualifiedMethodName::fromFullyQualifiedString($row['fqsen']); } else { $fqsen = FullyQualifiedFunctionName::fromFullyQualifiedString($row['fqsen']); } $method->getMethod()->setFQSEN($fqsen); return $method; }