/** * @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); }
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'); }
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)); }
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)); }
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; }
/** * @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); }
/** * 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; }
/** * 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()); }
/** * @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()); }
/** * @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])); }
/** * 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; }
/** * 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; }
/** * @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; }
/** * @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); }
/** * @return FullyQualifiedFunctionName|FullyQualifiedMethodName */ public function getFQSEN() { // Allow overrides if ($this->fqsen) { return $this->fqsen; } return FullyQualifiedMethodName::fromStringInContext($this->getName(), $this->getContext()); }
/** * @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; }
/** * 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(); }
/** * @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; }
/** * 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; }
/** * @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; }
/** * @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; }
/** * @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}"); }
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; }
/** * @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; }