Even though both plugins and observers have been around for quite some time, there are a lot of developers who don’t really understand the difference between the two and which one you should use in different situations.
Over the years we’ve optimized a lot of third-party extensions and customizations where inexperienced developers used poor development methods instead of researching whether they should use plugins or observers for what they were trying to build.
So in the article, we take a look at plugins, observers, and preferences, compare them with one another, and showcase situations in which these development tools work the best.
Some extension developers use preferences and don’t make a big deal out of it. But the way Magento handles preferences doesn’t allow us to use them as a good replacement.
Preferences don’t offer enough reliability in Magento. Let’s say two distinct extensions use preferences to set the same value. Because of the way Magento loads extensions, it will rewrite the value with the preference that was loaded last.
This means if two extensions use the same preference to modify something the preference that loads last will override everyone else’s changes. This conflict will lead to huge bugs in extensions that are loaded first which is of course unacceptable.
But if you use redefining too often, get ready for extensive compatibility testing next time you need to update to a newer Magento version. This happens because when something gets added to the constructor, the affected class that gets redefined will also require you to add the same code to your own class.
But changing the construct is only one of the reasons Magento acts up. Another factor is adding new features to the store. In this case, the slowdown happens because when Magento gets new features you have to port them over to your redefined code. In addition, your code can stop working from the slightest change in the class that you have redefined.
Execute the command bin/magento setup:di:compile in order to check your code for this issue. Even though, it will not free you from the task of analyzing the cause of this change and making your code compatible with the new changes in the redefined file.
You could use preferences to customize your Magento store if you are the only one who creates customizations for the store and you are sure they won’t conflict with one another. In any other case, we strongly advise against using preferences for customizations.
When we remove preferences from the equation what we are left with are observers and plugins. Observers used to be one of the main means of adding changes to the code logic, but today this is the prerogative of dependency injections and plugins. Event observers are legacy elements from the Magento 1 era which are quite limited in what they can do.
Speaking from our own experience, a lot of Magento developers use event observers for their extensions but don’t really implement them properly. For example, an extension will use an event observer to make Checkout faster.
A poorly built observer can affect the performance of the whole store. For example, if you hook up the observer to the model_load_after event and make a badly optimized function there, the store can become punishingly slow. That’s why we’ve recommended removing unused plugins and event observers in our complete guide on Magento 2 speed optimization.
Event observers are not without their uses, though. Even if their best years are now behind them, they still offer a decent number of applications. One prominent example would be creating extension points inside private or protected Magento methods.
Observers are also useful when you need to log something specific, clean the cache, or send a piece of data to another system. They are 100% fit for tracking changes/creation/removal/initialization of specific models that are inherited from \Magento\Framework\Model\AbstractModel.
One crucial point, though. Let’s say we need to save every changing model ID into a log file. If you wanted to use a plugin you’d have to create one for every model in the system that uses AbstractModel inheritance.
At the same time, you can’t attach this plugin directly to the AbstractModel since this class has a standard save function. The function works fine for any model that triggers the model_save_after event used to track the changes in every inheritance that calls on this function.
Observers are extremely useful if you need to find a workaround for the limitations that plugins have. If you attach a plugin to the parent class from which many other classes are inherited, it will not work. But if the parent class generates an event, then it will be possible to perform actions with all entities that are inherited from that event.
Plugins are more versatile than observers. Plugins can change the behavior of any public method in Magento (except for virtual and final classes, final, static and non-public methods, constructors, and objects instantiated before bootstrapping Magento\Framework\Interception).
Compared to event observers, plugins can function anywhere in the system. They can be used to change or override any public method in Magento. Plugins are a valuable tool in custom development. For example, they are not affected by new Magento patches.
Used in conjunction with stable public API (bearing the @api mark), developers can write plugin-based code that is resistant to new Magento updates and offers all 3 methods (before, after, and around) to overwrite the original Magento 2 behavior.
Plugins are also called interceptors because they can intercept the function before, during, and after the call. See, the thing is you can change almost any function with a plugin:
- with Before plugins developers can alter input arguments;
- with After plugins they can change the result of the function;
- and using Around plugins they can completely change the logic of the function.
In plain English, this means that plugins don’t conflict with one another. They are always called one by one according to a pre-sorted sequence which reduces mutual conflicts. Even more:
- used throughout the platform, plugins can be implemented for any public function;
- they are great for extensions that need to intercept and change public method behavior;
- when too many plugins are used around the call, they increase stack traces and reduce site performance.
Magento 1 didn’t generally leave developers with a lot of options. If they needed to change the behavior of the original code, they either had to implement observers to listen to certain events or deal with a confusing mess of preferences which could screw with each others’ values if the developer isn’t careful enough.
But now the time of event observers is long gone. Observers are stuck in the M1 era. They are mostly used as a part of legacy code or in narrow applications in M2 development.
Event observers have disadvantages:
- observers are slower than plugins because Magento creates at least 3 objects upon the trigger event;
- observers offer less flexibility when you need to introduce platform-wide features;
- event observers have critical limitations since they MUST NOT change the objects that they influence.
Bear in mind that sometimes event observers can be useful even in Magento 2 development. Same as in M1, setting up observers can come in handy when you want to implement store-wide features such as a reward system and bonus points for purchases.
But even then you are better off using plugins to get the job done. Event observers can be also used separately for frontend and adminhtml (with events.xml file designating their field of application).
Core Magento 2 also has a lot of places where event observers play a prominent role in changing the logic of the application. The sheer number of places where observers work inside Magento means that it would be extremely difficult to get rid of them any time soon.
There’s no doubt in the developer community that observers will eventually fade out of favor. But it will only happen when M2 completely abandons inheritance in favor of composition which is not the matter of the near future.
We’ve created a mini-guide on how to choose the optimal tool for your task (ranked from most suited to less suited):
- use plugins with @api methods over simple plugins. @api methods will not get changed often by the Magento core dev team and thus are more reliable and future-proof;
- event observers will remain your second best choice especially if you are well-acquainted with them from the M1 dev times;
- [email protected] plugins should be used last. They offer less stability than event observers and don’t have the advantages of @api plugins.
Still have trouble upgrading your third-party extensions from observers to plugins? Want to boost your store speed or make it more reliable? Being a Magento 2 development company, Onilab can help you move faster in the vivid e-commerce environment and upgrade your Magento extensions with proper plugin use. Drop us a line to start your faster e-commerce journey today.