日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

為什么 php 會引入 Trait ? 我們先來看看軟件開發中的兩種常用代碼復用模式,繼承組合

  • 繼承:強調 父類與子類 的關系,即子類是父類的一個特殊類型;
  • 組合:強調 整體與局部 的關系,側重的一種需要的關系;

軟件開發中有一條原則,叫做組合優于繼承。這是因為從耦合度來看,繼承要高于組合。繼承關系中,子類與父類保持著高度的依賴關系,加上 PHP 不支持多繼承,為了避免重寫編寫代碼,很多功能都被統一封裝到父類中。這樣做有兩個壞處:一是隨著繼承的層數和子類的增加,代碼復雜度不斷增加,大量的方法都將面臨著重寫;二是這些功能對于一些子類來說可能是不必要的,破壞了代碼的封裝性。

Trait 的提出彌補了 PHP 對組合支持的不足,一個 Trait 就相當于一個模塊,不同的 Trait 以組合的方式注入到類中。我們以 Laravel 的控制器為例,來介紹下繼承和組合是如何在具體的場景中使用的。

首先,底層的代碼應當多使用組合。Laravel 的底層控制器只繼承了一個簡單的控制器 IlluminateRoutingController,結構相對穩定。同時,控制器使用了不同的 Trait 來組織代碼,避免了對象的臃腫,極大程度的保持了架構的靈活性。

<?php

namespace AppHttpControllers;

use IlluminateFoundationAuthAccessAuthorizesRequests;
use IlluminateFoundationBusDispatchesJobs;
use IlluminateFoundationValidationValidatesRequests;
use IlluminateRoutingController as BaseController;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

具體的業務邏輯或頂層代碼應當多使用繼承,這樣能夠大大提高的開發效率

<?php
use AppHttpControllersController;

class UserController extends Controller
{
}

以上就是繼承和組合的簡單介紹。接下來看看 Trait 的具體使用。

使用規范

Symfony 編碼規范建議在每個 Trait 之后添加 Trait 關鍵字。

namespace SymfonyContractsTranslation;

trait TranslatorTrait {

}

PSR-12 規范建議在每個 Trait 使用一個 use 語句來聲明,同時 Trait 與類的其他成員需要保持一行空行。

class ClassName
{
    use FirstTrait;
    use SecondTrait;
    use ThirdTrait;

    public $a;
}

成員

Trait 中可包含屬性、方法 與 抽象方法,這三者的結合既可以復用代碼,也可以對代碼的使用作出一些約定,例如 Laravel 中的自動維護 slug 字段

<?php

namespace AppTraits;

use IlluminateSupportStr;

trait HasSlug 
{   
    public static function bootSluggable()
    {
        static::saving(function ($model) {
            $model->slug = Str::slug(
                $model->getAttribute( $model->sluggable() )
            );
        });
    }

    /**
     * Slug 字段
     * 
     * @return string
     */
    abstract public function sluggable(): string;

}

Trait 中也可以包括靜態屬性和靜態方法,以下是一個單例模式的簡單封裝。

trait Singleton
{
    private static $instance;

    public static function getInstance() {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self;
        }
        return self::$instance;
    }
}

每個 Trait 中可以包含其他 Trait,進一步提高了代碼的靈活性

<?php
trait Hello
{
    function sayHello() {
        echo "Hello";
    }
}

trait World
{
    function sayWorld() {
        echo "World";
    }
}

class MyWorld
{
    use Hello;
    use World;
}

Trait 與類的沖突處理

當存在同名方法時,當前類的方法會覆蓋 Trait 中的方法,而 Trait 中的方法會覆蓋父類的方法。

<?php
// 父類,優先級最低
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

// Trait 優先級大于父類
trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

// 當前類,優先級最高
class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();  // Hello, World

當存在同名屬性時,類的屬性必須與 Trait 的屬性兼容(相同的訪問性、相同的初始值),否則會報致命錯誤

<?php
trait Foo {
    public $same = true; 
    public $different = false;
}

class Bar {
    use Foo;
    public $same = true; // 合法
    public $different = true; // fatal error
}

Trait 與 Trait 的沖突處理

當一個類包含多個 Trait 時,不同 Trait 之間可能會存在屬性和方法的沖突。

當存在相同屬性時,屬性必須兼容,跟 Trait 與類的沖突處理類似

Trait A {
    public $a = 'foo';
}
Trait B {
    public $a = 'foo';
}
class Foo 
{
    use A;
    use B;
}

當存在方法沖突時,需要使用 insteadof 來手動處理沖突,否則會報致命錯誤

<?php
Trait A {
    public function foo()
    {
        return "A foo";
    }
}

Trait B {
    public function foo()
    {
        return "B foo";
    }
}

class Bar {
    use A, B {
        B::foo insteadof A;  // 用 B 的 foo 方法來代替 A
    }
}

$bar = new Bar();
echo $bar->foo();  // B foo

這時候如果想要保留 A 的 foo 方法,可以用 as 定義別名來進行調用。注意,起別名僅僅代表可以用別名來調用該方法,仍然需要用 insteadof 處理沖突

class Bar {
    use A, B {
        B::foo insteadof A;  // 用 B 的 foo 方法來代替 A
        A::foo as aFoo; // A 的  foo 方法用 aFoo 來調用
    }
}

$bar = new Bar();
echo $bar->aFoo(); // A foo

as 關鍵字還可以用來更改方法法的訪問控制

<?php

Trait A {
    public function foo()
    {
        return "A foo";
    }
}

class Bar {
    use A {
        A::foo as private;
    }
}

$bar = new Bar();
echo $bar->foo(); // Fatal error: Uncaught Error: Call to private method Bar::foo()

這兩者可以結合起來用,這時候原有方法的訪問控制就不會受到影響

<?php

Trait A {
    public function foo()
    {
        return "A foo";
    }
}

class Bar {
    use A {
        A::foo as private aFoo;
    }
}

$bar = new Bar();
echo $bar->foo(); // A foo,照常調用
echo $bar->aFoo(); // 被設置成私有方法,因此報錯。Fatal error: Uncaught Error: Call to private method

關注我吧,每日不斷更新內容!!!

分享到:
標簽:PHP
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定