In AOP in Java (AspectJ) when we talk about method pointcuts, we can differentiate them into two different sets: method call pointcuts
and method execution pointcuts
.
Basing on these resources here on SO:
- execution Vs. call Join point
- Difference between call and execution in AOP
And some AspectJ background, we can tell that basically the differences between the two can be expressed as the following:
Given these classes:
class CallerObject {
//...
public void someMethod() {
CompiletimeTypeObject target = new RuntimeTypeObject();
target.someMethodOfTarget();
}
//...
}
class RuntimeTypeObject extends CompileTypeObject {
@Override
public void someMethodOfTarget() {
super.someMethodOfTarget();
//...some other stuff
}
}
class CompiletimeTypeObject {
public void someMethodOfTarget() {
//...some stuff
}
}
- A method call pointcut refers to the call of a method from a caller object which calls the method of a target object (the one which actually implements the method being called). In the example above, the caller is CallerObject, the target is RuntimeTypeObject. Also, a method call pointcut refers to the compile time type of the object, i.e. "CompiletimeTypeObject" in the example above;
So a method call pointcut
like this:
pointcut methodCallPointcut():
call(void com.example.CompiletimeTypeObject.someMethodOfTarget())
Will match the target.someMethodOfTarget();
join point inside the CallerObject.someMethod() method as the compile type
of the RuntimeTypeObject is CompiletimeTypeObject, but this method call pointcut:
pointcut methodCallPointcut():
call(void com.example.RuntimeTypeObject.someMethodOfTarget())
Will not match, as the compile time type of the object (CompiletimeTypeObject) is not a RuntimeTypeObject or a subtype of it (it is the opposite).
- A method execution pointcut refers to the execution of a method (i.e. after the method has been called or right before the method call returns). It doesn't give information about the caller and more important it refers to the runtime type of the object and not to the compile time type.
So, both these method execution pointcuts will match the target.someMethodOfTarget();
execution join point:
pointcut methodCallPointcut():
execution(void com.example.CompiletimeTypeObject.someMethodOfTarget())
pointcut methodCallPointcut():
execution(void com.example.RuntimeTypeObject.someMethodOfTarget())
As the matching is based on the runtime type of the object which is RuntimeTypeObject for both and RuntimeTypeObject is both CompiletimeTypeObject (first pointcut) and a RuntimeTypeObject (second pointcut).
Now, as PHP doesn't provide compile time types for objects (unless type-hinting is used to somehow emulate this behaviour), does it make sense to differentiate method call and method execution pointcuts in a PHP AOP implementation? How then will the pointcuts differ from each other?
Thanks for the attention!
EDIT: @kriegaex has pointed out another interesting aspect between call and method execution pointcuts in AspectJ.
Thank you for the great and concise example. I have tried to make an example myself too and here is what I understood:
In case A (I use a 3rd party library), I actually can't intercept the execution of a library method because the library itself was already compiled into bytecode and any aspect concerning that library was already woven into that bytecode too (I would need to weave the sources in order to do so).
So I can only intercept the method calls to the library methods, but again I can only intercept the calls to library methods in my code and not the calls to library methods from within the library itself because of the same principle (the calls to library methods from within the library itself are also already compiled).
The same applies for System classes (same principle) as is said here (even if the reference refers to JBoss):
https://docs.jboss.org/jbossaop/docs/2.0.0.GA/docs/aspect-framework/reference/en/html/pointcuts.html
System classes cannot be used within execution expressions because it is impossible to instrument them.
In case B (I provide a library for other users), if I actually need to intercept the usage of a method of my library either in the library itself or in the future user code which will use that method, then I need to use an execution pointcut as the aspect weaver will compile both the method execution and call pointcuts that concern my library and not the user code which will use my library methods (simply because the user code doesn't exist yet when I am writing the library), therefore using an execution pointcut will ensure that the weaving will occur inside the method execution (for a clear and intuitive example, look at the @kriegaex pseudo-code below) and not wherever the method is called within my library (i.e. at the caller side).
So I can intercept the usage (more precisely, execution) of my library method both when the method is used within my library and in the user's code. If I had used a method call pointcut in this case, I would have intercepted only the calls made from within my library, and not the calls made in the user's code.
Anyway, still think if these considerations make sense and can be applied in the PHP world, what do you think guys?