/** * @param Stmt $classStmt * @param $namespace * @param $source * @return Element\ClassModel */ public function parse(Stmt $classStmt, $namespace, $source) { $attrs = $classStmt->getAttributes(); $class = $this->classFactory->create($classStmt->name); $class->setNamespace($namespace); $class->setSource($source, $attrs['startLine'], 0); // annotation $this->commentsParser->parse($attrs, $class); // property $properties = array_filter($classStmt->stmts, function ($stmt) { return $this->propertyParser->match($stmt); }); array_map(function (Stmt $propertiesStmt) use($class) { $prop = $this->propertyParser->parse($propertiesStmt, $class); $this->propertyAnnotationParser->parse($propertiesStmt, $prop, $class); $varAnnotations = $prop->annotations->withName('var'); if (!$varAnnotations->isEmpty()) { /** @var Element\Annotation $var */ $var = $varAnnotations->first(); $prop->setAccessModifier($var->parameters); } }, $properties); // method $methods = array_filter($classStmt->stmts, function ($stmt) { return $this->methodParser->match($stmt); }); array_map(function ($methodStmt) use($class) { $this->methodParser->parse($methodStmt, $class); }, $methods); return $class; }
/** * @param Stmt $stmt * @param Context $context * @return bool */ public function pass(Stmt $stmt, Context $context) { if ($stmt->getDocComment() === null) { $context->notice('missing_docblock', 'Missing Docblock', $stmt); return true; } return false; }
/** * @inheritdoc * @param Stmt\ClassMethod $function */ public function createFunction(Stmt $function) { assert($function instanceof Stmt\ClassMethod, 'Only accepts class methods'); if ($function->isStatic()) { return $this->traitCreateFunction($function); } else { return $this->instanceEnvironment->createFunction($function); } }
/** * @param \PhpParser\Node\Stmt $context * @return int */ public static function getForContext(Stmt $context) { if ($context->isPublic()) { return Class_::MODIFIER_PUBLIC; } elseif ($context->isProtected()) { return Class_::MODIFIER_PROTECTED; } else { return Class_::MODIFIER_PRIVATE; } }
/** * @param Stmt\ClassMethod|Stmt\Function_ $stmt * @param Context $context * @return bool */ private function inspectParams(Stmt $stmt, Context $context) { /** @var \PhpParser\Node\Param $param */ foreach ($stmt->getParams() as $param) { if ($param->name === 'this') { $context->notice('unexpected_use.this', sprintf('Method/Function %s can not have a parameter named "this".', $stmt->name), $param); return true; } } return false; }
/** * @param Stmt $func * @param Context $context * @return bool */ public function pass(Stmt $func, Context $context) { $prevIsOptional = false; foreach ($func->getParams() as $param) { if ($prevIsOptional && $param->default === null) { $context->notice('optional-param-before-required', 'Optional parameter before required one is always required.', $func); return true; } $prevIsOptional = $param->default !== null; } return false; }
/** * @param Stmt $stmt * @param Context $context * @return bool */ public function pass(Stmt $stmt, Context $context) { // if it is private, protected or public return false if ($stmt->isPrivate() || $stmt->isProtected() || ($stmt->type & Class_::MODIFIER_PUBLIC) !== 0) { return false; } if ($stmt instanceof Property) { $context->notice('missing_visibility', 'Class property was defined with the deprecated var keyword. Use a visibility modifier instead.', $stmt); } elseif ($stmt instanceof ClassMethod) { $context->notice('missing_visibility', 'Class method was defined without a visibility modifier.', $stmt); } return true; }
/** * Constructs a try catch node. * * @param Node[] $stmts Statements * @param Catch_[] $catches Catches * @param null|Finally_ $finally Optionaly finally node * @param array|null $attributes Additional attributes */ public function __construct(array $stmts, array $catches, Finally_ $finally = null, array $attributes = array()) { parent::__construct($attributes); $this->stmts = $stmts; $this->catches = $catches; $this->finally = $finally; }
/** * Constructs a try catch node. * * @param Node[] $stmts Statements * @param Catch_[] $catches Catches * @param Node[] $finallyStmts Finally statements (null means no finally clause) * @param array|null $attributes Additional attributes */ public function __construct(array $stmts, array $catches, array $finallyStmts = null, array $attributes = array()) { if (empty($catches) && null === $finallyStmts) { throw new Error('Cannot use try without catch or finally'); } parent::__construct(array('stmts' => $stmts, 'catches' => $catches, 'finallyStmts' => $finallyStmts), $attributes); }
/** * Constructs a group use node. * * @param Name $prefix * Prefix for uses * @param UseUse[] $uses * Uses * @param int $type * Type of group use * @param array $attributes * Additional attributes */ public function __construct(Name $prefix, array $uses, $type = Use_::TYPE_NORMAL, array $attributes = array()) { parent::__construct($attributes); $this->type = $type; $this->prefix = $prefix; $this->uses = $uses; }
/** * Constructs a catch node. * * @param Node\Name $type * Class of exception * @param string $var * Variable for exception * @param Node[] $stmts * Statements * @param array $attributes * Additional attributes */ public function __construct(Node\Name $type, $var, array $stmts = array(), array $attributes = array()) { parent::__construct($attributes); $this->type = $type; $this->var = $var; $this->stmts = $stmts; }
/** * Constructs a class property list node. * * @param int $flags Modifiers * @param PropertyProperty[] $props Properties * @param array $attributes Additional attributes */ public function __construct($flags, array $props, array $attributes = array()) { parent::__construct($attributes); $this->flags = $flags; $this->type = $flags; $this->props = $props; }
/** * Constructs a catch node. * * @param Node\Name[] $types Types of exceptions to catch * @param string $var Variable for exception * @param Node[] $stmts Statements * @param array $attributes Additional attributes */ public function __construct(array $types, $var, array $stmts = array(), array $attributes = array()) { parent::__construct($attributes); $this->types = $types; $this->var = $var; $this->stmts = $stmts; }
/** * Constructs a for loop node. * * @param array $subNodes Array of the following optional subnodes: * 'init' => array(): Init expressions * 'cond' => array(): Loop conditions * 'loop' => array(): Loop expressions * 'stmts' => array(): Statements * @param array $attributes Additional attributes */ public function __construct(array $subNodes = array(), array $attributes = array()) { parent::__construct(null, $attributes); $this->init = isset($subNodes['init']) ? $subNodes['init'] : array(); $this->cond = isset($subNodes['cond']) ? $subNodes['cond'] : array(); $this->loop = isset($subNodes['loop']) ? $subNodes['loop'] : array(); $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array(); }
/** * Constructs an if node. * * @param Node\Expr $cond Condition * @param array $subNodes Array of the following optional subnodes: * 'stmts' => array(): Statements * 'elseifs' => array(): Elseif clauses * 'else' => null : Else clause * @param array $attributes Additional attributes */ public function __construct(Node\Expr $cond, array $subNodes = array(), array $attributes = array()) { parent::__construct($attributes); $this->cond = $cond; $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array(); $this->elseifs = isset($subNodes['elseifs']) ? $subNodes['elseifs'] : array(); $this->else = isset($subNodes['else']) ? $subNodes['else'] : null; }
/** * @param Stmt $stmt * @param Context $context * @return bool */ public function pass(Stmt $stmt, Context $context) { if ($stmt instanceof Stmt\ClassMethod && $stmt->isAbstract()) { // abstract classes are ok return false; } if ($stmt instanceof Stmt\Switch_) { $counting = $stmt->cases; } else { $counting = $stmt->stmts; } if (count($counting) === 0) { $context->notice('missing_body', 'Missing Body', $stmt); return true; } return false; }
/** * Constructs a function node. * * @param string $name Name * @param array $subNodes Array of the following optional subnodes: * 'byRef' => false : Whether to return by reference * 'params' => array(): Parameters * 'returnType' => null : Return type * 'stmts' => array(): Statements * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = array(), array $attributes = array()) { parent::__construct($attributes); $this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : false; $this->name = $name; $this->params = isset($subNodes['params']) ? $subNodes['params'] : array(); $this->returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null; $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array(); }
/** * Constructs a foreach node. * * @param Node\Expr $expr * Expression to iterate * @param Node\Expr $valueVar * Variable to assign value to * @param array $subNodes * Array of the following optional subnodes: * 'keyVar' => null : Variable to assign key to * 'byRef' => false : Whether to assign value by reference * 'stmts' => array(): Statements * @param array $attributes * Additional attributes */ public function __construct(Node\Expr $expr, Node\Expr $valueVar, array $subNodes = array(), array $attributes = array()) { parent::__construct(null, $attributes); $this->expr = $expr; $this->keyVar = isset($subNodes['keyVar']) ? $subNodes['keyVar'] : null; $this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : false; $this->valueVar = $valueVar; $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array(); }
/** * Constructs an alias (use) node. * * @param Node\Name $name Namespace/Class to alias * @param null|string $alias Alias * @param int $type Type of the use element (for mixed group use declarations only) * @param array $attributes Additional attributes */ public function __construct(Node\Name $name, $alias = null, $type = Use_::TYPE_UNKNOWN, array $attributes = array()) { if (null === $alias) { $alias = $name->getLast(); } parent::__construct($attributes); $this->type = $type; $this->name = $name; $this->alias = $alias; }
/** * Constructs an alias (use) node. * * @param Node\Name $name Namespace/Class to alias * @param null|string $alias Alias * @param array $attributes Additional attributes */ public function __construct(Node\Name $name, $alias = null, array $attributes = array()) { if (null === $alias) { $alias = $name->getLast(); } if ('self' == $alias || 'parent' == $alias) { throw new Error(sprintf('Cannot use %s as %s because \'%2$s\' is a special class name', $name, $alias)); } parent::__construct(array('name' => $name, 'alias' => $alias), $attributes); }
/** * Constructs a try catch node. * * @param Node[] $stmts * Statements * @param Catch_[] $catches * Catches * @param null|Node[] $finallyStmts * Finally statements (null means no finally clause) * @param array|null $attributes * Additional attributes */ public function __construct(array $stmts, array $catches, array $finallyStmts = null, array $attributes = array()) { if (empty($catches) && null === $finallyStmts) { throw new Error('Cannot use try without catch or finally'); } parent::__construct($attributes); $this->stmts = $stmts; $this->catches = $catches; $this->finallyStmts = $finallyStmts; }
/** * Constructs a class node. * * @param string $name Name * @param array $subNodes Array of the following optional subnodes: * 'extends' => array(): Name of extended interfaces * 'stmts' => array(): Statements * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = array(), array $attributes = array()) { parent::__construct(array('name' => $name, 'extends' => isset($subNodes['extends']) ? $subNodes['extends'] : array(), 'stmts' => isset($subNodes['stmts']) ? $subNodes['stmts'] : array()), $attributes); if (isset(self::$specialNames[(string) $this->name])) { throw new Error(sprintf('Cannot use \'%s\' as class name as it is reserved', $this->name)); } foreach ($this->extends as $interface) { if (isset(self::$specialNames[(string) $interface])) { throw new Error(sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface)); } } }
/** * Constructs an alias (use) node. * * @param Node\Name $name Namespace/Class to alias * @param null|string $alias Alias * @param array $attributes Additional attributes */ public function __construct(Node\Name $name, $alias = null, array $attributes = array()) { if (null === $alias) { $alias = $name->getLast(); } if ('self' == strtolower($alias) || 'parent' == strtolower($alias)) { throw new Error(sprintf('Cannot use %s as %s because \'%2$s\' is a special class name', $name, $alias)); } parent::__construct(null, $attributes); $this->name = $name; $this->alias = $alias; }
/** * Constructs a class property list node. * * @param int $type * Modifiers * @param PropertyProperty[] $props * Properties * @param array $attributes * Additional attributes */ public function __construct($type, array $props, array $attributes = array()) { if ($type & Class_::MODIFIER_ABSTRACT) { throw new Error('Properties cannot be declared abstract'); } if ($type & Class_::MODIFIER_FINAL) { throw new Error('Properties cannot be declared final'); } parent::__construct($attributes); $this->type = $type; $this->props = $props; }
/** * Constructs a namespace node. * * @param null|Node\Name $name Name * @param Node[] $stmts Statements * @param array $attributes Additional attributes */ public function __construct(Node\Name $name = null, $stmts = array(), array $attributes = array()) { parent::__construct(array('name' => $name, 'stmts' => $stmts), $attributes); if (isset(self::$specialNames[(string) $this->name])) { throw new Error(sprintf('Cannot use \'%s\' as namespace name', $this->name)); } if (null !== $this->stmts) { foreach ($this->stmts as $stmt) { if ($stmt instanceof self) { throw new Error('Namespace declarations cannot be nested', $stmt->getLine()); } } } }
/** * Constructs a class property list node. * * @param int $type Modifiers * @param PropertyProperty[] $props Properties * @param array $attributes Additional attributes */ public function __construct($type, array $props, array $attributes = array()) { if (0 === ($type & Class_::VISIBILITY_MODIFER_MASK)) { // If no visibility modifier given, PHP defaults to public $type |= Class_::MODIFIER_PUBLIC; } if ($type & Class_::MODIFIER_ABSTRACT) { throw new Error('Properties cannot be declared abstract'); } if ($type & Class_::MODIFIER_FINAL) { throw new Error('Properties cannot be declared final'); } parent::__construct(array('type' => $type, 'props' => $props), $attributes); }
/** * Constructs a class method node. * * @param string $name Name * @param array $subNodes Array of the following optional subnodes: * 'type' => MODIFIER_PUBLIC: Type * 'byRef' => false : Whether to return by reference * 'params' => array() : Parameters * 'stmts' => array() : Statements * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = array(), array $attributes = array()) { parent::__construct(array('type' => isset($subNodes['type']) ? $subNodes['type'] : Class_::MODIFIER_PUBLIC, 'byRef' => isset($subNodes['byRef']) ? $subNodes['byRef'] : false, 'name' => $name, 'params' => isset($subNodes['params']) ? $subNodes['params'] : array(), 'stmts' => array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : array()), $attributes); if ($this->type & Class_::MODIFIER_STATIC) { switch (strtolower($this->name)) { case '__construct': throw new Error(sprintf('Constructor %s() cannot be static', $this->name)); case '__destruct': throw new Error(sprintf('Destructor %s() cannot be static', $this->name)); case '__clone': throw new Error(sprintf('Clone method %s() cannot be static', $this->name)); } } }
/** * @param Stmt $propertyStmt * @param Element\Property $property * @param Element\ClassModel $class * @return Element\Annotation\AnnotationCollection */ public function parse(Stmt $propertyStmt, Element\Property $property, Element\ClassModel $class) { // annotation $attrs = $propertyStmt->getAttributes(); $this->commentsParser->parse($attrs, $property); $vars = $property->annotations->withName('var'); if ($vars->count()) { /** @var Element\Annotation $var */ $var = $vars->first(); if (!is_array($var->parameters)) { // classのuseにあるものだけにする(FQCN形式等は要検討) // 型が単純なクラス名ではなくて Element\Annotation のような形式になっている場合は、Element 部分が use にあればOK if ($searchAlias = strstr($var->parameters, '\\', true) === false) { $searchAlias = $var->parameters; } $classReferences = $class->references->withAlias($searchAlias); if ($classReferences->count()) { $ref = $this->referenceFactory->create($var->parameters, null); $property->reference = $ref; } } } return $property->annotations; }
/** * Constructs a namespace node. * * @param null|Node\Name $name Name * @param null|Node[] $stmts Statements * @param array $attributes Additional attributes */ public function __construct(Node\Name $name = null, $stmts = array(), array $attributes = array()) { parent::__construct(null, $attributes); $this->name = $name; $this->stmts = $stmts; if (isset(self::$specialNames[strtolower($this->name)])) { throw new Error(sprintf('Cannot use \'%s\' as namespace name', $this->name), $this->name->getAttributes()); } if (null !== $this->stmts) { foreach ($this->stmts as $stmt) { if ($stmt instanceof self) { throw new Error('Namespace declarations cannot be nested', $stmt->getAttributes()); } } } }
/** * Constructs a class method node. * * @param string $name Name * @param array $subNodes Array of the following optional subnodes: * 'type' => MODIFIER_PUBLIC: Type * 'byRef' => false : Whether to return by reference * 'params' => array() : Parameters * 'stmts' => array() : Statements * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = array(), array $attributes = array()) { $type = isset($subNodes['type']) ? $subNodes['type'] : 0; if (0 === ($type & Class_::VISIBILITY_MODIFER_MASK)) { // If no visibility modifier given, PHP defaults to public $type |= Class_::MODIFIER_PUBLIC; } parent::__construct(array('type' => $type, 'byRef' => isset($subNodes['byRef']) ? $subNodes['byRef'] : false, 'name' => $name, 'params' => isset($subNodes['params']) ? $subNodes['params'] : array(), 'stmts' => array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : array()), $attributes); if ($this->type & Class_::MODIFIER_STATIC) { switch (strtolower($this->name)) { case '__construct': throw new Error(sprintf('Constructor %s() cannot be static', $this->name)); case '__destruct': throw new Error(sprintf('Destructor %s() cannot be static', $this->name)); case '__clone': throw new Error(sprintf('Clone method %s() cannot be static', $this->name)); } } }