1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\PhpDocParser\Ast\PhpDoc;
4:
5: use PHPStan\PhpDocParser\Ast\Node;
6: use PHPStan\PhpDocParser\Ast\NodeAttributes;
7: use function array_column;
8: use function array_filter;
9: use function array_map;
10: use function implode;
11:
12: class PhpDocNode implements Node
13: {
14:
15: use NodeAttributes;
16:
17: /** @var PhpDocChildNode[] */
18: public array $children;
19:
20: /**
21: * @param PhpDocChildNode[] $children
22: */
23: public function __construct(array $children)
24: {
25: $this->children = $children;
26: }
27:
28:
29: /**
30: * @return PhpDocTagNode[]
31: */
32: public function getTags(): array
33: {
34: return array_filter($this->children, static fn (PhpDocChildNode $child): bool => $child instanceof PhpDocTagNode);
35: }
36:
37:
38: /**
39: * @return PhpDocTagNode[]
40: */
41: public function getTagsByName(string $tagName): array
42: {
43: return array_filter($this->getTags(), static fn (PhpDocTagNode $tag): bool => $tag->name === $tagName);
44: }
45:
46:
47: /**
48: * @return VarTagValueNode[]
49: */
50: public function getVarTagValues(string $tagName = '@var'): array
51: {
52: return array_filter(
53: array_column($this->getTagsByName($tagName), 'value'),
54: static fn (PhpDocTagValueNode $value): bool => $value instanceof VarTagValueNode,
55: );
56: }
57:
58:
59: /**
60: * @return ParamTagValueNode[]
61: */
62: public function getParamTagValues(string $tagName = '@param'): array
63: {
64: return array_filter(
65: array_column($this->getTagsByName($tagName), 'value'),
66: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamTagValueNode,
67: );
68: }
69:
70:
71: /**
72: * @return TypelessParamTagValueNode[]
73: */
74: public function getTypelessParamTagValues(string $tagName = '@param'): array
75: {
76: return array_filter(
77: array_column($this->getTagsByName($tagName), 'value'),
78: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypelessParamTagValueNode,
79: );
80: }
81:
82:
83: /**
84: * @return ParamImmediatelyInvokedCallableTagValueNode[]
85: */
86: public function getParamImmediatelyInvokedCallableTagValues(string $tagName = '@param-immediately-invoked-callable'): array
87: {
88: return array_filter(
89: array_column($this->getTagsByName($tagName), 'value'),
90: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamImmediatelyInvokedCallableTagValueNode,
91: );
92: }
93:
94:
95: /**
96: * @return ParamLaterInvokedCallableTagValueNode[]
97: */
98: public function getParamLaterInvokedCallableTagValues(string $tagName = '@param-later-invoked-callable'): array
99: {
100: return array_filter(
101: array_column($this->getTagsByName($tagName), 'value'),
102: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamLaterInvokedCallableTagValueNode,
103: );
104: }
105:
106:
107: /**
108: * @return ParamClosureThisTagValueNode[]
109: */
110: public function getParamClosureThisTagValues(string $tagName = '@param-closure-this'): array
111: {
112: return array_filter(
113: array_column($this->getTagsByName($tagName), 'value'),
114: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamClosureThisTagValueNode,
115: );
116: }
117:
118: /**
119: * @return PureUnlessCallableIsImpureTagValueNode[]
120: */
121: public function getPureUnlessCallableIsImpureTagValues(string $tagName = '@pure-unless-callable-is-impure'): array
122: {
123: return array_filter(
124: array_column($this->getTagsByName($tagName), 'value'),
125: static fn (PhpDocTagValueNode $value): bool => $value instanceof PureUnlessCallableIsImpureTagValueNode,
126: );
127: }
128:
129: /**
130: * @return TemplateTagValueNode[]
131: */
132: public function getTemplateTagValues(string $tagName = '@template'): array
133: {
134: return array_filter(
135: array_column($this->getTagsByName($tagName), 'value'),
136: static fn (PhpDocTagValueNode $value): bool => $value instanceof TemplateTagValueNode,
137: );
138: }
139:
140:
141: /**
142: * @return ExtendsTagValueNode[]
143: */
144: public function getExtendsTagValues(string $tagName = '@extends'): array
145: {
146: return array_filter(
147: array_column($this->getTagsByName($tagName), 'value'),
148: static fn (PhpDocTagValueNode $value): bool => $value instanceof ExtendsTagValueNode,
149: );
150: }
151:
152:
153: /**
154: * @return ImplementsTagValueNode[]
155: */
156: public function getImplementsTagValues(string $tagName = '@implements'): array
157: {
158: return array_filter(
159: array_column($this->getTagsByName($tagName), 'value'),
160: static fn (PhpDocTagValueNode $value): bool => $value instanceof ImplementsTagValueNode,
161: );
162: }
163:
164:
165: /**
166: * @return UsesTagValueNode[]
167: */
168: public function getUsesTagValues(string $tagName = '@use'): array
169: {
170: return array_filter(
171: array_column($this->getTagsByName($tagName), 'value'),
172: static fn (PhpDocTagValueNode $value): bool => $value instanceof UsesTagValueNode,
173: );
174: }
175:
176:
177: /**
178: * @return ReturnTagValueNode[]
179: */
180: public function getReturnTagValues(string $tagName = '@return'): array
181: {
182: return array_filter(
183: array_column($this->getTagsByName($tagName), 'value'),
184: static fn (PhpDocTagValueNode $value): bool => $value instanceof ReturnTagValueNode,
185: );
186: }
187:
188:
189: /**
190: * @return ThrowsTagValueNode[]
191: */
192: public function getThrowsTagValues(string $tagName = '@throws'): array
193: {
194: return array_filter(
195: array_column($this->getTagsByName($tagName), 'value'),
196: static fn (PhpDocTagValueNode $value): bool => $value instanceof ThrowsTagValueNode,
197: );
198: }
199:
200:
201: /**
202: * @return MixinTagValueNode[]
203: */
204: public function getMixinTagValues(string $tagName = '@mixin'): array
205: {
206: return array_filter(
207: array_column($this->getTagsByName($tagName), 'value'),
208: static fn (PhpDocTagValueNode $value): bool => $value instanceof MixinTagValueNode,
209: );
210: }
211:
212: /**
213: * @return RequireExtendsTagValueNode[]
214: */
215: public function getRequireExtendsTagValues(string $tagName = '@phpstan-require-extends'): array
216: {
217: return array_filter(
218: array_column($this->getTagsByName($tagName), 'value'),
219: static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireExtendsTagValueNode,
220: );
221: }
222:
223: /**
224: * @return RequireImplementsTagValueNode[]
225: */
226: public function getRequireImplementsTagValues(string $tagName = '@phpstan-require-implements'): array
227: {
228: return array_filter(
229: array_column($this->getTagsByName($tagName), 'value'),
230: static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireImplementsTagValueNode,
231: );
232: }
233:
234: /**
235: * @return DeprecatedTagValueNode[]
236: */
237: public function getDeprecatedTagValues(): array
238: {
239: return array_filter(
240: array_column($this->getTagsByName('@deprecated'), 'value'),
241: static fn (PhpDocTagValueNode $value): bool => $value instanceof DeprecatedTagValueNode,
242: );
243: }
244:
245:
246: /**
247: * @return PropertyTagValueNode[]
248: */
249: public function getPropertyTagValues(string $tagName = '@property'): array
250: {
251: return array_filter(
252: array_column($this->getTagsByName($tagName), 'value'),
253: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
254: );
255: }
256:
257:
258: /**
259: * @return PropertyTagValueNode[]
260: */
261: public function getPropertyReadTagValues(string $tagName = '@property-read'): array
262: {
263: return array_filter(
264: array_column($this->getTagsByName($tagName), 'value'),
265: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
266: );
267: }
268:
269:
270: /**
271: * @return PropertyTagValueNode[]
272: */
273: public function getPropertyWriteTagValues(string $tagName = '@property-write'): array
274: {
275: return array_filter(
276: array_column($this->getTagsByName($tagName), 'value'),
277: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
278: );
279: }
280:
281:
282: /**
283: * @return MethodTagValueNode[]
284: */
285: public function getMethodTagValues(string $tagName = '@method'): array
286: {
287: return array_filter(
288: array_column($this->getTagsByName($tagName), 'value'),
289: static fn (PhpDocTagValueNode $value): bool => $value instanceof MethodTagValueNode,
290: );
291: }
292:
293:
294: /**
295: * @return TypeAliasTagValueNode[]
296: */
297: public function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array
298: {
299: return array_filter(
300: array_column($this->getTagsByName($tagName), 'value'),
301: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasTagValueNode,
302: );
303: }
304:
305:
306: /**
307: * @return TypeAliasImportTagValueNode[]
308: */
309: public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array
310: {
311: return array_filter(
312: array_column($this->getTagsByName($tagName), 'value'),
313: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasImportTagValueNode,
314: );
315: }
316:
317:
318: /**
319: * @return AssertTagValueNode[]
320: */
321: public function getAssertTagValues(string $tagName = '@phpstan-assert'): array
322: {
323: return array_filter(
324: array_column($this->getTagsByName($tagName), 'value'),
325: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagValueNode,
326: );
327: }
328:
329:
330: /**
331: * @return AssertTagPropertyValueNode[]
332: */
333: public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'): array
334: {
335: return array_filter(
336: array_column($this->getTagsByName($tagName), 'value'),
337: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagPropertyValueNode,
338: );
339: }
340:
341:
342: /**
343: * @return AssertTagMethodValueNode[]
344: */
345: public function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): array
346: {
347: return array_filter(
348: array_column($this->getTagsByName($tagName), 'value'),
349: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagMethodValueNode,
350: );
351: }
352:
353:
354: /**
355: * @return SelfOutTagValueNode[]
356: */
357: public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'): array
358: {
359: return array_filter(
360: array_column($this->getTagsByName($tagName), 'value'),
361: static fn (PhpDocTagValueNode $value): bool => $value instanceof SelfOutTagValueNode,
362: );
363: }
364:
365:
366: /**
367: * @return ParamOutTagValueNode[]
368: */
369: public function getParamOutTypeTagValues(string $tagName = '@param-out'): array
370: {
371: return array_filter(
372: array_column($this->getTagsByName($tagName), 'value'),
373: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamOutTagValueNode,
374: );
375: }
376:
377:
378: public function __toString(): string
379: {
380: $children = array_map(
381: static function (PhpDocChildNode $child): string {
382: $s = (string) $child;
383: return $s === '' ? '' : ' ' . $s;
384: },
385: $this->children,
386: );
387: return "/**\n *" . implode("\n *", $children) . "\n */";
388: }
389:
390: }
391: