1<?php declare(strict_types=1);
2
3namespace PhpParser\Builder;
4
5use PhpParser;
6use PhpParser\BuilderHelpers;
7use PhpParser\Modifiers;
8use PhpParser\Node;
9use PhpParser\Node\Identifier;
10use PhpParser\Node\Name;
11use PhpParser\Node\Stmt;
12use PhpParser\Node\ComplexType;
13
14class Property implements PhpParser\Builder {
15    protected string $name;
16
17    protected int $flags = 0;
18
19    protected ?Node\Expr $default = null;
20    /** @var array<string, mixed> */
21    protected array $attributes = [];
22    /** @var null|Identifier|Name|ComplexType */
23    protected ?Node $type = null;
24    /** @var list<Node\AttributeGroup> */
25    protected array $attributeGroups = [];
26    /** @var list<Node\PropertyHook> */
27    protected array $hooks = [];
28
29    /**
30     * Creates a property builder.
31     *
32     * @param string $name Name of the property
33     */
34    public function __construct(string $name) {
35        $this->name = $name;
36    }
37
38    /**
39     * Makes the property public.
40     *
41     * @return $this The builder instance (for fluid interface)
42     */
43    public function makePublic() {
44        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
45
46        return $this;
47    }
48
49    /**
50     * Makes the property protected.
51     *
52     * @return $this The builder instance (for fluid interface)
53     */
54    public function makeProtected() {
55        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
56
57        return $this;
58    }
59
60    /**
61     * Makes the property private.
62     *
63     * @return $this The builder instance (for fluid interface)
64     */
65    public function makePrivate() {
66        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
67
68        return $this;
69    }
70
71    /**
72     * Makes the property static.
73     *
74     * @return $this The builder instance (for fluid interface)
75     */
76    public function makeStatic() {
77        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);
78
79        return $this;
80    }
81
82    /**
83     * Makes the property readonly.
84     *
85     * @return $this The builder instance (for fluid interface)
86     */
87    public function makeReadonly() {
88        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);
89
90        return $this;
91    }
92
93    /**
94     * Makes the property abstract. Requires at least one property hook to be specified as well.
95     *
96     * @return $this The builder instance (for fluid interface)
97     */
98    public function makeAbstract() {
99        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);
100
101        return $this;
102    }
103
104    /**
105     * Makes the property final.
106     *
107     * @return $this The builder instance (for fluid interface)
108     */
109    public function makeFinal() {
110        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);
111
112        return $this;
113    }
114
115    /**
116     * Gives the property private(set) visibility.
117     *
118     * @return $this The builder instance (for fluid interface)
119     */
120    public function makePrivateSet() {
121        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET);
122
123        return $this;
124    }
125
126    /**
127     * Gives the property protected(set) visibility.
128     *
129     * @return $this The builder instance (for fluid interface)
130     */
131    public function makeProtectedSet() {
132        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET);
133
134        return $this;
135    }
136
137    /**
138     * Sets default value for the property.
139     *
140     * @param mixed $value Default value to use
141     *
142     * @return $this The builder instance (for fluid interface)
143     */
144    public function setDefault($value) {
145        $this->default = BuilderHelpers::normalizeValue($value);
146
147        return $this;
148    }
149
150    /**
151     * Sets doc comment for the property.
152     *
153     * @param PhpParser\Comment\Doc|string $docComment Doc comment to set
154     *
155     * @return $this The builder instance (for fluid interface)
156     */
157    public function setDocComment($docComment) {
158        $this->attributes = [
159            'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
160        ];
161
162        return $this;
163    }
164
165    /**
166     * Sets the property type for PHP 7.4+.
167     *
168     * @param string|Name|Identifier|ComplexType $type
169     *
170     * @return $this
171     */
172    public function setType($type) {
173        $this->type = BuilderHelpers::normalizeType($type);
174
175        return $this;
176    }
177
178    /**
179     * Adds an attribute group.
180     *
181     * @param Node\Attribute|Node\AttributeGroup $attribute
182     *
183     * @return $this The builder instance (for fluid interface)
184     */
185    public function addAttribute($attribute) {
186        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
187
188        return $this;
189    }
190
191    /**
192     * Adds a property hook.
193     *
194     * @return $this The builder instance (for fluid interface)
195     */
196    public function addHook(Node\PropertyHook $hook) {
197        $this->hooks[] = $hook;
198
199        return $this;
200    }
201
202    /**
203     * Returns the built class node.
204     *
205     * @return Stmt\Property The built property node
206     */
207    public function getNode(): PhpParser\Node {
208        if ($this->flags & Modifiers::ABSTRACT && !$this->hooks) {
209            throw new PhpParser\Error('Only hooked properties may be declared abstract');
210        }
211
212        return new Stmt\Property(
213            $this->flags !== 0 ? $this->flags : Modifiers::PUBLIC,
214            [
215                new Node\PropertyItem($this->name, $this->default)
216            ],
217            $this->attributes,
218            $this->type,
219            $this->attributeGroups,
220            $this->hooks
221        );
222    }
223}
224