Magento 2 uses the Proxy design pattern to improve system performance. It helps manage heavy objects that consume high memory. The system creates a “placeholder” instead of the real object. This ensures that Magento only initializes expensive classes when they are actually needed.
What is a Proxy?
A Proxy is a class that replaces another class. It shares the same interface as the original object. Magento generates these classes automatically during the code compilation process. By using proxies, you prevent unnecessary object instantiation during the bootstrap phase.
Why Use Proxies in Magento 2?
Most Magento 2 classes use Constructor Injection. If a class has ten dependencies, Magento loads all ten immediately. Some dependencies might be “heavy” or rarely used. A Proxy stops this “chain reaction” of loading, which speeds up your application significantly.
What is the proxy design pattern ?
The Magento 2 Proxy Design Pattern is a structural design pattern. It works as a placeholder for another object. The real object is created only when it is actually required. This approach is known as lazy loading. Magento uses proxies to avoid heavy object initialization during class construction.
Lets understand why this problem comes in magento2.
Problem:
Magento 2 supports multiple types of dependency injection, with constructor injection and method injection used most frequently.
Constructor injection introduces a performance issue. When a class is instantiated, Magento immediately creates all objects injected into its constructor.
This behavior triggers a chain reaction where Magento creates multiple dependent objects at once. As the number of dependencies increases, the instantiation process becomes slower and resource-intensive.
To prevent this chain reaction and improve performance, Magento uses the Proxy Design Pattern, which enables lazy loading of dependencies.
Solution:
Magento solves this performance problem by using the Proxy Design Pattern.
Instead of creating all dependencies during class instantiation, Magento injects a proxy class into the constructor. The proxy acts as a placeholder for the actual dependency. Magento creates the real object only when the code actually uses it.
This approach delays object creation and avoids unnecessary instantiation. As a result, Magento reduces memory usage and improves overall performance.
The Proxy Design Pattern enables lazy loading while keeping constructor injection clean and maintainable.
Example:
<type name="Magento\Catalog\Model\Product">
<arguments>
<argument name="catalogProductStatus" xsi:type="object">
Magento\Catalog\Model\Product\Attribute\Source\Status\Proxy
</argument>
<argument name="productLink" xsi:type="object">
Magento\Catalog\Model\Product\Link\Proxy
</argument>
</arguments>
</type>
The above entry comes from the Catalog module’s di.xml file.
In the type declaration for the Magento\Catalog\Model\Product class, Magento replaces the constructor arguments catalogProductStatus and productLink with their corresponding Proxy classes:
Magento\Catalog\Model\Product\Attribute\Source\Status\ProxyMagento\Catalog\Model\Product\Link\Proxy
Both classes include the word Proxy, which indicates the use of the Proxy Design Pattern. You will not find these proxy classes in the Magento 2 codebase after installation.
Magento generates these proxy classes automatically using its code generation system.
The system creates proxy classes in two situations.
First, when you run the CLI command:
php bin/magento setup:di:compile
Magento scans all di.xml files across installed modules.
If it finds a reference to a Proxy class that does not exist, it generates the class automatically inside the generated/code directory with the same namespace.
Second, when Magento requests a Proxy class at runtime and the class does not exist, it does not throw an error.
Instead, Magento dynamically generates the Proxy class inside the generated/code directory and returns its object.
This mechanism shows that Magento generates proxy classes on demand using a fixed convention.
Magento replaces the original object with its Proxy, but the key question remains: how does the Proxy solve the performance problem?
To understand this, we need to analyze a generated Proxy class.
Let’s look at the Proxy class next.
<?php
namespace Magento\Catalog\Model\Product\Attribute\Source\Status;
/**
* Proxy class for @see \Magento\Catalog\Model\Product\Attribute\Source\Status
*/
class Proxy extends \Magento\Catalog\Model\Product\Attribute\Source\Status implements \Magento\Framework\ObjectManager\NoninterceptableInterface
{
/**
* Object Manager instance
*
* @var \Magento\Framework\ObjectManagerInterface
*/
protected $_objectManager = null;
/**
* Proxied instance name
*
* @var string
*/
protected $_instanceName = null;
/**
* Proxied instance
*
* @var \Magento\Catalog\Model\Product\Attribute\Source\Status
*/
protected $_subject = null;
/**
* Instance shareability flag
*
* @var bool
*/
protected $_isShared = null;
/**
* Proxy constructor
*
* @param \Magento\Framework\ObjectManagerInterface $objectManager
* @param string $instanceName
* @param bool $shared
*/
public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, $instanceName = '\\Magento\\Catalog\\Model\\Product\\Attribute\\Source\\Status', $shared = true)
{
$this->_objectManager = $objectManager;
$this->_instanceName = $instanceName;
$this->_isShared = $shared;
}
/**
* @return array
*/
public function __sleep()
{
return ['_subject', '_isShared', '_instanceName'];
}
/**
* Retrieve ObjectManager from global scope
*/
public function __wakeup()
{
$this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
}
/**
* Clone proxied instance
*/
public function __clone()
{
$this->_subject = clone $this->_getSubject();
}
/**
* Get proxied instance
*
* @return \Magento\Catalog\Model\Product\Attribute\Source\Status
*/
protected function _getSubject()
{
if (!$this->_subject) {
$this->_subject = true === $this->_isShared
? $this->_objectManager->get($this->_instanceName)
: $this->_objectManager->create($this->_instanceName);
}
return $this->_subject;
}
/**
* {@inheritdoc}
*/
public function getVisibleStatusIds()
{
return $this->_getSubject()->getVisibleStatusIds();
}
/**
* {@inheritdoc}
*/
public function getSaleableStatusIds()
{
return $this->_getSubject()->getSaleableStatusIds();
}
/**
* {@inheritdoc}
*/
public function getAllOptions()
{
return $this->_getSubject()->getAllOptions();
}
/**
* {@inheritdoc}
*/
public function getOptionText($optionId)
{
return $this->_getSubject()->getOptionText($optionId);
}
/**
* {@inheritdoc}
*/
public function addValueSortToCollection($collection, $dir = 'asc')
{
return $this->_getSubject()->addValueSortToCollection($collection, $dir);
}
/**
* {@inheritdoc}
*/
public function setAttribute($attribute)
{
return $this->_getSubject()->setAttribute($attribute);
}
/**
* {@inheritdoc}
*/
public function getAttribute()
{
return $this->_getSubject()->getAttribute();
}
/**
* {@inheritdoc}
*/
public function getOptionId($value)
{
return $this->_getSubject()->getOptionId($value);
}
/**
* {@inheritdoc}
*/
public function getFlatColumns()
{
return $this->_getSubject()->getFlatColumns();
}
/**
* {@inheritdoc}
*/
public function getFlatIndexes()
{
return $this->_getSubject()->getFlatIndexes();
}
/**
* {@inheritdoc}
*/
public function getFlatUpdateSelect($store)
{
return $this->_getSubject()->getFlatUpdateSelect($store);
}
/**
* {@inheritdoc}
*/
public function getIndexOptionText($value)
{
return $this->_getSubject()->getIndexOptionText($value);
}
/**
* {@inheritdoc}
*/
public function toOptionArray()
{
return $this->_getSubject()->toOptionArray();
}
}
Understanding the Proxy Class in Magento 2
A Proxy class follows a strict structure to replace the original class efficiently.
- The namespace of the Proxy class matches the original class
(Magento\Catalog\Model\Product\Attribute\Source\Status).
This allows Magento to seamlessly substitute the original object with the Proxy. - The Proxy class extends the original class, so it can access all public methods without breaking functionality.
- The Proxy implements
\Magento\Framework\ObjectManager\NoninterceptableInterface.
This marker interface prevents plugins from intercepting the Proxy class. - The constructor is the most important part. It injects only the
ObjectManager, not the full dependency chain. This makes the Proxy lightweight and fast to instantiate. The constructor does not call the parent constructor, which avoids unnecessary object creation. - PHP magic methods like
__sleep,__wakeup, and__clonemanage serialization and cloning behavior safely. - The
_getSubject()method creates and returns the original class object only when needed. This enables lazy loading and delays heavy object creation. - All public methods from the original class are overridden in the Proxy. Each method calls
_getSubject()and then delegates execution to the real object.
In short, the Proxy class delays object creation until required, reducing memory usage and improving Magento 2 performance.
For technical assistance, please get in touch with us via email at support@webkul.com.
Discover powerful solutions to enhance your Magento 2 store by exploring our Magento 2 plugins page.
Bring your vision to life with custom-built solutions—hire skilled Magento 2 developers today.
Happy Coding!!

10 comments
class Example extends Crazy\SimpleSolution\Model\Test\Proxy
if this possible ?? if not why
there is abc class and i need to call some function from xyz class.
Normal practice is xyz add in constructor and make a variable in constructor and use it. so xyz also will load while initialize abc object. but with the help of proxy xyz class will not load while initialize abc object and although we can use xyz class function in abc class if we define xyz class as proxy in di.xml. am i right?