Task #55957
RFC: Optimize AOP proxies
Status: | New | Start date: | 2014-02-13 | |
---|---|---|---|---|
Priority: | Should have | Due date: | ||
Assigned To: | - | % Done: | 0% |
|
Category: | AOP | |||
Target version: | - | |||
Sprint: | Has patch: | No | ||
PHP Version: | Complexity: |
Description
Our current approach of applying AOP in generated proxies has some downsides:
- It's hard to follow the dynamic calls during debugging (Flow_Aop_Proxy_invokeJoinPoint, call_user_func_array, $adviceObject->$methodName($joinPoint))
- Profiling information contains a lot of these dynamic calls where it's again hard to follow parent / child call relations
- The creation of all advices for all methods in the constructor has some overhead
- The *Advice objects that are used to evaluate the advices dynamically add an additional overhead and nesting
- The proxy code is hard to understand, it's not obvious what a proxy method will execute
Idea:
- Unroll the advices in the proxied method, this is simple for everything but
Around
- Use a direct call to the aspect method for easier to debug code
- Use a direct call to the original method by using a closure instead of the dynamic invocation with
Flow_Aop_Proxy_invokeJoinPoint
Sketch:
<?php
class TargetClass01 extends TargetClass01_Original implements \TYPO3\Flow\Object\Proxy\ProxyInterface {
/**
* Autogenerated Proxy Method
*/
public function __construct() {
if (isset($this->Flow_Aop_Proxy_methodIsInAdviceMode['__construct'])) {
parent::__construct();
} else {
$this->Flow_Aop_Proxy_methodIsInAdviceMode['__construct'] = TRUE;
try {
$methodArguments = array();
// The advice chain is only needed for an Around advice, before advices could be directly placed here
// The advice chain is composed of a list of closures that actually call the method / advices to have an explicit call instead of call_user_func_array
// (we could cache the advice chain instances per method if we can measure a performance improvement)
$adviceChain = new LightweightAdviceChain(function($joinPoint) {
// Needs PHP 5.4
return parent::__construct();
});
$joinPoint = new \TYPO3\Flow\Aop\JoinPoint($this, 'TYPO3\Flow\Tests\Unit\Aop\Fixtures\TargetClass01', '__construct', $methodArguments, $adviceChain);
$aspect = \TYPO3\Flow\Core\Bootstrap::$staticObjectManager->get('TYPO3\Flow\Tests\Functional\Aop\Fixtures\BaseFunctionalityTestingAspect');
// The advices are invoked explicitly for easier debugging and profiling
$result = $aspect->lousyConstructorAdvice($joinPoint);
} catch (\Exception $e) {
unset($this->Flow_Aop_Proxy_methodIsInAdviceMode['__construct']);
throw $e;
}
unset($this->Flow_Aop_Proxy_methodIsInAdviceMode['__construct']);
return;
}
if (get_class($this) === 'TYPO3\Flow\Tests\Unit\Aop\Fixtures\TargetClass01') {
$this->initializeObject(1);
}
}
}