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 优化代码结构