Proxies Design
Pattern
Proxies is a powerful and
easy technique to help you overcome a huge problem of Magento 2. Basically, we
can say it is design pattern, which is remove cycle of dependency injection.
However, its role and importance are still underestimated. Therefore, in this
post, I am going to help you to understand what is Magento 2 proxies and
its need in Magento 2.
What are Proxies in Magento 2
Just similar to design patterns which are created to solve a
cycle of dependency problems in the project, proxy design pattern solves a
particular problem. Proxies work as a surrogate which means it acts on behalf
of others, in programming, they are classes which could be used instead of any
other class. More specifically, in Magento 2, proxies are used to replace
resource hungry classes.
However, when replacing like that, an issue happens in Magento 2
In Magento 2 your able use constructor injection pattern to
flexibly manage your class dependencies. However, constructor injection also
means that a chain reaction of object instantiation is often the result when
you create an object. (The original object has dependencies that have
dependencies, and those objects have dependencies, and so on.)
If a
class’s constructor is particularly resource-intensive, this can lead to
unnecessary performance impact when another class depends on it, if the
expensive object does not end up being needed during a particular request. (You
can display a dependency graph of such objects
by enabling profiling.)
As an
example, consider the following two classes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
class SlowLoading { public function __construct() { // ... Do something resource intensive }
public function getValue() { return 'SlowLoading value'; } }
class FastLoading { protected $slowLoading;
public function __construct( SlowLoading $slowLoading ){ $this->slowLoading = $slowLoading; }
public function getFastValue() { return 'FastLoading value'; }
public function getSlowValue() { return $this->slowLoading->getValue(); } } |
Assume that class SlowLoading
has a
non-trivial performance impact when instantiated (perhaps due to a complex
database query or a call to a third-party web API). Because of the dependency
injection in the constructor of FastLoading
, this impact is
incurred if FastLoading
is instantiated. Note, however, that the SlowLoading
instance is used only in the method getSlowValue
, meaning that the resource cost is unnecessary if this method
is never called on the FastLoading
object.
Proxies
are generated code
Magento
has a solution for this situation: proxies. Proxies extend
other classes to become lazy-loaded versions of them. That is, a real instance
of the class a proxy extends is created only after one of the class’s methods
is actually called. A proxy implements the same interface as the original class
and so can be used as a dependency anywhere the original class can. Unlike its
parent, a proxy has only one dependency: the object manager.
Proxies
are generated code and therefore do not need to be manually written. (See Code
generation for more information.) Simply reference a class in the form \Original\Class\Name\Proxy
, and the class is generated if it
does not exist.
Using
the preceding example, a proxy can be passed into the constructor arguments
instead of the original class, using DI configuration as follows:
1 2 3 4 5 |
<type name="FastLoading"> <arguments> <argument name="slowLoading" xsi:type="object">SlowLoading\Proxy</argument> </arguments> </type> |
With
the proxy used in place of SlowLoading
, the SlowLoading
class will not be instantiated—and therefore, the resource
intensive constructor operations not performed—until the SlowLoading
object is used (that is, if the getSlowValue
method is called).
Because
DI configuration is used to inject a proxy, proxies can be dropped in to
replace their corresponding classes - or proxy replacements removed -
without touching application code.
As a
practical example of a proxy, you can see the StoreManager class and
then see the generated StoreManager
proxy
class.
The
following excerpt from the Magento code passes the storeManager
argument as a proxy to the Magento\Store\Model\Resolver\Store
class. The StoreManagerInterface
model is defined as a proxy
class by the added Proxy
at the end of the original class in the di.xml
file.
1 2 3 4 5 |
<type name="Magento\Store\Model\Resolver\Store"> <arguments> <argument name="storeManager" xsi:type="object">Magento\Store\Model\StoreManagerInterface\Proxy</argument> </arguments> </type> |