You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a complex issue with multiple layers and no easy fix.
The ReflectionService currently has a special case in initialize for Production context specifically that will load a limited subset of cached reflection data compared to the full compiletime set. This distinction is generally very sensible as the amount of data is huge and shouldn't really be used during runtime anyways. BUT there is no limitation to calling the respective methods using this data, thus you unexpectedly get different results in Development and Production on the same codebase when asking the ReflectionService for example for getClassesContainingMethodsAnnotatedWith.
This is dangerous as it can lead to errors that appear only after a production deployment.
Expected Behavior
Loading all reflection data on production is prohibitive due to the RAM usage it would incur, so alternative solutions have to be found. A workaround exists in the form of CompileStatic annotation/attribute, which will execute the annotated static method at compiletime and store the results of that call as hardcoded return value in the generated proxy class. This works and is great for performance, yet has issues in itself. First of all CompileStatic is inert in Development again, so you get different proxy classes between Production and Development environments. While no known issues exist around this and the Flow core uses CompileStatic since years, it might lead to hard to track down effects as well.
As these two (CompileStatic and the different reflection data in Production) work hand in hand any steps changing this need to be taken carefully.
It could be benefial for example to change \Neos\Flow\Reflection\ReflectionService::initialize to not be special for Production but generally divide between compile time and runtime data for all appliction contexts. This however would immediately lead to compile static failing in Development and Testing as the necessary reflection data (as mentioned above CompileStatic is inert outside of Production) is not available anymore so the runtime call executing the static method will not receive the necessary data anymore.
The tandem step would be to enable CompileStatic for Development and Testing. This should generally be fairly safe, the biggest consideration is managing regeneration of the proxies (a quick and safe approach could be to just regenerate any proxy with compile static in it on any change to reflection data). To help debugging compile static behavior and what happens inside the static method we could provide a command that runs in compiletime and executes a given (compile) static method, so you can xdebug and observe it in isolation.
This combination of 3 measures together would be one route to take to clean this up a bit and prevent surprises in Production.
Next up to add additional safety would be a split between compiletime reflection and runtime reflection analog to the object manager, such that the runtime reflectionservice doesn't offer any methods using data not available at runtime.
This would be a breaking change however as even if we do not rename the ReflectionService and keep that as runtime ReflectionService, any CompileStatic method would have to use the (to be introduced CompiletimeReflectionService instead).
An easier but dirtier solution would be to throw in the respective methods when the data is not available (aka you try to access compiletime data at runtime).
Altogether different route of thinking (that I fear might be a waste of time) is trying to find a clever solution to load the minimum data necessary (and maybe lazy) to enable the functionality, but I am not sure a good tradeoff can be found here.
Steps To Reproduce
No response
Environment
- Flow: any
- PHP: any
Anything else?
No response
The text was updated successfully, but these errors were encountered:
Is there an existing issue for this?
Current Behavior
This is a complex issue with multiple layers and no easy fix.
The ReflectionService currently has a special case in initialize for Production context specifically that will load a limited subset of cached reflection data compared to the full compiletime set. This distinction is generally very sensible as the amount of data is huge and shouldn't really be used during runtime anyways. BUT there is no limitation to calling the respective methods using this data, thus you unexpectedly get different results in Development and Production on the same codebase when asking the ReflectionService for example for
getClassesContainingMethodsAnnotatedWith
.This is dangerous as it can lead to errors that appear only after a production deployment.
Expected Behavior
Loading all reflection data on production is prohibitive due to the RAM usage it would incur, so alternative solutions have to be found. A workaround exists in the form of CompileStatic annotation/attribute, which will execute the annotated static method at compiletime and store the results of that call as hardcoded return value in the generated proxy class. This works and is great for performance, yet has issues in itself. First of all CompileStatic is inert in Development again, so you get different proxy classes between Production and Development environments. While no known issues exist around this and the Flow core uses CompileStatic since years, it might lead to hard to track down effects as well.
As these two (CompileStatic and the different reflection data in Production) work hand in hand any steps changing this need to be taken carefully.
It could be benefial for example to change
\Neos\Flow\Reflection\ReflectionService::initialize
to not be special for Production but generally divide between compile time and runtime data for all appliction contexts. This however would immediately lead to compile static failing in Development and Testing as the necessary reflection data (as mentioned above CompileStatic is inert outside of Production) is not available anymore so the runtime call executing the static method will not receive the necessary data anymore.The tandem step would be to enable CompileStatic for Development and Testing. This should generally be fairly safe, the biggest consideration is managing regeneration of the proxies (a quick and safe approach could be to just regenerate any proxy with compile static in it on any change to reflection data). To help debugging compile static behavior and what happens inside the static method we could provide a command that runs in compiletime and executes a given (compile) static method, so you can xdebug and observe it in isolation.
This combination of 3 measures together would be one route to take to clean this up a bit and prevent surprises in Production.
Next up to add additional safety would be a split between compiletime reflection and runtime reflection analog to the object manager, such that the runtime reflectionservice doesn't offer any methods using data not available at runtime.
This would be a breaking change however as even if we do not rename the ReflectionService and keep that as runtime ReflectionService, any CompileStatic method would have to use the (to be introduced CompiletimeReflectionService instead).
An easier but dirtier solution would be to throw in the respective methods when the data is not available (aka you try to access compiletime data at runtime).
Altogether different route of thinking (that I fear might be a waste of time) is trying to find a clever solution to load the minimum data necessary (and maybe lazy) to enable the functionality, but I am not sure a good tradeoff can be found here.
Steps To Reproduce
No response
Environment
Anything else?
No response
The text was updated successfully, but these errors were encountered: