There is a framework called Go! Aspect-Oriented Framework for PHP
And it is made in plain PHP, doesn't require any PECL-extentions and DI-containers to work.
What's more can be integrated with any existing PHP frameworks and libraries (with or without additional configuration).
And there is no runtime checks of pointcuts, no runtime annotations parsing, no evals and __call methods, no slow proxies and call_user_func_array(). Fast bootstraping process (2-20ms) and advice invocation.
So I am very impressed, but what I want to know, is how does that actually work?
These points that I listed here...
I looked on github and official website, and some other articles but couldn't find any concrete information about how does this work (in general and in specific).
I'm so eager to know how does this work? How it was implemented?
This framework is using many hidden tricks to perform its job, but if we look from the bird's view, then process can be described as following:
- Current version of AOP engine is designed to work tightly with composer, so it wraps composer loader with own proxy. From that point of time, AOP knows about which class should be loaded and where to look for its source code.
- When some class
Foo
is loading from file Foo.php
, AOP wraps it into special filter stream like this: include 'php://filter/read=go.source.transforming.loader/resource=Foo.php';
. You can read more about this stream filter at 'php://stream' manual
- At that point of time, class is not loaded into PHP memory, but framework already knows about it's content and can perform analysis or even modification of source code.
- Source code then tokenized, parsed into AST via nikic/PHP-Parser library and then static reflection of this code is generated (still without loading this file into PHP's memory) via goaop/parser-reflection
- Engine checks all registered pointcuts from aspects and performs transformation of original class
Foo
: it's renamed to Foo__AopProxied
and new file with class Foo extends Foo__AopProxied
is generated in cache.
- Engine then direct autoloader to load this class from that new file instead of original one, so you have your original class name, but with additional logic from advices. It's look like automatic decorator generation in runtime.
Of course, it's only small amount of information, because implementing of AOP in pure PHP was very hard task and I tried many times before discovering of working solution, so it can be interesting to dig into source code to discover hidden gems :) Some information is also available in my PhpSerbia talk about cross-cutting concerns in PHP, you can watch it for better understanding (sorry for my English).
Also we are working on documentation for framework right now, so if you want to make it better, just send us a PR to the official documentation.
You should also use PhpStorm plugin, which provides many features for developers that use AOP in PHP projects.