Inheritance: extends FullyQualifiedClassElement, implements Phan\Language\FQSEN\FullyQualifiedFunctionLikeName
示例#1
0
 /**
  * @return Method[]
  */
 public static function methodListFromReflectionClassAndMethod(Context $context, CodeBase $code_base, \ReflectionClass $class, \ReflectionMethod $reflection_method) : array
 {
     $reflection_method = new \ReflectionMethod($class->getName(), $reflection_method->name);
     $method = new Method($context, $reflection_method->name, new UnionType(), $reflection_method->getModifiers());
     $method->setNumberOfRequiredParameters($reflection_method->getNumberOfRequiredParameters());
     $method->setNumberOfOptionalParameters($reflection_method->getNumberOfParameters() - $reflection_method->getNumberOfRequiredParameters());
     $method->setFQSEN(FullyQualifiedMethodName::fromStringInContext($method->getName(), $context));
     return self::functionListFromFunction($method, $code_base);
 }
示例#2
0
 public function testFullyQualifiedMethodName()
 {
     $this->assertFQSENEqual(FullyQualifiedMethodName::make(FullyQualifiedClassName::make('\\Name\\Space', 'a'), 'f'), '\\Name\\Space\\a::f');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('\\Name\\a::f'), '\\Name\\a::f');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('Name\\a::f'), '\\Name\\a::f');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('\\Name\\Space\\a::f,2'), '\\Name\\Space\\a::f,2');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('\\Name\\Space\\a,1::f,2'), '\\Name\\Space\\a,1::f,2');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromStringInContext('a::methodName', $this->context), '\\a::methodname');
 }
示例#3
0
文件: ContextTest.php 项目: etsy/phan
 public function testSimple()
 {
     $context = new Context();
     $context_namespace = $context->withNamespace('\\A');
     $context_class = $context_namespace->withScope(new ClassScope($context_namespace->getScope(), FullyQualifiedClassName::fromFullyQualifiedString('\\A\\B')));
     $context_method = $context_namespace->withScope(new FunctionLikeScope($context_namespace->getScope(), FullyQualifiedMethodName::fromFullyQualifiedString('\\A\\b::c')));
     $this->assertTrue(!empty($context));
     $this->assertTrue(!empty($context_namespace));
     $this->assertTrue(!empty($context_class));
     $this->assertTrue(!empty($context_method));
 }
示例#4
0
 public function testSimple()
 {
     $context = new Context();
     $context_namespace = $context->withNamespace('\\A');
     $context_class = $context_namespace->withClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString('\\A\\B'));
     $context_method = $context_namespace->withMethodFQSEN(FullyQualifiedMethodName::fromFullyQualifiedString('\\A\\b::c'));
     $this->assertTrue(!empty($context));
     $this->assertTrue(!empty($context_namespace));
     $this->assertTrue(!empty($context_class));
     $this->assertTrue(!empty($context_method));
 }
示例#5
0
文件: File.php 项目: tmli3b3rm4n/phan
 public static function createSchema() : Schema
 {
     $schema = new Schema('File', [new Column('file_path', Column::TYPE_STRING, true), new Column('modification_time', Column::TYPE_INT)]);
     $schema->addAssociation(new ListAssociation('FileClassFQSEN', Column::TYPE_STRING, function (File $file, array $class_fqsen_string_list) {
         $file->getFile()->setClassFQSENList(array_map(function (string $fqsen_string) {
             return FullyQualifiedClassName::fromFullyQualifiedString($fqsen_string);
         }, $class_fqsen_string_list));
     }, function (File $file) {
         return array_map(function (FullyQualifiedClassName $fqsen) {
             return (string) $fqsen;
         }, $file->getFile()->getClassFQSENList());
     }));
     $schema->addAssociation(new ListAssociation('FileMethodFQSEN', Column::TYPE_STRING, function (File $file, array $method_fqsen_string_list) {
         $file->getFile()->setMethodFQSENList(array_map(function (string $fqsen_string) {
             if (false !== strpos($fqsen_string, '::')) {
                 return FullyQualifiedMethodName::fromFullyQualifiedString($fqsen_string);
             } else {
                 return FullyQualifiedFunctionName::fromFullyQualifiedString($fqsen_string);
             }
         }, $method_fqsen_string_list));
     }, function (File $file) {
         return array_map(function (FQSEN $fqsen) {
             return (string) $fqsen;
         }, $file->getFile()->getMethodFQSENList());
     }));
     $schema->addAssociation(new ListAssociation('FilePropertyFQSEN', Column::TYPE_STRING, function (File $file, array $fqsen_string_list) {
         $file->getFile()->setPropertyFQSENList(array_map(function (string $fqsen_string) {
             if (false !== strpos($fqsen_string, '::')) {
                 return FullyQualifiedPropertyName::fromFullyQualifiedString($fqsen_string);
             } else {
                 return FullyQualifiedFunctionName::fromFullyQualifiedString($fqsen_string);
             }
         }, $fqsen_string_list));
     }, function (File $file) {
         return array_map(function (FQSEN $fqsen) {
             return (string) $fqsen;
         }, $file->getFile()->getPropertyFQSENList());
     }));
     $schema->addAssociation(new ListAssociation('FileConstantFQSEN', Column::TYPE_STRING, function (File $file, array $fqsen_string_list) {
         $file->getFile()->setConstantFQSENList(array_map(function (string $fqsen_string) {
             if (false !== strpos($fqsen_string, '::')) {
                 return FullyQualifiedConstantName::fromFullyQualifiedString($fqsen_string);
             } else {
                 return FullyQualifiedFunctionName::fromFullyQualifiedString($fqsen_string);
             }
         }, $fqsen_string_list));
     }, function (File $file) {
         return array_map(function (FQSEN $fqsen) {
             return (string) $fqsen;
         }, $file->getFile()->getConstantFQSENList());
     }));
     return $schema;
 }
