Summary
Two pointcut components lag behind the modern PHP type/modifier system. Neither breaks weaving — matching is just silently impossible or wrong for these constructs. From the PHP 8.5 support audit (PR #597).
1. ReturnTypePointcut cannot match union / intersection / DNF types
src/Aop/Pointcut/ReturnTypePointcut.php:27-29 documents it:
This implementation currently doesn't support properly matching of complex types, thus union/intersection/DNF types are not supported yet here.
Matching is a string compare + wildcard on (string) $reflector->getReturnType() (line ~76), so execution(public **->*(*): Iterator) never matches Iterator|Generator, and member order (A&B vs B&A) defeats exact matches.
Proposed: normalize both sides into sorted member sets (split on | at depth 0, & inside parens), and let a single-type pattern match if any union member matches; document the semantics chosen.
2. ModifierPointcut has no predicates for modern modifiers
src/Aop/Pointcut/ModifierPointcut.php matches only the classic IS_PUBLIC/IS_PROTECTED/IS_PRIVATE/IS_STATIC/IS_FINAL/IS_ABSTRACT bitmask, and src/Aop/Pointcut/PointcutGrammar.php only accepts public|protected|private|final keywords. Not expressible today:
readonly properties/classes (8.1/8.2)
- asymmetric visibility
private(set) / protected(set) (8.4; static asymmetric visibility in 8.5)
- hooked vs plain properties (8.4)
final properties (8.4)
Proposed: extend the grammar with readonly, private(set), protected(set) modifier tokens mapped onto the corresponding ReflectionProperty predicates (isReadOnly(), isPrivateSet(), isProtectedSet(), isFinal()), with the existing matcher-gate caveat that readonly/hooked/static properties are excluded from access() interception anyway (useful mainly for negative filters and class filters).
Summary
Two pointcut components lag behind the modern PHP type/modifier system. Neither breaks weaving — matching is just silently impossible or wrong for these constructs. From the PHP 8.5 support audit (PR #597).
1.
ReturnTypePointcutcannot match union / intersection / DNF typessrc/Aop/Pointcut/ReturnTypePointcut.php:27-29documents it:Matching is a string compare + wildcard on
(string) $reflector->getReturnType()(line ~76), soexecution(public **->*(*): Iterator)never matchesIterator|Generator, and member order (A&BvsB&A) defeats exact matches.Proposed: normalize both sides into sorted member sets (split on
|at depth 0,&inside parens), and let a single-type pattern match if any union member matches; document the semantics chosen.2.
ModifierPointcuthas no predicates for modern modifierssrc/Aop/Pointcut/ModifierPointcut.phpmatches only the classicIS_PUBLIC/IS_PROTECTED/IS_PRIVATE/IS_STATIC/IS_FINAL/IS_ABSTRACTbitmask, andsrc/Aop/Pointcut/PointcutGrammar.phponly acceptspublic|protected|private|finalkeywords. Not expressible today:readonlyproperties/classes (8.1/8.2)private(set)/protected(set)(8.4; static asymmetric visibility in 8.5)finalproperties (8.4)Proposed: extend the grammar with
readonly,private(set),protected(set)modifier tokens mapped onto the correspondingReflectionPropertypredicates (isReadOnly(),isPrivateSet(),isProtectedSet(),isFinal()), with the existing matcher-gate caveat that readonly/hooked/static properties are excluded fromaccess()interception anyway (useful mainly for negative filters and class filters).