如何解析Laravel框架下的Contracts契約-創(chuàng)新互聯(lián)

小編給大家分享一下如何解析Laravel框架下的Contracts契約,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

創(chuàng)新互聯(lián)建站專(zhuān)業(yè)為企業(yè)提供龍圩網(wǎng)站建設(shè)、龍圩做網(wǎng)站、龍圩網(wǎng)站設(shè)計(jì)、龍圩網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、龍圩企業(yè)網(wǎng)站模板建站服務(wù),10余年龍圩做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

Contracts

Laravel 的契約是一組定義框架提供的核心服務(wù)的接口, 例如我們?cè)诮榻B用戶(hù)認(rèn)證的章節(jié)中到的用戶(hù)看守器契約IllumninateContractsAuthGuard 和用戶(hù)提供器契約IlluminateContractsAuthUserProvider以及框架自帶的App\User模型所實(shí)現(xiàn)的IlluminateContractsAuthAuthenticatable契約。

為什么使用契約

通過(guò)上面幾個(gè)契約的源碼文件我們可以看到,Laravel提供的契約是為核心模塊定義的一組interface。Laravel為每個(gè)契約都提供了相應(yīng)的實(shí)現(xiàn)類(lèi),下表列出了Laravel為上面提到的三個(gè)契約提供的實(shí)現(xiàn)類(lèi)。

如何解析Laravel框架下的Contracts契約

所以在自己開(kāi)發(fā)的項(xiàng)目中,如果Laravel提供的用戶(hù)認(rèn)證系統(tǒng)無(wú)法滿足需求,你可以根據(jù)需求定義看守器和用戶(hù)提供器的實(shí)現(xiàn)類(lèi),比如我之前做的項(xiàng)目就是用戶(hù)認(rèn)證依賴(lài)于公司的員工管理系統(tǒng)的API,所以我就自己寫(xiě)了看守器和用戶(hù)提供器契約的實(shí)現(xiàn)類(lèi),讓Laravel通過(guò)自定義的Guard和UserProvider來(lái)完成用戶(hù)認(rèn)證。自定義用戶(hù)認(rèn)證的方法在介紹用戶(hù)認(rèn)證的章節(jié)中我們介紹過(guò),讀者可以去翻閱那塊的文章。

所以Laravel為所有的核心功能都定義契約接口的目的就是為了讓開(kāi)發(fā)者能夠根據(jù)自己項(xiàng)目的需要自己定義實(shí)現(xiàn)類(lèi),而對(duì)于這些接口的消費(fèi)者(比如:Controller、或者內(nèi)核提供的 AuthManager這些)他們不需要關(guān)心接口提供的方法具體是怎么實(shí)現(xiàn)的, 只關(guān)心接口的方法能提供什么功能然后去使用這些功能就可以了,我們可以根據(jù)需求在必要的時(shí)候?yàn)榻涌诟鼡Q實(shí)現(xiàn)類(lèi),而消費(fèi)端不用進(jìn)行任何改動(dòng)。

定義和使用契約

上面我們提到的都是Laravel內(nèi)核提供的契約, 在開(kāi)發(fā)大型項(xiàng)目的時(shí)候我們也可以自己在項(xiàng)目中定義契約和實(shí)現(xiàn)類(lèi),你有可能會(huì)覺(jué)得自帶的Controller、Model兩層就已經(jīng)足夠你編寫(xiě)代碼了,憑空多出來(lái)契約和實(shí)現(xiàn)類(lèi)會(huì)讓開(kāi)發(fā)變得繁瑣。我們先從一個(gè)簡(jiǎn)單的例子出發(fā),考慮下面的代碼有什么問(wèn)題:

class OrderController extends Controller
{
    public function getUserOrders()
    {
        $orders= Order::where('user_id', '=', \Auth::user()->id)->get();
        return View::make('order.index', compact('orders'));
    }
}

這段代碼很簡(jiǎn)單,但我們要想測(cè)試這段代碼的話就一定會(huì)和實(shí)際的數(shù)據(jù)庫(kù)發(fā)生聯(lián)系。

也就是說(shuō), ORM和這個(gè)控制器有著緊耦合。如果不使用Eloquent ORM,不連接到實(shí)際數(shù)據(jù)庫(kù),我們就沒(méi)辦法運(yùn)行或者測(cè)試這段代碼。這段代碼同時(shí)也違背了“關(guān)注分離”這個(gè)軟件設(shè)計(jì)原則。

簡(jiǎn)單講:這個(gè)控制器知道的太多了。

控制器不需要去了解數(shù)據(jù)是從哪兒來(lái)的,只要知道如何訪問(wèn)就行。控制器也不需要知道這數(shù)據(jù)是從MySQL或哪兒來(lái)的,只需要知道這數(shù)據(jù)目前是可用的。

Separation Of Concerns 關(guān)注分離

Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class.

每個(gè)類(lèi)都應(yīng)該只有單一的職責(zé),并且職責(zé)里所有的東西都應(yīng)該由這個(gè)類(lèi)封裝

接下來(lái)我們定義一個(gè)接口,然后實(shí)現(xiàn)該接口

