5353use function array_slice ;
5454use function array_values ;
5555use function assert ;
56- use function end ;
5756use function in_array ;
5857use function is_int ;
5958use function is_string ;
@@ -120,7 +119,7 @@ class ReflectionClass implements Reflection
120119 private array $ immediateMethods ;
121120
122121 /** @var array{
123- * aliases: array<non-empty-string, non-empty-string>,
122+ * aliases: array<trait-string, list<array{alias: non-empty-string, method: non-empty-string, hash: non-empty-string}> >,
124123 * modifiers: array<non-empty-string, int-mask-of<ReflectionMethodAdapter::IS_*>>,
125124 * precedences: array<non-empty-string, non-empty-string>,
126125 * hashes: array<non-empty-string, non-empty-string>,
@@ -391,12 +390,22 @@ private function createMethodsFromTrait(ReflectionMethod $method): array
391390 $ methods [] = $ createMethod ($ method ->getAliasName ());
392391 }
393392
394- foreach ($ this ->traitsData ['aliases ' ] as $ aliasMethodName => $ traitAliasDefinition ) {
395- if ($ lowerCasedMethodHash !== $ traitAliasDefinition ) {
396- continue ;
397- }
393+ if ($ this ->traitsData ['aliases ' ] !== []) {
394+ $ traits = array_combine ($ this ->traitClassNames , $ this ->getTraits ());
395+
396+ foreach ($ this ->traitsData ['aliases ' ] as $ traitClassName => $ traitAliasDefinitions ) {
397+ foreach ($ traitAliasDefinitions as $ traitAliasDefinition ) {
398+ if ($ lowerCasedMethodHash !== $ traitAliasDefinition ['hash ' ]) {
399+ continue ;
400+ }
401+
402+ if (! $ traits [$ traitClassName ]->hasMethod ($ traitAliasDefinition ['method ' ])) {
403+ continue ;
404+ }
398405
399- $ methods [] = $ createMethod ($ aliasMethodName );
406+ $ methods [] = $ createMethod ($ traitAliasDefinition ['alias ' ]);
407+ }
408+ }
400409 }
401410
402411 return $ methods ;
@@ -1366,18 +1375,32 @@ static function (ReflectionClass $trait): string {
13661375 */
13671376 public function getTraitAliases (): array
13681377 {
1369- return array_map (
1370- fn (string $ lowerCasedMethodHash ): string => $ this ->traitsData ['hashes ' ][$ lowerCasedMethodHash ],
1371- $ this ->traitsData ['aliases ' ],
1372- );
1378+ if ($ this ->traitsData ['aliases ' ] === []) {
1379+ return [];
1380+ }
1381+
1382+ $ traits = array_combine ($ this ->traitClassNames , $ this ->getTraits ());
1383+ $ traitAliases = [];
1384+
1385+ foreach ($ this ->traitsData ['aliases ' ] as $ traitClassName => $ traitAliasDefinitions ) {
1386+ foreach ($ traitAliasDefinitions as $ traitAliasDefinition ) {
1387+ if (! $ traits [$ traitClassName ]->hasMethod ($ traitAliasDefinition ['method ' ])) {
1388+ continue ;
1389+ }
1390+
1391+ $ traitAliases [$ traitAliasDefinition ['alias ' ]] = $ this ->traitsData ['hashes ' ][$ traitAliasDefinition ['hash ' ]];
1392+ }
1393+ }
1394+
1395+ return $ traitAliases ;
13731396 }
13741397
13751398 /**
13761399 * Returns data when importing traits for this class:
13771400 *
13781401 * 'aliases': List of the aliases used when importing traits. In format:
13791402 *
1380- * 'aliasedMethodName' => 'ActualClass::actualMethod'
1403+ * 'traitClassName' => ['alias' => ' aliasedMethodName', 'method' => 'actualMethodName', 'hash' => 'traitClassName::actualMethodName'],
13811404 *
13821405 * Example:
13831406 * // When reflecting a code such as:
@@ -1387,7 +1410,7 @@ public function getTraitAliases(): array
13871410 * }
13881411 *
13891412 * // This method would return
1390- * // ['myAliasedMethod' => 'MyTrait::myTraitMethod' ]
1413+ * // ['MyTrait' => ['alias' => ' myAliasedMethod', 'method' => 'myTraitMethod', 'hash' => 'mytrait::mytraitmethod'] ]
13911414 *
13921415 * 'modifiers': Used modifiers when importing traits. In format:
13931416 *
@@ -1418,7 +1441,7 @@ public function getTraitAliases(): array
14181441 * // ['MyTrait1::foo' => 'MyTrait2::foo']
14191442 *
14201443 * @return array{
1421- * aliases: array<non-empty-string, non-empty-string>,
1444+ * aliases: array<trait-string, list<array{alias: non-empty-string, method: non-empty-string, hash: non-empty-string}> >,
14221445 * modifiers: array<non-empty-string, int-mask-of<ReflectionMethodAdapter::IS_*>>,
14231446 * precedences: array<non-empty-string, non-empty-string>,
14241447 * hashes: array<non-empty-string, non-empty-string>,
@@ -1434,37 +1457,60 @@ private function computeTraitsData(ClassNode|InterfaceNode|TraitNode|EnumNode $n
14341457 ];
14351458
14361459 foreach ($ node ->getTraitUses () as $ traitUsage ) {
1437- $ traitNames = $ traitUsage ->traits ;
1438- $ adaptations = $ traitUsage ->adaptations ;
1439-
1440- foreach ($ adaptations as $ adaptation ) {
1441- $ usedTrait = $ adaptation ->trait ;
1442- if ($ usedTrait === null ) {
1443- $ usedTrait = end ($ traitNames );
1444- }
1460+ foreach ($ traitUsage ->adaptations as $ adaptation ) {
1461+ $ usedTraits = $ adaptation ->trait !== null ? [$ adaptation ->trait ] : $ traitUsage ->traits ;
1462+ $ traitsData = $ this ->processTraitAdaptation ($ adaptation , $ usedTraits , $ traitsData );
1463+ }
1464+ }
14451465
1446- $ methodHash = $ this -> methodHash ( $ usedTrait -> toString (), $ adaptation -> method -> toString ()) ;
1447- $ lowerCasedMethodHash = $ this -> lowerCasedMethodHash ( $ usedTrait -> toString (), $ adaptation -> method -> toString ());
1466+ return $ traitsData ;
1467+ }
14481468
1449- $ traitsData ['hashes ' ][$ lowerCasedMethodHash ] = $ methodHash ;
1469+ /**
1470+ * @phpcs:disable Squiz.Commenting.FunctionComment.MissingParamName
1471+ *
1472+ * @param array<array-key, Node\Name> $usedTraits
1473+ * @param array{
1474+ * aliases: array<trait-string, list<array{alias: non-empty-string, method: non-empty-string, hash: non-empty-string}>>,
1475+ * modifiers: array<non-empty-string, int-mask-of<ReflectionMethodAdapter::IS_*>>,
1476+ * precedences: array<non-empty-string, non-empty-string>,
1477+ * hashes: array<non-empty-string, non-empty-string>,
1478+ * } $traitsData
1479+ *
1480+ * @return array{
1481+ * aliases: array<trait-string, list<array{alias: non-empty-string, method: non-empty-string, hash: non-empty-string}>>,
1482+ * modifiers: array<non-empty-string, int-mask-of<ReflectionMethodAdapter::IS_*>>,
1483+ * precedences: array<non-empty-string, non-empty-string>,
1484+ * hashes: array<non-empty-string, non-empty-string>,
1485+ * }
1486+ */
1487+ private function processTraitAdaptation (Node \Stmt \TraitUseAdaptation $ adaptation , array $ usedTraits , array $ traitsData ): array
1488+ {
1489+ foreach ($ usedTraits as $ usedTrait ) {
1490+ $ methodHash = $ this ->methodHash ($ usedTrait ->toString (), $ adaptation ->method ->toString ());
1491+ $ lowerCasedMethodHash = $ this ->lowerCasedMethodHash ($ usedTrait ->toString (), $ adaptation ->method ->toString ());
14501492
1451- if ($ adaptation instanceof Node \Stmt \TraitUseAdaptation \Alias) {
1452- if ($ adaptation ->newModifier !== null ) {
1453- /** @var int-mask-of<ReflectionMethodAdapter::IS_*> $modifier */
1454- $ modifier = $ adaptation ->newModifier ;
1455- $ traitsData ['modifiers ' ][$ lowerCasedMethodHash ] = $ modifier ;
1456- }
1493+ $ traitsData ['hashes ' ][$ lowerCasedMethodHash ] = $ methodHash ;
14571494
1458- if ($ adaptation ->newName ) {
1459- $ traitsData ['aliases ' ][$ adaptation ->newName ->name ] = $ lowerCasedMethodHash ;
1460- continue ;
1461- }
1495+ if ($ adaptation instanceof Node \Stmt \TraitUseAdaptation \Alias) {
1496+ if ($ adaptation ->newModifier !== null ) {
1497+ /** @var int-mask-of<ReflectionMethodAdapter::IS_*> $modifier */
1498+ $ modifier = $ adaptation ->newModifier ;
1499+ $ traitsData ['modifiers ' ][$ lowerCasedMethodHash ] = $ modifier ;
14621500 }
14631501
1464- if (! $ adaptation instanceof Node \Stmt \TraitUseAdaptation \Precedence || ! $ adaptation ->insteadof ) {
1465- continue ;
1502+ if ($ adaptation ->newName !== null ) {
1503+ // We need to save all possible combinations of trait and method names
1504+ // The real aliases will be filtered in getters
1505+ /** @var trait-string $usedTraitClassName */
1506+ $ usedTraitClassName = $ usedTrait ->toString ();
1507+ $ traitsData ['aliases ' ][$ usedTraitClassName ][] = [
1508+ 'alias ' => $ adaptation ->newName ->name ,
1509+ 'method ' => $ adaptation ->method ->toString (),
1510+ 'hash ' => $ lowerCasedMethodHash ,
1511+ ];
14661512 }
1467-
1513+ } elseif ( $ adaptation instanceof Node \ Stmt \ TraitUseAdaptation \Precedence) {
14681514 foreach ($ adaptation ->insteadof as $ insteadof ) {
14691515 $ adaptationNameHash = $ this ->lowerCasedMethodHash ($ insteadof ->toString (), $ adaptation ->method ->toString ());
14701516
0 commit comments