Skip to content
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

Seeking more flexibility is ways I can dynamically transform PHP code #317

Closed
loren-osborn opened this issue Mar 13, 2017 · 5 comments
Closed

Comments

@loren-osborn
Copy link

I'm using https://github.com/Codeception/AspectMock for testing, and have been frustrated that it doesn't support creating mocks to be used by functions in the global namespace. I'm looking into a few strategies to work around this, mostly involving more extensive code transformation in GoAOP!

the translators in GoAOP! currently seem to be doing ad hoc parsing with the built in PHP tokenizer. I have used https://github.com/nikic/PHP-Parser before, and it seems well suited for such syntactical surgery, and even notice this old issue: #16 highlighting a dashed hope to use PHP-Parser within GoAOP! when the parser didn't seem performant enough. The extra richness the PHP-Parser's parse tree includes should make several things I wish to add much easier.

The additional features I'd like to add to GoAOP! to facilitate this additional functionality in AspectMock include:

  • The ability to nest "Advised code" (the output of the aspect weaver) inside a user-specified namespace, such that all these classes reference the versions of their dependencies within this nested namespace, so that advised and "stock" code can coexist in memory simultaneously.
  • When necessary, the ability to redirect calls at the point they are initiated, probably with something like ) { /* Top of function */ \Codeeption\AspectMock\RunTimeResolver::lookup(['file_get_contents', 'system', 'is_dir'], [&$file_get_contents, &$system, &$is_dir], __FILE__, __NAMESPACE__, __FUNCTION__, __CLASS__); /* below: in function body */ $file_get_contents($fileName); I realize this can be very inefficient, but when necessary (and used sparingly) can give a great deal of flexibility. (This would require tracking all local variables declared in the function scope, and actively preventing variable collisions.) if used with function wrappers, this could even allow you to intercept statements like echo, require, unset, etc. Special handling could also be given for functions/Classes with absolute namespaces.
  • I'd also like to add optional tracking to model the load order of function definitions to detect possible calls to not-yet-defined functions. The function, class and constant definition order can be captured in a function, modeling nested include/require statements by calling each file's load_order function. After marking all functions as undefined, load order could be simulated such that calls to any function not marked as defined causes an exception to be thrown.

I know these are a very tall order, and I'm expecting to do most of the work, but I would appreciate any advice on things that work, and things to avoid.

Even though this is in a separate repo, I'm marking this as related to: Codeception/AspectMock#94

@loren-osborn
Copy link
Author

loren-osborn commented Mar 16, 2017

Just a followup to my previous comment:

While I would still like to see these features in GoAOP!, I've been surprised how much of this I can do directly inside AspectMock\Intercept\BeforeMockTransformer::transform().

Kudos on such a flexible design!

@lisachenko
Copy link
Member

Hi, @loren-osborn!

Sorry for the late response, so busy at my work that haven't any free time for my projects.
First of all, I want to thank you for reporting this issue, it makes me happy ) Looks like you dive deeper into the goaop's engine and already have a little knowledge about components.

There was an issue earlier with PHP-Parser that prevented me from using PHP-Parser for source transformation and it was inability to preserve original formatting and whitespaces. And it was no go, because changed files didn't match original ones and XDebug breakpoints were not working at all. This why goaop uses plain old string manipulation instead of more powerful AST-transformation.

I had a library, called goaop/ast-manipulator that was my attempt to make goaop transformers on top of PHP-Parser and with latest version this should finally work, because latest PHP-Parser preserves formatting. You can try to use it as a base step to create a fundament for future version of framework 😃

I can't guarantee that I will be able to respond to each comment very quickly, but I'll try to answer each question.

So, keep going! 👍

@loren-osborn
Copy link
Author

@lisachenko,

I did peek my head in at https://github.com/nikic/PHP-Parser, and it appears ( nikic/PHP-Parser#344 ) they are working on exactly that (modifying the AST while preserving the formatting) but not yet ready for prime time. I did notice they have the (undocumented) attributes startFilePos and endFilePos that I believe can use to modify the code while retaining line numbers. (I'm still experimenting)

I am not working on this on my own time, so am not yet able to offer patches back, but I anticipate this will likely change soon. I will keep you informed of my progress.

Thank you for your suggestions, and for all the work you've done on this very useful tool.

@lisachenko
Copy link
Member

@loren-osborn should we keep this issue? Do you have a plans to work on it? I want to clean as much issues as possible to start new year with clean issues :)

@lisachenko
Copy link
Member

Closed by inactivity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants