@@ -48,8 +48,23 @@ public static function parse(string $function): array
4848 try {
4949 if (str_contains ($ function , ':: ' )) {
5050 [$ className , $ methodName ] = explode (':: ' , $ function , 2 );
51- $ ref = new \ReflectionMethod ($ className , $ methodName );
52- $ contract = self ::parseMethod ($ ref );
51+
52+ /** @var class-string<object> $className */
53+ $ refClass = new \ReflectionClass ($ className );
54+ if ($ refClass ->hasMethod ($ methodName )) {
55+ $ ref = $ refClass ->getMethod ($ methodName );
56+ $ contract = self ::parseMethod ($ ref );
57+ } else {
58+ $ templates = [];
59+ $ aliases = [];
60+ self ::parseClassLevelDocs ($ refClass , $ templates , $ aliases );
61+ $ contract = [
62+ 'types ' => [],
63+ 'templates ' => $ templates ,
64+ 'return ' => null ,
65+ 'aliases ' => $ aliases ,
66+ ];
67+ }
5368 } else {
5469 $ ref = new \ReflectionFunction ($ function );
5570 $ contract = self ::parseFunction ($ ref );
@@ -81,7 +96,7 @@ public static function parseProperty(string $className, string $propertyName): ?
8196 $ doc = false ;
8297 $ declaringClass = null ;
8398
84- // 1. Search Class and Parent Class Hierarchy
99+ // Search Class and Parent Class Hierarchy
85100 $ current = $ refClass ;
86101 while ($ current !== false ) {
87102 if ($ current ->hasProperty ($ propertyName )) {
@@ -97,7 +112,7 @@ public static function parseProperty(string $className, string $propertyName): ?
97112 $ current = $ current ->getParentClass ();
98113 }
99114
100- // 2. Search Implemented Interfaces (PHP 8.4 Interface Properties)
115+ // Search Implemented Interfaces (PHP 8.4 Interface Properties)
101116 if ($ doc === false ) {
102117 foreach ($ refClass ->getInterfaces () as $ interface ) {
103118 if ($ interface ->hasProperty ($ propertyName )) {
@@ -143,6 +158,34 @@ public static function parseProperty(string $className, string $propertyName): ?
143158 }
144159 }
145160
161+ /**
162+ * Extracts and returns all class-level type aliases for a given class.
163+ *
164+ * @return array<string, TypeNode>
165+ */
166+ public static function parseClassAliases (string $ className ): array
167+ {
168+ if (! class_exists ($ className ) && ! interface_exists ($ className ) && ! trait_exists ($ className )) {
169+ return [];
170+ }
171+
172+ try {
173+ $ refClass = new \ReflectionClass ($ className );
174+ $ doc = $ refClass ->getDocComment ();
175+ if ($ doc === false ) {
176+ return [];
177+ }
178+
179+ $ phpDocNode = DocblockExtractor::parseDocString ($ doc );
180+ $ aliases = [];
181+ DocblockExtractor::extractAliases ($ phpDocNode , $ aliases , $ refClass );
182+
183+ return $ aliases ;
184+ } catch (\Throwable $ e ) {
185+ return [];
186+ }
187+ }
188+
146189 /**
147190 * Orchestrates parsing for class methods across the inheritance hierarchy.
148191 *
@@ -264,8 +307,10 @@ private static function parseClassLevelDocs(\ReflectionClass $declaringClass, ar
264307 /**
265308 * Resolves method-level docblocks (@param, @return, @template, aliases) up the method hierarchy.
266309 *
310+ * @param \ReflectionMethod $ref
267311 * @param array<string, TypeNode> $types
268312 * @param array<string, TemplateTagValueNode> $templates
313+ * @param TypeNode|null $returnType
269314 * @param array<string, TypeNode> $aliases
270315 */
271316 private static function parseMethodHierarchyDocs (
0 commit comments