示例#6
0
文件: Clazz.php 项目: hslatman/phan
 /**
  * @return Method
  * The method with the given name
  */
 public function getMethodByNameInContext(CodeBase $code_base, string $name, Context $context) : Method
 {
     $method_fqsen = FullyQualifiedMethodName::make($this->getFQSEN(), $name);
     if (!$code_base->hasMethod($method_fqsen)) {
         if ('__construct' === $name) {
             // Create a default constructor if its requested
             // but doesn't exist yet
             $default_constructor = Method::defaultConstructorForClassInContext($this, $this->getContext()->withClassFQSEN($this->getFQSEN()));
             $this->addMethod($code_base, $default_constructor);
             return $default_constructor;
         }
         throw new CodeBaseException("Method with name {$name} does not exist for class {$this->getFQSEN()}.");
     }
     return $code_base->getMethod($method_fqsen);
 }
示例#7
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Decl $node) : Context
 {
     // Bomb out if we're not in a class context
     $clazz = $this->getContextClass();
     $method_name = (string) $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethodWithFQSEN($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     // Create a new context with a new scope
     $context = $this->context->withScope(new Scope());
     $method = Method::fromNode($context, $this->code_base, $node);
     // Override the FQSEN with the found alternate ID
     $method->setFQSEN($method_fqsen);
     $clazz->addMethod($this->code_base, $method);
     if ('__construct' === $method_name) {
         $clazz->setIsParentConstructorCalled(false);
     } elseif ('__invoke' === $method_name) {
         $clazz->getUnionType()->addType(CallableType::instance());
     } elseif ('__toString' === $method_name && !$this->context->getIsStrictTypes()) {
         $clazz->getUnionType()->addType(StringType::instance());
     }
     // Send the context into the method and reset the scope
     $context = $this->context->withMethodFQSEN($method->getFQSEN());
     return $context;
 }
示例#8
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Decl $node) : Context
 {
     // Bomb out if we're not in a class context
     $class = $this->getContextClass();
     $method_name = (string) $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethodWithFQSEN($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     $method = Method::fromNode(clone $this->context, $this->code_base, $node, $method_fqsen);
     $class->addMethod($this->code_base, $method, new None());
     if ('__construct' === $method_name) {
         $class->setIsParentConstructorCalled(false);
         if ($class->isGeneric()) {
             // Get the set of template type identifiers defined on
             // the class
             $template_type_identifiers = array_keys($class->getTemplateTypeMap());
             // Get the set of template type identifiers defined
             // across all parameter types
             $parameter_template_type_identifiers = [];
             foreach ($method->getParameterList() as $parameter) {
                 foreach ($parameter->getUnionType()->getTypeSet() as $type) {
                     if ($type instanceof TemplateType) {
                         $parameter_template_type_identifiers[] = $type->getName();
                     }
                 }
             }
             $missing_template_type_identifiers = array_diff($template_type_identifiers, $parameter_template_type_identifiers);
             if ($missing_template_type_identifiers) {
                 $this->emitIssue(Issue::GenericConstructorTypes, $node->lineno ?? 0, implode(',', $missing_template_type_identifiers), (string) $class->getFQSEN());
             }
         }
     } elseif ('__invoke' === $method_name) {
         $class->getUnionType()->addType(CallableType::instance());
     } elseif ('__toString' === $method_name && !$this->context->getIsStrictTypes()) {
         $class->getUnionType()->addType(StringType::instance());
     }
     // Create a new context with a new scope
     return $this->context->withScope($method->getInternalScope());
 }
示例#9
0
 /**
  * @param FunctionInterface $method
  * Any method
  *
  * @param FullyQualifiedMethodName $fqsen
  * The FQSEN for the method
  *
  * @return null
  */
 private function addMethodWithMethodFQSEN(FunctionInterface $method, FullyQualifiedMethodName $fqsen)
 {
     $this->addMethodInScope($method, $fqsen->getFullyQualifiedClassName());
 }
示例#10
0
 /**
  * @param Node|string $method_name
  * Either then name of the method or a node that
  * produces the name of the method.
  *
  * @param bool $is_static
  * Set to true if this is a static method call
  *
  * @return Method
  * A method with the given name on the class referenced
  * from the given node
  *
  * @throws NodeException
  * An exception is thrown if we can't understand the node
  *
  * @throws CodeBaseExtension
  * An exception is thrown if we can't find the given
  * method
  *
  * @throws TypeException
  * An exception may be thrown if the only viable candidate
  * is a non-class type.
  *
  * @throws IssueException
  */
 public function getMethod($method_name, bool $is_static) : Method
 {
     if ($method_name instanceof Node) {
         // The method_name turned out to be a variable.
         // There isn't much we can do to figure out what
         // it's referring to.
         throw new NodeException($method_name, "Unexpected method node");
     }
     assert(is_string($method_name), "Method name must be a string. Found non-string at {$this->context}");
     try {
         $class_list = (new ContextNode($this->code_base, $this->context, $this->node->children['expr'] ?? $this->node->children['class']))->getClassList();
     } catch (CodeBaseException $exception) {
         throw new IssueException(Issue::fromType(Issue::UndeclaredClassMethod)($this->context->getFile(), $this->node->lineno ?? 0, [$method_name, (string) $exception->getFQSEN()]));
     }
     // If there were no classes on the left-type, figure
     // out what we were trying to call the method on
     // and send out an error.
     if (empty($class_list)) {
         $union_type = UnionTypeVisitor::unionTypeFromClassNode($this->code_base, $this->context, $this->node->children['expr'] ?? $this->node->children['class']);
         if (!$union_type->isEmpty() && $union_type->isNativeType() && !$union_type->hasAnyType([MixedType::instance(), ObjectType::instance(), StringType::instance()]) && !(Config::get()->null_casts_as_any_type && $union_type->hasType(NullType::instance()))) {
             throw new IssueException(Issue::fromType(Issue::NonClassMethodCall)($this->context->getFile(), $this->node->lineno ?? 0, [$method_name, (string) $union_type]));
         }
         throw new NodeException($this->node, "Can't figure out method call for {$method_name}");
     }
     // Hunt to see if any of them have the method we're
     // looking for
     foreach ($class_list as $i => $class) {
         if ($class->hasMethodWithName($this->code_base, $method_name)) {
             return $class->getMethodByNameInContext($this->code_base, $method_name, $this->context);
         } else {
             if ($class->hasMethodWithName($this->code_base, '__call')) {
                 return $class->getMethodByNameInContext($this->code_base, '__call', $this->context);
             }
         }
     }
     // Figure out an FQSEN for the method we couldn't find
     $method_fqsen = FullyQualifiedMethodName::make($class_list[0]->getFQSEN(), $method_name);
     if ($is_static) {
         throw new IssueException(Issue::fromType(Issue::UndeclaredStaticMethod)($this->context->getFile(), $this->node->lineno ?? 0, [(string) $method_fqsen]));
     }
     throw new IssueException(Issue::fromType(Issue::UndeclaredMethod)($this->context->getFile(), $this->node->lineno ?? 0, [(string) $method_fqsen]));
 }
示例#11
0
 /**
  * A list of types for parameters associated with the
  * given builtin function with the given name
  *
  * @param FullyQualifiedMethodName|FullyQualifiedFunctionName $function_fqsen
  *
  * @see internal_varargs_check
  * Formerly `function internal_varargs_check`
  */
 public static function internalFunctionSignatureMapForFQSEN($function_fqsen) : array
 {
     $context = new Context();
     $map = self::internalFunctionSignatureMap();
     if ($function_fqsen instanceof FullyQualifiedMethodName) {
         $class_fqsen = $function_fqsen->getFullyQualifiedClassName();
         $class_name = $class_fqsen->getName();
         $function_name = $class_name . '::' . $function_fqsen->getName();
     } else {
         $function_name = $function_fqsen->getName();
     }
     $function_name_original = $function_name;
     $alternate_id = 0;
     $configurations = [];
     while (isset($map[$function_name])) {
         // Get some static data about the function
         $type_name_struct = $map[$function_name];
         if (empty($type_name_struct)) {
             continue;
         }
         // Figure out the return type
         $return_type_name = array_shift($type_name_struct);
         $return_type = $return_type_name ? UnionType::fromStringInContext($return_type_name, $context) : null;
         $name_type_name_map = $type_name_struct;
         $property_name_type_map = [];
         foreach ($name_type_name_map as $name => $type_name) {
             $property_name_type_map[$name] = empty($type_name) ? new UnionType() : UnionType::fromStringInContext($type_name, $context);
         }
         $configurations[] = ['return_type' => $return_type, 'property_name_type_map' => $property_name_type_map];
         $function_name = $function_name_original . '\'' . ++$alternate_id;
     }
     return $configurations;
 }
示例#12
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Decl $node) : Context
 {
     // Bomb out if we're not in a class context
     $clazz = $this->getContextClass();
     $method_name = (string) $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethod($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     // Create a new context with a new scope
     $context = $this->context->withScope(new Scope());
     // Add $this to the scope of non-static methods
     if (!($node->flags & \ast\flags\MODIFIER_STATIC)) {
         assert($clazz->getContext()->getScope()->hasVariableWithName('this'), "Classes must have a \$this variable.");
         $context = $context->withScopeVariable($clazz->getContext()->getScope()->getVariableWithName('this'));
     }
     $method = Method::fromNode($context, $this->code_base, $node);
     // Override the FQSEN with the found alternate ID
     $method->setFQSEN($method_fqsen);
     $clazz->addMethod($this->code_base, $method);
     if ('__construct' === $method_name) {
         $clazz->setIsParentConstructorCalled(false);
     } else {
         if ('__invoke' === $method_name) {
             $clazz->getUnionType()->addType(CallableType::instance());
         } else {
             if ('__toString' === $method_name && !$this->context->getIsStrictTypes()) {
                 $clazz->getUnionType()->addType(StringType::instance());
             }
         }
     }
     // Add each method parameter to the scope. We clone it
     // so that changes to the variable don't alter the
     // parameter definition
     foreach ($method->getParameterList() as $parameter) {
         $method->getContext()->addScopeVariable(clone $parameter);
     }
     // Send the context into the method and reset the scope
     $context = $method->getContext()->withMethodFQSEN($method->getFQSEN());
     return $context;
 }
示例#13
0
文件: Method.php 项目: ablyler/phan
 /**
  * @return Method
  * A default constructor for the given class
  */
 public static function defaultConstructorForClassInContext(Clazz $clazz, Context $context) : Method
 {
     $method = new Method($context, '__construct', $clazz->getUnionType(), 0);
     $method->setFQSEN(FullyQualifiedMethodName::make($clazz->getFQSEN(), '__construct'));
     return $method;
 }
示例#14
0
 /**
  * @return FullyQualifiedMethodName
  * A fully-qualified method name
  */
 public function withMethodName(string $method_name, int $method_alternate_id = 0) : FullyQualifiedMethodName
 {
     return FullyQualifiedMethodName::make($this, $method_name, $method_alternate_id);
 }
示例#15
0
文件: Method.php 项目: themarios/phan
 /**
  * @return FullyQualifiedFunctionName|FullyQualifiedMethodName
  */
 public function getFQSEN()
 {
     // Allow overrides
     if ($this->fqsen) {
         return $this->fqsen;
     }
     return FullyQualifiedMethodName::fromStringInContext($this->getName(), $this->getContext());
 }
示例#16
0
 /**
  * @return void
  */
 public function unserialize($serialized)
 {
     list($file_ref, $serialized) = explode('^', $serialized);
     parent::unserialize($file_ref);
     list($namespace, $class_fqsen, $method_fqsen, $closure_fqsen) = explode('|', $serialized);
     $this->namespace = $namespace;
     $this->class_fqsen = $class_fqsen ? FullyQualifiedClassName::fromFullyQualifiedString($class_fqsen) : null;
     // Determine if we have a method or a function
     if (false === strpos($method_fqsen, '::')) {
         $this->method_fqsen = $method_fqsen ? FullyQualifiedFunctionName::fromFullyQualifiedString($method_fqsen) : null;
     } else {
         $this->method_fqsen = $method_fqsen ? FullyQualifiedMethodName::fromFullyQualifiedString($method_fqsen) : null;
     }
     $this->closure_fqsen = $closure_fqsen ? FullyQualifiedFunctionName::fromFullyQualifiedString($closure_fqsen) : null;
 }
示例#17
0
 /**
  * Visit a node with kind `\ast\AST_STATIC_CALL`
  *
  * @param Node $node
  * A node of the type indicated by the method name that we'd
  * like to figure out the type that it produces.
  *
  * @return UnionType
  * The set of types that are possibly produced by the
  * given node
  */
 public function visitStaticCall(Node $node) : UnionType
 {
     $class_name = AST::classNameFromNode($this->context, $this->code_base, $node);
     // assert(!empty($class_name), 'Class name cannot be empty');
     if (!$class_name) {
         return new UnionType();
     }
     $method_name = $node->children['method'];
     // Give up on any complicated nonsense where the
     // method name is a variable such as in
     // `$variable->$function_name()`.
     if ($method_name instanceof Node) {
         return new UnionType();
     }
     // Method names can some times turn up being
     // other method calls.
     assert(is_string($method_name), "Method name must be a string. Something else given.");
     $method_fqsen = FullyQualifiedMethodName::make(FullyQualifiedClassName::fromStringInContext($class_name, $this->context), $method_name);
     if (!$this->code_base->hasMethod($method_fqsen)) {
         return new UnionType();
     }
     $method = $this->code_base->getMethod($method_fqsen);
     return $method->getUnionType();
 }
示例#18
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) : 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;
 }
示例#19
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Node $node) : Context
 {
     // Bomb out if we're not in a class context
     $clazz = $this->getContextClass();
     $method_name = $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethod($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     $method = Method::fromNode(clone $this->context, $this->code_base, $node);
     // Override the FQSEN with the found alternate ID
     $method->setFQSEN($method_fqsen);
     $clazz->addMethod($this->code_base, $method);
     if ('__construct' === $method_name) {
         $clazz->setIsParentConstructorCalled(false);
     } else {
         if ('__invoke' === $method_name) {
             $clazz->getUnionType()->addType(CallableType::instance());
         } else {
             if ('__toString' === $method_name) {
                 $clazz->getUnionType()->addType(StringType::instance());
             }
         }
     }
     // Send the context into the method
     $context = $this->context->withMethodFQSEN($method->getFQSEN());
     // Add each method parameter to the scope. We clone it
     // so that changes to the variable don't alter the
     // parameter definition
     foreach ($method->getParameterList() as $parameter) {
         $context->addScopeVariable(clone $parameter);
     }
     return $context;
 }
示例#20
0
 /**
  * @param Node|string $method_name_or_node
  * Either then name of the method or a node that
  * produces the name of the method.
  *
  * @param bool $is_static
  * Set to true if this is a static method call
  *
  * @return Method
  * A method with the given name on the class referenced
  * from the given node
  *
  * @throws NodeException
  * An exception is thrown if we can't understand the node
  *
  * @throws CodeBaseExtension
  * An exception is thrown if we can't find the given
  * method
  *
  * @throws TypeException
  * An exception may be thrown if the only viable candidate
  * is a non-class type.
  */
 public function getMethod($method_name_or_node, bool $is_static) : Method
 {
     $clazz = $this->getClass();
     if ($method_name_or_node instanceof Node) {
         // TODO: The method_name turned out to
         //       be a variable. We'd have to look
         //       that up to figure out what the
         //       string is, but thats a drag.
         throw new NodeException($method_name_or_node, "Unexpected method node");
     }
     $method_name = $method_name_or_node;
     assert(is_string($method_name), "Method name must be a string. Found non-string at {$this->context}");
     if (!$clazz->hasMethodWithName($this->code_base, $method_name)) {
         $method_fqsen = FullyQualifiedMethodName::make($clazz->getFQSEN(), $method_name);
         if ($is_static) {
             throw new CodeBaseException($method_fqsen, "static call to undeclared method {$method_fqsen}");
         } else {
             throw new CodeBaseException($method_fqsen, "call to undeclared method {$method_fqsen}");
         }
     }
     $method = $clazz->getMethodByNameInContext($this->code_base, $method_name, $this->context);
     return $method;
 }
示例#21
0
文件: Method.php 项目: tpunt/phan
 /**
  * @return Method
  * A default constructor for the given class
  */
 public static function defaultConstructorForClassInContext(Clazz $clazz, Context $context, CodeBase $code_base) : Method
 {
     $method_fqsen = FullyQualifiedMethodName::make($clazz->getFQSEN(), '__construct');
     $method = new Method($context, '__construct', $clazz->getUnionType(), 0, $method_fqsen);
     if ($clazz->hasMethodWithName($code_base, $clazz->getName())) {
         $old_style_constructor = $clazz->getMethodByName($code_base, $clazz->getName());
         $method->setParameterList($old_style_constructor->getParameterList());
         $method->setNumberOfRequiredParameters($old_style_constructor->getNumberOfRequiredParameters());
         $method->setNumberOfOptionalParameters($old_style_constructor->getNumberOfOptionalParameters());
     }
     return $method;
 }
示例#22
0
 /**
  * @param Node|string $method_name
  * Either then name of the method or a node that
  * produces the name of the method.
  *
  * @param bool $is_static
  * Set to true if this is a static method call
  *
  * @return Method
  * A method with the given name on the class referenced
  * from the given node
  *
  * @throws NodeException
  * An exception is thrown if we can't understand the node
  *
  * @throws CodeBaseExtension
  * An exception is thrown if we can't find the given
  * method
  *
  * @throws TypeException
  * An exception may be thrown if the only viable candidate
  * is a non-class type.
  */
 public function getMethod($method_name, bool $is_static) : Method
 {
     if ($method_name instanceof Node) {
         // The method_name turned out to be a variable.
         // There isn't much we can do to figure out what
         // it's referring to.
         throw new NodeException($method_name, "Unexpected method node");
     }
     assert(is_string($method_name), "Method name must be a string. Found non-string at {$this->context}");
     try {
         $class_list = (new ContextNode($this->code_base, $this->context, $this->node->children['expr'] ?? $this->node->children['class']))->getClassList();
     } catch (CodeBaseException $exception) {
         // We can give a more explicit message
         throw new CodeBaseException($exception->getFQSEN(), "Can't access method {$method_name} from undeclared class {$exception->getFQSEN()}");
     }
     // If there were no classes on the left-type, figure
     // out what we were trying to call the method on
     // and send out an error.
     if (empty($class_list)) {
         $union_type = UnionTypeVisitor::unionTypeFromClassNode($this->code_base, $this->context, $this->node->children['expr'] ?? $this->node->children['class']);
         if (!$union_type->isEmpty() && $union_type->isNativeType() && !$union_type->hasType(MixedType::instance())) {
             throw new TypeException("Calling method on non-class type {$union_type}");
         }
         throw new NodeException($this->node, "Can't figure out method call for {$method_name}");
     }
     // Hunt to see if any of them have the method we're
     // looking for
     foreach ($class_list as $i => $class) {
         if ($class->hasMethodWithName($this->code_base, $method_name)) {
             return $class->getMethodByNameInContext($this->code_base, $method_name, $this->context);
         }
     }
     // Figure out an FQSEN for the method we couldn't find
     $method_fqsen = FullyQualifiedMethodName::make($class_list[0]->getFQSEN(), $method_name);
     if ($is_static) {
         throw new CodeBaseException($method_fqsen, "static call to undeclared method {$method_fqsen}");
     }
     throw new CodeBaseException($method_fqsen, "call to undeclared method {$method_fqsen}");
 }
示例#23
0
 public function unserialize($serialized)
 {
     list($file_ref, $serialized) = explode('^', $serialized);
     parent::unserialize($file_ref);
     list($namespace, $is_conditional, $class_fqsen, $method_fqsen, $closure_fqsen) = explode('|', $serialized);
     $this->namespace = $namespace;
     $this->is_conditional = (bool) $is_conditional;
     $this->class_fqsen = $class_fqsen ? FullyQualifiedClassName::fromFullyQualifiedString($class_fqsen) : null;
     $this->method_fqsen = $method_fqsen ? FullyQualifiedMethodName::fromFullyQualifiedString($method_fqsen) : null;
     $this->closure_fqsen = $closure_fqsen ? FullyQualifiedFunctionName::fromFullyQualifiedString($closure_fqsen) : null;
 }
示例#24
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) : 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;
 }