Edit in GitHubLog an issue
Thanks to Classy Llama for contributing this topic!

Proxies

The Adobe Commerce and Magento Open Source constructor injection pattern enables you 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:

Copied to your clipboard
1class SlowLoading
2{
3 public function __construct()
4 {
5 // ... Do something resource intensive
6 }
7
8 public function getValue()
9 {
10 return 'SlowLoading value';
11 }
12}
13
14class FastLoading
15{
16 protected $slowLoading;
17
18 public function __construct(
19 SlowLoading $slowLoading
20 ){
21 $this->slowLoading = $slowLoading;
22 }
23
24 public function getFastValue()
25 {
26 return 'FastLoading value';
27 }
28
29 public function getSlowValue()
30 {
31 return $this->slowLoading->getValue();
32 }
33}

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#

The application 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:

Copied to your clipboard
1<type name="FastLoading">
2 <arguments>
3 <argument name="slowLoading" xsi:type="object">SlowLoading\Proxy</argument>
4 </arguments>
5</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 application 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.

Copied to your clipboard
1<type name="Magento\Store\Model\Resolver\Store">
2 <arguments>
3 <argument name="storeManager" xsi:type="object">Magento\Store\Model\StoreManagerInterface\Proxy</argument>
4 </arguments>
5</type>
Was this helpful?
  • Privacy
  • Terms of Use
  • Do not sell my personal information
  • AdChoices
Copyright © 2022 Adobe. All rights reserved.