1<?php
2/**
3 * This file is part of phpDocumentor.
4 *
5 * For the full copyright and license information, please view the LICENSE
6 * file that was distributed with this source code.
7 *
8 * @copyright 2010-2015 Mike van Riel<mike@phpdoc.org>
9 * @license   http://www.opensource.org/licenses/mit-license.php MIT
10 * @link      http://phpdoc.org
11 */
12
13namespace phpDocumentor\Reflection\DocBlock\Tags;
14
15use phpDocumentor\Reflection\DocBlock\Description;
16use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
17use phpDocumentor\Reflection\Type;
18use phpDocumentor\Reflection\TypeResolver;
19use phpDocumentor\Reflection\Types\Context as TypeContext;
20use Webmozart\Assert\Assert;
21
22/**
23 * Reflection class for the {@}param tag in a Docblock.
24 */
25final class Param extends BaseTag implements Factory\StaticMethod
26{
27    /** @var string */
28    protected $name = 'param';
29
30    /** @var Type */
31    private $type;
32
33    /** @var string */
34    private $variableName = '';
35
36    /** @var bool determines whether this is a variadic argument */
37    private $isVariadic = false;
38
39    /**
40     * @param string $variableName
41     * @param Type $type
42     * @param bool $isVariadic
43     * @param Description $description
44     */
45    public function __construct($variableName, Type $type = null, $isVariadic = false, Description $description = null)
46    {
47        Assert::string($variableName);
48        Assert::boolean($isVariadic);
49
50        $this->variableName = $variableName;
51        $this->type = $type;
52        $this->isVariadic = $isVariadic;
53        $this->description = $description;
54    }
55
56    /**
57     * {@inheritdoc}
58     */
59    public static function create(
60        $body,
61        TypeResolver $typeResolver = null,
62        DescriptionFactory $descriptionFactory = null,
63        TypeContext $context = null
64    ) {
65        Assert::stringNotEmpty($body);
66        Assert::allNotNull([$typeResolver, $descriptionFactory]);
67
68        $parts = preg_split('/(\s+)/Su', $body, 3, PREG_SPLIT_DELIM_CAPTURE);
69        $type = null;
70        $variableName = '';
71        $isVariadic = false;
72
73        // if the first item that is encountered is not a variable; it is a type
74        if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] !== '$')) {
75            $type = $typeResolver->resolve(array_shift($parts), $context);
76            array_shift($parts);
77        }
78
79        // if the next item starts with a $ or ...$ it must be the variable name
80        if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] === '$' || substr($parts[0], 0, 4) === '...$')) {
81            $variableName = array_shift($parts);
82            array_shift($parts);
83
84            if (substr($variableName, 0, 3) === '...') {
85                $isVariadic = true;
86                $variableName = substr($variableName, 3);
87            }
88
89            if (substr($variableName, 0, 1) === '$') {
90                $variableName = substr($variableName, 1);
91            }
92        }
93
94        $description = $descriptionFactory->create(implode('', $parts), $context);
95
96        return new static($variableName, $type, $isVariadic, $description);
97    }
98
99    /**
100     * Returns the variable's name.
101     *
102     * @return string
103     */
104    public function getVariableName()
105    {
106        return $this->variableName;
107    }
108
109    /**
110     * Returns the variable's type or null if unknown.
111     *
112     * @return Type|null
113     */
114    public function getType()
115    {
116        return $this->type;
117    }
118
119    /**
120     * Returns whether this tag is variadic.
121     *
122     * @return boolean
123     */
124    public function isVariadic()
125    {
126        return $this->isVariadic;
127    }
128
129    /**
130     * Returns a string representation for this tag.
131     *
132     * @return string
133     */
134    public function __toString()
135    {
136        return ($this->type ? $this->type . ' ' : '')
137        . ($this->isVariadic() ? '...' : '')
138        . '$' . $this->variableName
139        . ($this->description ? ' ' . $this->description : '');
140    }
141}
142