The old way:

If you come from Magento 1 world, then you probably know you have 3 main options to change an internal behaviour:

  • Create an observer
  • Create a class rewrite
  • Create a local overriding class

All the three ways has pro and cons, expecially when you want to make your module redistributable.

We all know the observer way is the best one because it does not actually rewrite anything and multiple modules can access the same resource without conflicting, but we also know it is not always available. For example some events are missing and sometime observing an event is not enough for what you need to do.

The rewrite way is the most used, it allows you to do almost anything, but we all know that two rewrites from two different modules to the same resource result in a conflict.

The overriding way is the most powerful, but also the most dangerous since it replaces a whole class exposing your Magento to backwards compatibility issues and a bunch of other problems.

So, to be honest, we had no a real solution in Magento 1 to avoid problems or conflicts while installing or creating modules.

The new Magento 2 way:

In Magento 2 we have a new option called “plugin“. This is one of the most powerful options introduced in this new version.

A plugin allows you to intercept an existing method execution and run code after or before. It can also be used to change the input or the output and even to replace the whole method.

A plugin works using 3 possible strategies:

  • before: A code running before the intercepted method
  • after: A code running after the intercepted method
  • around: A code wrapping the intercepted method

Example of a “before” plugin:

Immagine you need to filter a product’s SKU by removing all the non-alphanueric chars. You can do this by using a “before” plugin on class “Magento\Catalog\Model\Product“.

First of all you have to register you plugin in your di.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    ...
    <type name="Magento\Catalog\Model\Product">
        <plugin sortOrder="1" name="myTestProduct"
            type="My\Module\Plugin\Model\ProductPlugin"/>
    </type>
    ...
</config>

Now let’s create the plugin class itself:

<?php
namespace My\Module\Plugin\Model;

class ProductPlugin
{
    public function beforeBeforeSave(\Magento\Catalog\Model\Product $subject)
    {
        // This code will run just before the "beforeSave" method
        // in "Magento\Catalog\Model\Product"
        $subject->setSku(preg_replace('/\W+/', '', $subject->getSku()));
    }
}

Since we are going to intercept the “before” event on “beforeSave” method, we have to call our intercepting method “beforeBeforeSave“.

An “after” plugin:

To change the values returned by an original method or add code after its execution, you can use the after strategy by prefixing the original method name with “after“.

In the next example we will double the products prices by changing the getPrice method output.

<?php
namespace My\Module\Plugin\Model;

class ProductPlugin
{
    ...
    public function afterGetPrice(\Magento\Catalog\Model\Product $subject, $result)
    {
       return $result * 2;
    }
    ...
}

An “around” plugin:

The last strategy is the “around” strategy that allow you to wrap a method and, if needed, change its input or output:

In the next example we will change the tier prices calculation. In out example we will need to set “3” as minimum quantity and reduce the resulting price by an half.

<?php
namespace My\Module\Plugin\Model;

class ProductPlugin
{
    ...
    public function aroundGetTierPrice(\Magento\Catalog\Model\Product $subject, \Closure $procede, $qty = null)
    {
        $qty = min(3, $qty);
        $res = $procede($qty);
        return $res / 3;
    }
    ...
}

Why plugins are better than rewrites:

A plugin is stackable, you can inercept the same method from different modules without conflicting. A calling priority can be defined in your di.xml.

More information can be found here: http://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html