PHP中Trait的使用

Trait

triat是PHP中一种代码复用技术。

官方解释:

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

创建 Triat

使用关键字trait来创建,以Laravel中的用户认证作为实例:

1
<?php
2
3
namespace Illuminate\Foundation\Auth;
4
5
use Illuminate\Http\Request;
6
use Illuminate\Support\Facades\Auth;
7
use Illuminate\Validation\ValidationException;
8
9
trait AuthenticatesUsers
10
{
11
    use RedirectsUsers, ThrottlesLogins;
12
13
    protected function validateLogin(Request $request)
14
    {
15
        $this->validate($request, [
16
            $this->username() => 'required|string',
17
            'password' => 'required|string',
18
        ]);
19
    }
20
21
    public function logout(Request $request)
22
    {
23
        $this->guard()->logout();
24
25
        $request->session()->invalidate();
26
27
        return redirect('/');
28
    }
29
    
30
    .
31
    .
32
    .
33
}

通过use引入AuthenticatesUsers,然后我们创建一个adminLogin登录方法,在这我们可以调用triat中定义的验证方法validateLogin.
还可以重写logout方法。

1
<?php
2
namespace App\Http\Controllers\Admin;
3
4
use App\Http\Controllers\Controller;
5
use Auth;
6
use Illuminate\Foundation\Auth\AuthenticatesUsers;
7
8
class LoginController extends Controller
9
{
10
    use AuthenticatesUsers;
11
12
    public function index()
13
    {
14
        return view('admin/login/index');
15
    }
16
17
    public function adminLogin(Request $request)
18
    {
19
        $this->validateLogin($request);
20
    }
21
22
    public function logout()
23
    {
24
        Auth::guard('admin')->logout();
25
        return redirect('admin/login/index');
26
    }
27
}

优先级

优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。

MyHelloWorld 继承 Base 的 sayHello 方法被 SayWorld Triat 中的 sayHello 方法覆盖。

1
<?php
2
class Base {
3
    public function sayHello() {
4
        echo 'Hello ';
5
    }
6
}
7
8
trait SayWorld {
9
    public function sayHello() {
10
        parent::sayHello();
11
        echo 'World!';
12
    }
13
}
14
15
class MyHelloWorld extends Base {
16
    use SayWorld;
17
}
18
19
$o = new MyHelloWorld();
20
$o->sayHello();
21
?>

输出:

Hello World!

如果在 MyHelloWorld 中定义一个 sayHello 方法的话。那么 MyHelloWorld 中的 sayHello 就会覆盖 SayWorld Triat 中的方法。

1
<?php
2
class Base {
3
    public function sayHello() {
4
        echo 'Hello ';
5
    }
6
}
7
8
trait SayWorld {
9
    public function sayHello() {
10
        parent::sayHello();
11
        echo 'World!';
12
    }
13
}
14
15
class MyHelloWorld extends Base {
16
    use SayWorld;
17
    public function sayHello() {
18
        echo 'Hello My World';
19
    }
20
}
21
22
$o = new MyHelloWorld();
23
$o->sayHello();
24
?>

输出:

Hello My World

多个 trait

通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。
如果两个 trait 都插入了一个同名的方法,使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。或者使用 as 为某个方法引入别名。

1
<?php
2
trait A {
3
    public function smallTalk() {
4
        echo 'a';
5
    }
6
    public function bigTalk() {
7
        echo 'A';
8
    }
9
}
10
11
trait B {
12
    public function smallTalk() {
13
        echo 'b';
14
    }
15
    public function bigTalk() {
16
        echo 'B';
17
    }
18
}
19
20
class Talker {
21
    use A, B {
22
        B::smallTalk insteadof A;
23
        A::bigTalk insteadof B;
24
    }
25
}
26
27
class Aliased_Talker {
28
    use A, B {
29
        B::smallTalk insteadof A;
30
        A::bigTalk insteadof B;
31
        B::bigTalk as talk;
32
    }
33
}
34
?>

官方文档
掌握 PHP Trait 的概念和用法
在 Laravel 中使用 Trait 优化代码结构


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!