Disclaimer: These are some practical notes about the code generation in Magento 2 so there are edge cases and details that I will gloss over. Note that I did not architect, design, or write any of the relevant code but I do work on the Magento 2 codebase. This is not an official Magento 2 doc. You should find more detailed information at the official Developer Docs.
Several referenced classes in the Magento 2 codebase do not exist in the GitHub repository. For instance, look at the
<?php ... public function __construct( \Magento\Customer\Model\AddressFactory $addressFactory, ...
The first constructor parameter has a type of
\Magento\Customer\Model\AddressFactory. However, this class does not exist in the
\Magento\Customer\Model directory. You cannot find the class in the git repository.
How does Magento 2 work with these missing classes?
Code is generated when the application is run. Simply, if Magento 2 cannot find a class and the name of the class falls within a recognized convention (e.g. it ends with Factory), Magento 2 will generate the class.
Where is the generated code?
The generated code will be put in your
MAGENTO_2_HOME/var/generation directory. Issue a web request to an installed Magento 2 instance, and you will see new files in that directory.
Unlike some other languages/libraries, you can look at the generated code on disk to see what really happens and still debug through the code.
When is code automatically generated?
For most people in a non-production mode (e.g. by default after a git clone), code is generated when Magento 2 cannot find the class during code execution.
However, you can generate all of the code as well (instead of on demand) which would be useful for production by using the
Why generate code?
There’s boring code, and then there’s interesting code. Code generation writes the boilerplate code to allow developers to write the more exciting code.
Code generation is useful when the logic follows a pattern but you need to have specific logic for a particular class.
For instance, a Factory class creates instances of a type. So a generated
\Magento\Customer\Model\AddressFactory creates new instances of
\Magento\Customer\Model\Address. The actual code in
AddressFactory has some specific code for the
In more complex code generation, a Proxy can be generated for a type. Generally, a proxy must have an implementation of all the declared public methods of the original class.
The method implementation could be delegating to another object in memory. Or the method could make a network call to another object on a different machine. All the Proxy methods in a class usually do the same thing (e.g. they all delegate to another object or they all make a network call) except they need a slight difference to call a specific method.
Advantages of Generating Code
In both Factories and Proxies, the code can be simple to write. But do you really want a developer to spend time writing tedious code?
By generating the code, you can be assured:
- The code is correct. You won’t have to worry that the generated code is delegating to the wrong method or forgetting a semicolon. You don’t have to write tests for the generated code. (Yes, this assumes the code generation is correct ☺ ; Magento 2 code generation is for well understood patterns and the code generator itself is tested).
- Consistency in implementation. All generated Factories work the same way. So once you know how one Factory works, you should know how they all work.
- Ability to change the implementation for all generated code. If you discover a better way of implementing a Proxy, you can do it across the board. If you want the code generator to use a PHP
__callmagic method or if you want real methods, you just need to change the generator. The maintenance of code is reduced.
But I need to write my own Factory!
Write the code in your module. If the class really exists, then code will not be generated even if the class name matches a convention.
However, if you do not have custom logic, it is a best practice to use the code generation whenever possible.
When is code regenerated?
If the class does not exist and is missing from
var/generation, then the code generation will be called. So delete the
var/generation directory, and code should be generated again.
When should I regenerate the code?
The practical developer advice is to regenerate whenever you update your Magento 2 code.
rm -rf var/generation and other config cache directories.
Why should I regenerate the code?
Doesn’t this stuff work the first time? ☺
Customer\Proxy class for a
Customer class is generated. The
Customer class has new methods added to it. Because a
Customer\Proxy exists in
var/generation, it will not be re-generated. However, the
Customer\Proxy implementation is incomplete now because it does not have the new methods. You need to regenerate the
On a rare occcasion, the code generator implementation is changed itself which means you should regenerate all the classes.
Personally, I just delete the
var/generation directory (among other cache directories) whenever I update the Magento 2 code. I don’t want to waste my time on weird issues just because my generated code is outdated.
How is the code generated?
More specifically, you may want to check out the \Magento\Framework\Code\Generator\Autoloader.
Why are there Proxy and Factory classes in the lib?
Code generation is only intended for application module code and not the framework, so you will see code for factories and proxies in the
What are some things that can be generated?
Factories are useful for creating objects. In general, use a factory whenever you need to create non-singleton objects in your code.
Proxies lazily instantiate objects and break cyclical dependency cycles. Normally you should never need to reference a proxy directly in code. You usually explicitly configure a Proxy via a di.xml (the dependency injection config file) as one of the constructor arguments to a class.
If you write a Plugin, an Interceptor is generated for the real implementation class to make the Plugin work. I rarely look at these generated classes and look at the Plugin code mode. But the logic is quite interesting and help unravel how Plugins work.