interface OrderRepositoryInterface 
{
    public function userOrders(User $user);
}
 
class OrderRepository implements OrderRepositoryInterface
{
    public function userOrders(User $user)
    {
        Order::where('user_id', '=', $user->id)->get();
    }
}

將接口的實(shí)現(xiàn)綁定到Laravel的服務(wù)容器中

App::singleton('OrderRepositoryInterface', 'OrderRespository');

然后我們將該接口的實(shí)現(xiàn)注入我們的控制器

class UserController extends Controller
{
    public function __construct(OrderRepositoryInterface $orderRepository)
    {
        $this->orders = $orderRespository;
    }
   
    public function getUserOrders()
    {
        $orders = $this->orders->userOrders();
        return View::make('order.index', compact('orders'));
    }
}

現(xiàn)在我們的控制器就完全和數(shù)據(jù)層面無(wú)關(guān)了。在這里我們的數(shù)據(jù)可能來(lái)自MySQL,MongoDB或者Redis。我們的控制器不知道也不需要知道他們的區(qū)別。這樣我們就可以獨(dú)立于數(shù)據(jù)層來(lái)測(cè)試Web層了,將來(lái)切換存儲(chǔ)實(shí)現(xiàn)也會(huì)很容易。

接口與團(tuán)隊(duì)開(kāi)發(fā)

當(dāng)你的團(tuán)隊(duì)在開(kāi)發(fā)大型應(yīng)用時(shí),不同的部分有著不同的開(kāi)發(fā)速度。

比如一個(gè)開(kāi)發(fā)人員在開(kāi)發(fā)數(shù)據(jù)層,另一個(gè)開(kāi)發(fā)人員在做控制器層。

寫(xiě)控制器的開(kāi)發(fā)者想測(cè)試他的控制器,不過(guò)數(shù)據(jù)層開(kāi)發(fā)較慢沒(méi)法同步測(cè)試。那如果兩個(gè)開(kāi)發(fā)者能先以interface的方式達(dá)成協(xié)議,后臺(tái)開(kāi)發(fā)的各種類(lèi)都遵循這種協(xié)議。

一旦建立了約定,就算約定還沒(méi)實(shí)現(xiàn),開(kāi)發(fā)者也可以為這接口寫(xiě)個(gè)“假”實(shí)現(xiàn)

class DummyOrderRepository implements OrderRepositoryInterface 
{
    public function userOrders(User $user)
    {
        return collect(['Order 1', 'Order 2', 'Order 3']);
    }
}

一旦假實(shí)現(xiàn)寫(xiě)好了,就可以被綁定到IoC容器里

App::singleton('OrderRepositoryInterface', 'DummyOrderRepository');

然后這個(gè)應(yīng)用的視圖就可以用假數(shù)據(jù)填充了。接下來(lái)一旦后臺(tái)開(kāi)發(fā)者寫(xiě)完了真正的實(shí)現(xiàn)代碼,比如叫RedisOrderRepository。

那么使用IoC容器切換接口實(shí)現(xiàn),應(yīng)用就可以輕易地切換到真正的實(shí)現(xiàn)上,整個(gè)應(yīng)用就會(huì)使用從Redis讀出來(lái)的數(shù)據(jù)了。

接口與測(cè)試

建立好接口約定后也更有利于我們?cè)跍y(cè)試時(shí)進(jìn)行Mock

public function testIndexActionBindsUsersFromRepository()
{    
    // Arrange...
    $repository = Mockery::mock('OrderRepositoryInterface');
    $repository->shouldReceive('userOrders')->once()->andReturn(['order1', 'order2]);
    App::instance('OrderRepositoryInterface', $repository);
    // Act...
    $response  = $this->action('GET', 'OrderController@getUserOrders');
         
    // Assert...
    $this->assertResponseOk();
    $this->assertViewHas('order', ['order1', 'order2']);
 }

總結(jié)

接口在程序設(shè)計(jì)階段非常有用,在設(shè)計(jì)階段與團(tuán)隊(duì)討論完成功能需要制定哪些接口,然后設(shè)計(jì)出每個(gè)接口具體要實(shí)現(xiàn)的方法,方法的入?yún)⒑头祷刂颠@些,每個(gè)人就可以按照接口的約定來(lái)開(kāi)發(fā)自己的模塊,遇到還沒(méi)實(shí)現(xiàn)的接口完全可以先定義接口的假實(shí)現(xiàn)等到真正的實(shí)現(xiàn)開(kāi)發(fā)完成后再進(jìn)行切換,這樣既降低了軟件程序結(jié)構(gòu)中上層對(duì)下層的耦合也能保證各部分的開(kāi)發(fā)進(jìn)度不會(huì)過(guò)度依賴(lài)其他部分的完成情況。

看完了這篇文章,相信你對(duì)“如何解析Laravel框架下的Contracts契約”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!

當(dāng)前名稱(chēng):如何解析Laravel框架下的Contracts契約-創(chuàng)新互聯(lián)
本文鏈接:http://muchs.cn/article8/dshiip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、外貿(mào)建站、小程序開(kāi)發(fā)、網(wǎng)站排名、電子商務(wù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都app開(kāi)發(fā)公司