I have started to learn Symfony (4.1) and I have a question about annotations.
As far as I know, annotation are just comments in terms of php and they are not a part of the language itself. However they are rather powerful thing in Symfony.
I want to know, how it all works.
Is there a code preprocessor which parses the source files dynamically and creates new php entities?
But if it's so, how does it affect the performance of an application?
Why should I use special namespaces for certain annotations?
Put simply, I would like to know how do annotations in Symfony work, the mechanism of this feature.
Yes, indeed, annotations are not part of the language itself. But they're also not the part of Symfony framework.
Annotations are usually handled by doctrine/annotations package (most common). It utilizes reflection to read and parse these comments and transform them into annotation objects (every annotation has an annotation class which it represents).
Then, its up to the library to make use of generated objects representing these annotations.
So to answer first question - yes, there is a preprocessor. But it doesn't "create new php entities", because its the job for the library that uses those annotations (e.g. Symfony framework or Doctrine ORM).
How it affects the performance, depends on the library that uses them. If they would be parsed on every request, that would indeed affect performance. So e.g. Symfony and Doctrine ORM cache this data or create proxy classes etc.
So the answer to second question is - it might if used incorrectly, but it usually is not (in production environment) as they are simply not parsed every time.
The last question doesn't really relates to annotations. Since annotations are really classes, the reason for namespacing them is also the same. To avoid conflicts between libraries and for sake of readability.
Related
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.
Ok, so I am working on creating a custom standalone library that I intend to use in a Drupal 8 site. Drupal 8 runs on Symfony 2.8.x. I want this code to be usable outside Drupal. So I have focused on making it more Symfony oriented than Drupal oriented.
What I have found, thus far, with all my searching, is that Symfony requires you to write a bunch of config declarations in DependencyInjection/Configuration.php. As well as service declarations in a MyBundleExtension.php file.
What I have NOT found is a simple way to say "Hey, I want this config parameter in this standalone (not at all a controller) class". So I wrote the class you see below.
Is there a better way to handle this?
Code: http://pastebin.com/pdp53kxe
Also, will this create any problems with loading services?
At some point I have to deal with dependency injection and actually new up what we want to inject. Still not sure how I will work that into this standalone library while utilizing the Symfony framework. So suggestions as to how to have Symfony wire that up for me would be great.
My basic question here is about using Symfony in a library setting. Where you would not expect to just need the variables within a controller context.
Like you said if you want to import configuration you need to use your DependecyInjection/MyBundleExtension.php class to load the config (maybe even parse) yourself.
Another way is to use compiler passes to directly manipulate the container but this looks like it would be an overkill for your case.
The main reason is that the Dependency Injection Container (wich contains all your service definitions and config parameters) is compiled.
So you have to inject your extra config before the compilation.
Helpful links:
http://symfony.com/doc/current/service_container/import.html
http://symfony.com/doc/current/service_container/compiler_passes.html
Addendum
Doctrine 2 Annotations
Can you give me any reason one is better than the other ?
Here my list for now :
Addendum is a project dedicated for that
Addendum seems to have more functionnalities
Addendum API seems easier to use
Doctrine has more support and more people involved
Doctrine seems to be a project more alive
Doctrine is fully compatible PHP 5.3, whereas Addendum seems to be trying to become compatible (see home page)
Doctrine Annotations can be cached easily
The decision is not easy...
I suppose I'd rather use the Doctrine's component :
I've never heard of Addendum -- while I've heard a lot about Doctrine (and have used it several times)
Which means more community and support for Doctrine
Doctrine is used by some big Frameworks (symfony ; and can easily be integrated with Zend Framework)
Which means chances are higher that you'll already use Doctrine ; and find developers who are familiar with its syntax
Maybe less important for you, But some guy from Doctrine's team has done some work on getting Annotations integrated into PHP
There is a RFC : Request for Comments: Class Metadata
For now, it doesn't seem this is going to be integrated into PHP, but it means there is works done by the Doctrine's team, that shows their solution has some thinking
For what it's worth...
I've been using Addendum for a year now, and I've found it ridiculously easy to use. Its extension to the PHP Reflection API is seamless, and it supports far more use cases than Doctrine Annotations component.
It lacks namespaces support, but I could patch AnnotationMatcher class so it accepted namespaced classes (without getting false matches from docblock tags) and it has worked like a charm.
Doctrine's annotations takes into account PHP 5.3 use statements. That's the only thing that Addendum does not do and IMO it wouldn't be so trivial to implement.
Is there a way to use Doctrine using the model classes I've already setup for my Symfony applications without having to call Symfony with all that overhead?
This is more to satisfy a curiosity than anything else. For all the scripts I've used, I've just been able to instantiate Symfony (which typically turns out nice since I have all of the features that I'm used to working with on this particular project. But there has to be a way to load Doctrine and use the Symfony model classes without Symfony... Right?
Doctrine isn't dependet on symfony. Doctrine is a "framework" on its own. It has it's own autoloading and can therefore work with it's classes like a regular PHP app. You can integrate Doctrine with other frameworks if you want (like CodeIgniter or Zend). So you have every freedom you need without the need to do some tedious migration of your models/data/... from one system to another.
I've come to the conclusion there really isn't a way to use the model classes from Symfony elsewhere. With a little work, you can port over the classes to a new Doctrine model (even if you use the generator, since the main model class just extends the base which extends sfDoctrineRecord (from the API docs, you can see which functions will need to be removed).
Otherwise, there isn't a practical way of doing that.
Anytime I need to access the Symfony model, I'm making a task or plugin since I do typically need part of Symfony's functionality.
As far as Symfony2 goes, just looking at the documentation makes me want to run screaming. It's not mature in any form or fashion (but, then again, neither is Symfony "legacy"). So, I'm not sure if the process would be any easier there.
I've been looking for a good PHP ORM tool to use, and I recently found a good ORM class in Kohana. It has a fairly good and simple ORM implementation. The problem is, the code is unreusable outside of the Kohana framework without a rewrite/refactor. It relies on the Kohana class loader and various framework loading strategies to even work in the first place. Further, the required classes aren't packaged into a single dependency directory, or even multiple directories.
When I do this rewrite, I intend to republish the code via sourceforge or something, and those guys can of course reuse it if they want. So, should I just package the fileset needed into one directory, and make the appropriate classes do a require_once on any dependant classes, and 2 should I stick with the original class names that are project dependent (like Kohana_exception) even though it is pretty much unrelated to the Kohana project as a whole?
A second option would be to write another classloader that is a simplified version of the Kohana Framework classloader, and only cares about the ORM related stuff...
If you think what you are doing will be a marked improvement to the Kohana project you should make your changes and submit a patch to be considered by the project's maintainers. You probably aren't the first person to appreciate a part of their framework and component-izing their framework into smaller bits may be something you could help encourage by submitting a patch (though that will require much more time on your part to engineer).
It sounds like you are extracting a piece of their framework for independent use so it doesn't sound like you're forking at all, though I can imagine removing all of those dependencies may sure seem like a fork.