关于重写 sendResetResponse() 方法的trait加载机制

Trait 与类的冲突处理

当存在同名方法时,当前类的方法会覆盖 Trait 中的方法,而 Trait 中的方法会覆盖父类的方法。

例子:

目录结构如下:

OOP
--traits
    --test
        helloTrait.php
myHelloWord.php

helloTrait.php代码如下:

<?php
namespace OOP\traits\test;
trait helloTrait
{
    public function hello(){
        echo 'this is helloTrait';
    }
}
  1. myHelloWord类中没有声明hello()方法时:

代码如下:

<?php
require './vendor/autoload.php';
use OOP\traits\test\helloTrait;
class myHelloWorld
{
    use helloTrait;
    public function sayHello(){
        // 调用hello方法。
        $this->hello();
    }
}
$obj = new myHelloWorld();
$obj->sayHello();

毫无疑问,输出的是this is helloTrait,也就是说调用的是trait中的hello()方法。

  1. myHelloWord类中声明了hello()方法时:

代码如下:

<?php
require './vendor/autoload.php';
use OOP\traits\test\helloTrait;
class myHelloWorld
{
    use helloTrait;
    public function sayHello(){
        // 调用hello方法。
        $this->hello();
    }
    public function hello(){
        echo 'this is myHelloWorld';
    }
}
$obj = new myHelloWorld();
$obj->sayHello();

输出的是:this is myHelloWorld。也就是说调用的是myHelloWorld类中的方法。也就是说当前类的hello()方法覆盖了trait中的hello()方法
正如文章开头所言:
trait存在同名方法时,当前类的方法会覆盖 Trait 中的方法。

回到教程中重写 sendResetResponse() 方法的问题

  1. 先看更新密码的路由:
    Route::post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');

关于重写 sendResetResponse() 方法的trait加载机制

  1. 当我们点击重置密码的时候会调用ResetPasswordControllerreset()方法。我们先看一下ResetPasswordController的码源:
    <?php
    namespace App\Http\Controllers\Auth;
    use App\Http\Controllers\Controller;
    use Illuminate\Foundation\Auth\ResetsPasswords;
    use Illuminate\Http\Request;
    class ResetPasswordController extends Controller
    {
     use ResetsPasswords;
     protected $redirectTo = '/';
     public function __construct()
     {
         $this->middleware('guest');
     }
    }
    发现ResetPasswordController类中没有reset()方法,但是发现使用了ResetsPasswordstrait。根据use Illuminate\Foundation\Auth\ResetsPasswords;和教程得知:该路由调用的是ResetsPasswordstrait中的reset()方法。我们来看一下ResetsPasswordstrait中的reset()方法的返回值:
    public function reset(Request $request)
     {
         ...
         // 如果重置成功,我们会调用 sendResetResponse 方法重定向到程序主页上,
         // 失败的话调用 sendResetFailedResponse 返回并附带错误信息
         return $response == Password::PASSWORD_RESET
                     ? $this->sendResetResponse($request, $response)
                     : $this->sendResetFailedResponse($request, $response);
     }
    根据注释我们得知如果重置成功,我们会调用 sendResetResponse 方法重定向到程序主页上。
    回到本节的问题:重置密码成功后没有反馈。也就是说ResetsPasswordstrait中的sendResetResponse()方法并没有达到预期的效果。但是ResetsPasswordstrait是laravel框架自带的,最好不要去动它。更好的解决办法是覆盖trait中的sendResetResponse()方法

具体的解决办法

利用Trait 与类的冲突处理。即在ResetPasswordController类中声明sendResetResponse()方法

<?php
...
class ResetPasswordController extends Controller
{
    ...
    protected function sendResetResponse(Request $request, $response)
    {
        session()->flash('success', '密码更新成功,您已成功登录!');
        return redirect($this->redirectPath());
    }
}

参考:

PHP 核心特性 - Trait

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!