-
-
Notifications
You must be signed in to change notification settings - Fork 163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature][Long-Term] Interception of methods in the internal PHP classes #188
Comments
On a related issue - I have read the Intercepting Execution of System Functions in PHP article and was wondering if the above limitation also applies to core functions (e.g., mysql_query(...)). In other words, can I use Go! to intercept this kind of functions ? If not, then while you are considering the core classes issue, can you also consider the core functions one as well ? |
@lgoldstein you can intercept core functions with Go! AOP, but cache warming will be slower. Check the demo: http://demo.aopphp.com/?showcase=function-interceptor UPD1: To enable a function interception, you should explicitly enable this functionality via Features::INTERCEPT_FUNCTIONS, see https://github.com/lisachenko/go-aop-php/blob/master/demos/autoload_aspect.php#L24 and then just define an advice with |
@lisachenko Great - I will give it a go with mysql functions... |
Updated my previous answer to include some useful links for you, should be helpful. |
Please note that I am talking about core functions (like mysql_query()) - all your examples refer to user functions in some application namespace - this is not the case for core functions... |
My example is for core functions :) so, if you have a call to the Typical modern code is satisfies these requirements. |
@lisachenko Great - just wanted to make sure that you understood my meaning. I haven't tried it yet (turns out the application I was trying to instrument uses either mysqli or PDO). I will try to locate an application that uses mysql funtioncs and see if I can instrument it. BTW, I assume that PDO is also non-instrumentable (being a core class...)... |
Yes, PDO are core classes, so without this feature, framework can't handle them. |
@lisachenko Understood - I will follow this issue hoping that a solution can be found... |
@lisachenko Does not seem to work for mysql_query functions - the code is issuing queries but the aspect isn't being invoked. I have used this sample application with the following initializations and code: $aspectKernel = VMerlinAspectKernel::getInstance();
// see AspectKernel::getDefaultOptions
$aspectKernel->init(array(
'debug' => false,
// Cache directory
'cacheDir' => $cacheDir,
'appDir' => join(DIRECTORY_SEPARATOR, array('C:', 'Projects', 'appwatch', 'xampp', 'htdocs', 'phpcrud')),
'interceptFunctions' => true
)); Followed by this aspect definition (the aspect is registered at the container in the VMerlinAspectKernel::configureAop function): /**
* Intercepts <U>functional</U> calls to <code>mysql_*query*</code>
* @author Lyor Goldstein <[email protected]>
* @since Dec 3, 2014 2:57:43 PM
*/
class MysqlFunctionsOperationCollectionAspect extends VMerlinOperationCollectionAspectSupport implements Aspect {
function __construct(array $config) {
parent::__construct($config);
}
/**
* @param FunctionInvocation $invocation Invocation
* @Around(execution(mysql_query(*))
* @return mixed
*/
public function aroundQueryFunctions(FunctionInvocation $invocation) {
$method = $invocation->getFunction();
$args = $invocation->getArguments();
$query = $args[0];
if ($this->logger->isTraceEnabled()) {
$this->logger->trace($method->getName().'('.$query.')');
}
$startTime = VMerlinHelper::timestampValue();
try {
$result = $invocation->proceed();
return $result;
} catch(Exception $e) {
if ($this->logger->isTraceEnabled()) {
$this->logger->trace($method->getName().'('.$query.') '.get_class($e).': '.$e->getMessage());
}
throw $e;
}
}
} |
@lgoldstein your pointcut will never match anything, correct form is But it's only a minor fix. Framework is not suited for spaghetti code like in your example. http://zaldivar.orgfree.com/php/crud-example-for-php-beginner/ This will result in errors during static parsing and analysing of source code. Moreover, auto_prepending AOP initalization for such spaghetti code won't do anything. So, is your real source code looks like that? Or there are normal classes with methods? For auto_prepended file there is only one ugly way to enable AOP, something like this: |
@lisachenko My purpose is to use Go! in order to instrument any application - in other words, I want to place some code in the auto_prepend PHP script that will intercept API(s) of interest (e.g., mysql). Therefore, I have no control over the "spaghetti code" that you mention - i.e., I am not instrumenting my application but rather any application - one that is written by anyone (so I don't know if they are using "nice" or "spaghetti" code). Furthermore, I don't want to ask the user to change his/her application scripts with ugly code such as the eval statement you mentioned. In this context, if the application I am trying to instrument contains only pure PHP instead of mixed HTML and PHP would the auto_prepend approach work ? Is there some way to have Go! support mixed HTML + PHP scripts (such as the example) ? |
@lgoldstein nice questions, you are right that tool should work for any application. Unfortunately, PHP-Token-Reflection library (which is used internally by framework) may not be able to parse any code, because it's assume that code is valid OOP, eg. classes, functions, interfaces, etc. I think, that userland implementation of AOP is not suitable for your requirements. Have you tried AOP-PHP extension? This tool is working on engine level and you can use it with auto_prepend as well, also it capable to intercept execution of system functions and execution of methods for internal classes. But be aware, that this project is not maintained for 6 monthes and doesn't working for PHP>=5.5 |
@lisachenko I will look into the AOP-PHP extension - I was aware of it, but I prefer a pure PHP approach (also like you said "project is not maintained for 6 monthes and doesn't working for PHP>=5.5"). In the meanwhile, it would be nice if some solution could be found for Go! to support this kind of applications. I will continue to follow your project - at least for supporting core classes and/or functions - even if mixed HTML / PHP code is (for now) not supported. Thanks. |
One more possible way to handle your cases is to utilize |
Thanks :) 👍 |
I don't believe that for now it is going to be possible to utilize those extension. |
@TheCelavi It is still possible ) But requires AST transformation support from PHP-Parser with preseration of white nodes. Idea is following: we define a pointcut for system namespace like this:
It's complex, but doable. |
Great minds think alike :D I was thinking similar idea:
so, Concept is based on: "If I can not hook into PHP system classes and do the monkey patching, I can wrap it with something on which I can do monkey patching" - right? |
Yeah - because problem are |
Yes, but there are so many limitations in this solution. So it can quickly become unreliable. I even had a thought about dropping support of interception for object initialization and function execution. They are very fragile. |
For now - I think that we should focus on current issues, documentation, stabilizing library, tune it up, polishing, optimizing and so on... Hopefully that will attract more users & contributors which would bring more resources and clever ideas and approaches... I dont think that currently only two of us could deal with that at the moment. |
Hi Dear, use Go\Aop\Aspect; class Mysql implements Aspect { /**
public function beforeQueryFunctions(FunctionInvocation $invocation) {
} And i am getting this error [Mon Feb 03 16:00:09.451595 2020] [php7:error] [pid 12915] [client ::1:30563] PHP Fatal error: Uncaught Dissect\Parser\Exception\UnexpectedTokenException: Unexpected public at line 1.\n\nExpected one of namePart. in /var/www/html/Agent/framework/vendor/jakubledl/dissect/src/Dissect/Parser/LALR1/Parser.php:60\nStack trace:\n#0 /var/www/html/Agent/framework/src/Core/AbstractAspectLoaderExtension.php(121): Dissect\Parser\LALR1\Parser->parse()\n#1 /var/www/html/Agent/framework/src/Core/AbstractAspectLoaderExtension.php(71): Go\Core\AbstractAspectLoaderExtension->parseTokenStream()\n#2 /var/www/html/Agent/framework/src/Core/GeneralAspectLoaderExtension.php(77): Go\Core\AbstractAspectLoaderExtension->parsePointcut()\n#3 /var/www/html/Agent/framework/src/Core/AspectLoader.php(181): Go\Core\GeneralAspectLoaderExtension->load()\n#4 /var/www/html/Agent/framework/src/Core/AspectLoader.php(100): Go\Core\AspectLoader->loadFrom()\n#5 /var/www/html/Agent/framework/src/Core/CachedAspectLoader.php(74): Go\Core\AspectLoader->load()\n#6 /var/www/html/Agent/framework/src/Core/AspectLoader.php(121): Go\Core\CachedAspectLoader->load( in /var/www/html/Agent/framework/src/Core/AbstractAspectLoaderExtension.php on line 139, referer: http://localhost/Agent/framework/demos/?showcase=MysqlTest Tell me Where is the isssue in code |
Tell me that ,Is this Aop framework will work for predefine classes , |
@rahmatrh199 This feature is not supported, all internal (pre-defined) classes could not be processed by framework as there is no source code to transform. You could use a wrapper (eg. define a class that extends original) and then it will be possible to intercept methods. Support for internal classes could be implemented in version 4 of framework via lisachenko/z-engine. But I couldn't promise that version will be available soon. |
@lisachenko Thank you so much for the quick response. I hope version 4 will be available soon |
Interception of methods in the internal PHP classes is the most complex one, however, it is required for special cases, for example, to intercept
mysql->query()
invocation:The text was updated successfully, but these errors were encountered: