Beispiel #1
0
 /**
  * @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);
     $clazz->setFQSEN(FullyQualifiedClassName::fromFullyQualifiedString($row['fqsen']));
     return new Clazz($clazz);
 }
Beispiel #2
0
 /**
  * Visit a node with kind `\ast\AST_CLASS`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitClass(Decl $node) : Context
 {
     if ($node->flags & \ast\flags\CLASS_ANONYMOUS) {
         $class_name = (new ContextNode($this->code_base, $this->context, $node))->getUnqualifiedNameForAnonymousClass();
     } else {
         $class_name = (string) $node->name;
     }
     // This happens now and then and I have no idea
     // why.
     if (empty($class_name)) {
         return $this->context;
     }
     assert(!empty($class_name), "Class must have name in {$this->context}");
     $class_fqsen = FullyQualifiedClassName::fromStringInContext($class_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasClassWithFQSEN($class_fqsen)) {
         $class_fqsen = $class_fqsen->withAlternateId(++$alternate_id);
     }
     // Build the class from what we know so far
     $class_context = $this->context->withLineNumberStart($node->lineno ?? 0)->withLineNumberEnd($node->endLineno ?? -1);
     $clazz = new Clazz($class_context, $class_name, UnionType::fromStringInContext($class_name, $this->context), $node->flags ?? 0);
     // Override the FQSEN with the found alternate ID
     $clazz->setFQSEN($class_fqsen);
     // Get a comment on the class declaration
     $comment = Comment::fromStringInContext($node->docComment ?? '', $this->context);
     $clazz->setIsDeprecated($comment->isDeprecated());
     $clazz->setSuppressIssueList($comment->getSuppressIssueList());
     // Add the class to the code base as a globally
     // accessible object
     $this->code_base->addClass($clazz);
     // Look to see if we have a parent class
     if (!empty($node->children['extends'])) {
         $parent_class_name = $node->children['extends']->children['name'];
         // Check to see if the name isn't fully qualified
         if ($node->children['extends']->flags & \ast\flags\NAME_NOT_FQ) {
             if ($this->context->hasNamespaceMapFor(T_CLASS, $parent_class_name)) {
                 // Get a fully-qualified name
                 $parent_class_name = (string) $this->context->getNamespaceMapFor(T_CLASS, $parent_class_name);
             } else {
                 $parent_class_name = $this->context->getNamespace() . '\\' . $parent_class_name;
             }
         }
         // The name is fully qualified. Make sure it looks
         // like it is
         if (0 !== strpos($parent_class_name, '\\')) {
             $parent_class_name = '\\' . $parent_class_name;
         }
         $parent_fqsen = FullyQualifiedClassName::fromStringInContext($parent_class_name, $this->context);
         // Set the parent for the class
         $clazz->setParentClassFQSEN($parent_fqsen);
     }
     // Add any implemeneted interfaces
     if (!empty($node->children['implements'])) {
         $interface_list = (new ContextNode($this->code_base, $this->context, $node->children['implements']))->getQualifiedNameList();
         foreach ($interface_list as $name) {
             $clazz->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString($name));
         }
     }
     // Update the context to signal that we're now
     // within a class context.
     $context = $class_context->withClassFQSEN($class_fqsen);
     return $context;
 }
Beispiel #3
0
 /**
  * @param CodeBase $code_base
  * A reference to the entire code base in which this
  * context exists
  *
  * @param ReflectionClass $class
  * A reflection class representing a builtin class.
  *
  * @return Clazz
  * A Class structural element representing the given named
  * builtin.
  */
 public static function fromReflectionClass(CodeBase $code_base, \ReflectionClass $class) : Clazz
 {
     // Build a set of flags based on the constitution
     // of the built-in class
     $flags = 0;
     if ($class->isFinal()) {
         $flags = \ast\flags\CLASS_FINAL;
     } elseif ($class->isInterface()) {
         $flags = \ast\flags\CLASS_INTERFACE;
     } elseif ($class->isTrait()) {
         $flags = \ast\flags\CLASS_TRAIT;
     }
     if ($class->isAbstract()) {
         $flags |= \ast\flags\CLASS_ABSTRACT;
     }
     $context = new Context();
     // Build a base class element
     $clazz = new Clazz($context, $class->getName(), UnionType::fromStringInContext($class->getName(), $context), $flags);
     $clazz->setFQSEN(FullyQualifiedClassName::fromStringInContext($class->getName(), $context));
     // If this class has a parent class, add it to the
     // class info
     if ($parent_class = $class->getParentClass()) {
         $parent_class_fqsen = FullyQualifiedClassName::fromFullyQualifiedString('\\' . $parent_class->getName());
         $clazz->setParentClassFQSEN($parent_class_fqsen);
     }
     foreach ($class->getDefaultProperties() as $name => $value) {
         // TODO: whats going on here?
         $reflection_property = new \ReflectionProperty($class->getName(), $name);
         $property_context = $context->withClassFQSEN($clazz->getFQSEN());
         $property = new Property($property_context, $name, Type::fromObject($value)->asUnionType(), 0);
         $property->setFQSEN(FullyQualifiedPropertyName::make($clazz->getFQSEN(), $name));
         $clazz->addProperty($code_base, $property);
     }
     foreach ($class->getInterfaceNames() as $name) {
         $clazz->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString('\\' . $name));
     }
     foreach ($class->getTraitNames() as $name) {
         $clazz->addTraitFQSEN(FullyQualifiedClassName::fromFullyQualifiedString('\\' . $name));
     }
     foreach ($class->getConstants() as $name => $value) {
         $constant = new ClassConstant($context, $name, Type::fromObject($value)->asUnionType(), 0);
         $constant->setFQSEN(FullyQualifiedClassConstantName::make($clazz->getFQSEN(), $name));
         $clazz->addConstant($code_base, $constant);
     }
     foreach ($class->getMethods() as $reflection_method) {
         $method_list = FunctionFactory::methodListFromReflectionClassAndMethod($context->withClassFQSEN($clazz->getFQSEN()), $code_base, $class, $reflection_method);
         foreach ($method_list as $method) {
             $clazz->addMethod($code_base, $method);
         }
     }
     return $clazz;
 }