相对于Magento1版本,2版本增加很多的特性,plugin就是其中一项,允许我们对原来的方法进行重写、覆盖,还是比较实用,在此记录一下plugin的使用经验。
来自官方的说明:plugin插件或拦截器是一个类,它通过拦截函数调用并在该函数调用之前、之后或前后运行代码来修改公共类函数的行为。这允许您替换或扩展任何类或接口的原始公共方法的行为。
一、基础情况
1、需要注意的是以下情况是无法使用plugin进行重写的:Final methods(最终方法)、Final classes(最终类)、Non-public methods(非公共方法)、Class methods (such as static methods)(非公共类)、__construct
(构造函数) 、 __destruct
(析构函数)、Virtual types(虚拟类型)、Objects that are instantiated before Magento\Framework\Interception
is bootstrapped(此类之前的实例化对象)。
2、有两个属性可以在xml配置里面声明,分别是sortorder(调用顺序,多次重写时可用此参数指定运行顺序)、disabled(是否禁用:可以不用改代码直接在xml指定停用)
3、有before、after、around三种方法,分别对应着方法之前、之后、修改当前方法,在此方法加上要修改的方法(原方法第一字符改为大写),再在di.xml声明一下就可以了
<type name="sna\test\Model\Point">
<plugin name="snatestpoing" type="Sna\test\Plugin\Point"/>
</type>
<?php
namespace Sna\Test\Plugin;
class Point
{
protected $_session;
public function __construct(
\Magento\Customer\Model\Session $session
){
$this->_session = $session;
}
public function beforeGetPoint(
\sna\test\Model\Point $subject,
$user
){
........
}
public function aroundGetPoint(
\sna\test\Model\Point $subject,
\Closure $proceed,
$user
){
........
}
public function afterGetPoint(
\sna\test\Model\Point $subject,
$user
){
........
}
}
二、plugin应该怎么开发?
第一种before
这是在原方法执行之前调用,一般可以用来改变参数,达到让原方法结果有不同的返回值,或者基于参数做其它逻辑的处理。
before方法:第一个参数传入原方法对应的类,第二个参数对应原方法参数名,最后return的时候,要用[]包含原参数名,如果原方法没参数,return []就行。
<?php
#原方法
namespace Sna\Test\Model;
class Point
{
public function getPoint($user
){
if($user->getPoint()){
$this->point = $user->getPoint();
}
return $this->point;
}
}
namespace Sna\Test\Plugin\Point;
class Point
{
public function beforeGetPoint(
\Sna\Test\Model\Point $subject,
$user
){
if($user->getPoint()){
$this->point = 1;
}
return [$user];
}
}
第二种after
这是在原方法执行之后调用,一般可以用来修改/改变结果(如某一组用户返回多一些信息),或者基于结果做其它逻辑的处理。
after方法:第一个参数传入原方法对应的类,第二个参数对应原方法参数名,最后直接return 原方法的参数,不同于before方法,是不需要用[]包含起来
<?php
#原方法
namespace Sna\Test\Model;
class Point
{
public function getPoint($user
){
if($user->getPoint()){
$this->point = $user->getPoint();
}
return $this->point;
}
}
namespace Sna\Test\Plugin\Point;
class Point
{
public function afterGetPoint(
\Sna\Test\Model\Point $subject,
$user
){
if($user->getPoint()==1){
return fasle;//中断返回
}
return $user;//保持原来的结果
}
}
第三种around
这是可以直接修改原方法逻辑,当before及after都无法实现你的要求,必需调整原方法的逻辑时(如原方法直接查询用户信息再做处理,你的需求是基于用户信息再次调整逻辑)
around方法:第一个参数传入原方法对应的类,第二个参数需要为\Closure $proceed(对应为原方法的执行结果),第三个参数才是原方法的参数,最后直接return 结果,或return $proceed()走原方法的逻辑
<?php
#原方法
namespace Sna\Test\Model;
class Point
{
public function getPoint($user
){
if($user->getPoint()){
$this->point = $user->getPoint();
}
return $this->point;
}
}
namespace Sna\Test\Plugin\Point;
class Point
{
public function afterGetPoint(
\Sna\Test\Model\Point $subject,
\Closure $proceed,
$user
){
if($user->getPoint()==1 && $subject->getCustomerId()>0){
return fasle;//中断返回
}
return $proceed($user);//让程序走原来的逻辑
}
}
before、after、around这几种方法,需要注意的是:前一个参数都需要对应原方法的类,第二个参数之后保持跟原方法的参数数量一致就好,如原参数有3个参数,那么在修改后应该有4个参数,around也是如上,只不过还要多一个\Closure $proceed占用第二个参数位,如果是原方法并没有参数也是可以不传参。