FromReflectionMethod binds the class declaring the method but gives no information about the class on which the method was invoked on
rares-mollie opened this issue · 3 comments
When using ParseMethods
together with an attribute implementing FromReflectionMethod
the fromReflection
method is called with a \ReflectionMethod
parameter that contains information about the declaring class but no information about the "bound" or "analysed" class.
Detailed description
I think it would be an enhancement to pass also information about the analysed class to the method attributes, as it is the class in the context of which the method is callable. This is also the behaviour that FromReflectionClass
has.
Context
I am using attributes to mark methods to be traced by a tracing library, I need information about the object that is actually being instantiated as opposed to its class hierarchy.
Possible implementation
Add an interface that takes the analysed class as a parameter similar to FromReflectionClass
Your environment
not relevant
To replicate:
#[Attribute(Attribute::TARGET_CLASS)]
class classAttribute implements ParseMethods, Inheritable, FromReflectionClass
{
public function setMethods(array $methods): void
{
}
public function includeMethodsByDefault(): bool
{
return false;
}
public function methodAttribute(): string
{
return methodAttribute::class;
}
public function fromReflection(\ReflectionClass $subject): void
{
var_dump("REFLECTION CLASS");
var_dump($subject);
}
}
#[Attribute(Attribute::TARGET_METHOD)]
class methodAttribute implements FromReflectionMethod {
public function fromReflection(\ReflectionMethod $subject): void
{
var_dump("REFLECTION METHOD");
var_dump($subject);
}
}
#[classAttribute]
abstract class parentClass {
#[methodAttribute]
public function doSomething() {
return true;
}
}
class childClass extends parentClass {
}
$analyzer = new Analyzer();
$tracedClass = $analyzer->analyze(childClass::class, classAttribute::class);
// Outputs:
// string(16) "REFLECTION CLASS"
// object(ReflectionClass)#3671 (1) {
// ["name"]=>
// string(10) "childClass"
// }
// string(17) "REFLECTION METHOD"
// object(ReflectionMethod)#3711 (2) {
// ["name"]=>
// string(11) "doSomething"
// ["class"]=>
// string(11) "parentClass"
// }
Fascinating case. I'm not sure how to do that directly, but the just released 0.8.2 version includes a new ReadsClass
interface that the method attribute could use. It gets passed the class attribute, which could itself use FromReflectionClass
to know information about itself that can get passed on to the method attribute.
Can you give that a try and see if that works?
Actually this works, I did have to add a check because the interface doesn't allow me to be specific enough:
public function fromClassAttribute(object $class): void
{
if(!$class instanceof classAttribute) {
throw new Exception("Invalid usage of tracing attribute");
}
$this->className = $class->getName();
}
Ah, excellent. (Unfortunately we cannot make the type more specific until PHP lets us use never
as a parameter type.) Marking this done, then.