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 SealedTagValueNode[]
236: */
237: public function getSealedTagValues(string $tagName = '@phpstan-sealed'): array
238: {
239: return array_filter(
240: array_column($this->getTagsByName($tagName), 'value'),
241: static fn (PhpDocTagValueNode $value): bool => $value instanceof SealedTagValueNode,
242: );
243: }
244:
245: /**
246: * @return DeprecatedTagValueNode[]
247: */
248: public function getDeprecatedTagValues(): array
249: {
250: return array_filter(
251: array_column($this->getTagsByName('@deprecated'), 'value'),
252: static fn (PhpDocTagValueNode $value): bool => $value instanceof DeprecatedTagValueNode,
253: );
254: }
255:
256:
257: /**
258: * @return PropertyTagValueNode[]
259: */
260: public function getPropertyTagValues(string $tagName = '@property'): array
261: {
262: return array_filter(
263: array_column($this->getTagsByName($tagName), 'value'),
264: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
265: );
266: }
267:
268:
269: /**
270: * @return PropertyTagValueNode[]
271: */
272: public function getPropertyReadTagValues(string $tagName = '@property-read'): array
273: {
274: return array_filter(
275: array_column($this->getTagsByName($tagName), 'value'),
276: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
277: );
278: }
279:
280:
281: /**
282: * @return PropertyTagValueNode[]
283: */
284: public function getPropertyWriteTagValues(string $tagName = '@property-write'): array
285: {
286: return array_filter(
287: array_column($this->getTagsByName($tagName), 'value'),
288: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
289: );
290: }
291:
292:
293: /**
294: * @return MethodTagValueNode[]
295: */
296: public function getMethodTagValues(string $tagName = '@method'): array
297: {
298: return array_filter(
299: array_column($this->getTagsByName($tagName), 'value'),
300: static fn (PhpDocTagValueNode $value): bool => $value instanceof MethodTagValueNode,
301: );
302: }
303:
304:
305: /**
306: * @return TypeAliasTagValueNode[]
307: */
308: public function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array
309: {
310: return array_filter(
311: array_column($this->getTagsByName($tagName), 'value'),
312: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasTagValueNode,
313: );
314: }
315:
316:
317: /**
318: * @return TypeAliasImportTagValueNode[]
319: */
320: public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array
321: {
322: return array_filter(
323: array_column($this->getTagsByName($tagName), 'value'),
324: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasImportTagValueNode,
325: );
326: }
327:
328:
329: /**
330: * @return AssertTagValueNode[]
331: */
332: public function getAssertTagValues(string $tagName = '@phpstan-assert'): array
333: {
334: return array_filter(
335: array_column($this->getTagsByName($tagName), 'value'),
336: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagValueNode,
337: );
338: }
339:
340:
341: /**
342: * @return AssertTagPropertyValueNode[]
343: */
344: public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'): array
345: {
346: return array_filter(
347: array_column($this->getTagsByName($tagName), 'value'),
348: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagPropertyValueNode,
349: );
350: }
351:
352:
353: /**
354: * @return AssertTagMethodValueNode[]
355: */
356: public function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): array
357: {
358: return array_filter(
359: array_column($this->getTagsByName($tagName), 'value'),
360: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagMethodValueNode,
361: );
362: }
363:
364:
365: /**
366: * @return SelfOutTagValueNode[]
367: */
368: public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'): array
369: {
370: return array_filter(
371: array_column($this->getTagsByName($tagName), 'value'),
372: static fn (PhpDocTagValueNode $value): bool => $value instanceof SelfOutTagValueNode,
373: );
374: }
375:
376:
377: /**
378: * @return ParamOutTagValueNode[]
379: */
380: public function getParamOutTypeTagValues(string $tagName = '@param-out'): array
381: {
382: return array_filter(
383: array_column($this->getTagsByName($tagName), 'value'),
384: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamOutTagValueNode,
385: );
386: }
387:
388:
389: public function __toString(): string
390: {
391: $children = array_map(
392: static function (PhpDocChildNode $child): string {
393: $s = (string) $child;
394: return $s === '' ? '' : ' ' . $s;
395: },
396: $this->children,
397: );
398: return "/**\n *" . implode("\n *", $children) . "\n */";
399: }
400:
401: }
402: