ddtcorex

30 Jun 2026 · 2 min read

Magento 2 modules, Dependency Injection & Plugin/Interceptor

How Magento 2 modules compose, how the Dependency Injection container wires them, and how the plugin system lets you change behavior without patching core.

The single most important idea in Magento 2 is this: you almost never modify core code. Instead you extend it through a layered, configuration-driven system. This post covers the first half of that system — modules and the Dependency Injection (DI) container.

Modules are the unit of composition

A Magento 2 store is a collection of modules. Each module lives under app/code/<Vendor>/<Module>/ and declares itself in etc/module.xml and composer.json. The app/etc/config.php file (auto-generated) records which modules are enabled and in what order — order matters, because later modules can depend on earlier ones.

Dependency Injection is configuration, not code

Magento's object manager is a DI container. Instead of writing new Foo(), you declare constructor dependencies in PHP and let the container inject them. Configuration lives in etc/di.xml:

<type name="Vendor\Module\Model\Example">
    <arguments>
        <argument name="logger" xsi:type="object">Magento\Framework\Logger\Monolog</argument>
    </arguments>
</type>

This is what makes Magento testable and swappable: you can replace a class implementation project-wide by editing di.xml, with no edits to call sites.

Plugins (Interceptors): the safe override

A plugin lets you intercept a public method and run code before, after, or around it — without rewriting the class. Define it in etc/di.xml:

<type name="Magento\Catalog\Model\Product">
    <plugin name="log_product_name" type="Vendor\Module\Plugin\ProductNameLogger" />
</type>
class ProductNameLogger
{
    public function beforeGetName(\Magento\Catalog\Model\Product $subject)
    {
        // runs before Product::getName()
    }

    public function afterGetName(\Magento\Catalog\Model\Product $subject, $result)
    {
        return strtoupper($result); // mutate the return value
    }
}

Plugins are the default tool for changing behavior because they compose: many modules can plugin the same method, and Magento sorts them by sort order. You avoid the classic "two extensions both rewrite the class" collision.

Verifying on the running stack

Drop a module into app/code, then from govard shell:

bin/magento setup:upgrade
bin/magento cache:flush

The new module registers, its di.xml is compiled, and your plugin takes effect.

What's next in this series

Plugins are one override mechanism; events are the other. Next we compare them directly — when to use a plugin versus an event observer, and the performance and maintainability trade-offs of each.

Next in this series: Events/Observers vs Plugins — when to use which — /blog/magento2-events-vs-plugins

magento2dipluginsmodules