這篇文章主要介紹了關於利用Laravel Collections類如何編寫代碼,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
Laravel 提供了一些超贊的組件,在我看來,它是目前所有 Web 架構中提供組件支援最好的一個。它不僅提供了開箱即用的視圖(views)、身份認證(authentication)、會話(sessions)、緩衝(caching)、Eloquent、隊列(queues)、資料校正(data validation)等組件。甚至還提供了開發工具(Valet 和 Homestead)。
但是,這個架構功能中最強大的一個特性常常被萌新們視而不見 - Collection(集合) 類。在這篇文章,我們將探尋如何使用集合提升編碼效率、代碼的易讀行,及編寫出更精簡的編碼。
預覽
最初接觸到使用集合的情境來自於研發人員使用 Eloquent 執行資料庫查詢,並從返回資料中使用 foreach 語句遍曆擷取模型集合。
不過,初學者可能並沒有注意到,集合提供了超過 90 個以上的方法來操作底層資料。更妙的是幾乎所有的方法都支援鏈式操作,能夠讓你的代碼讀起來就像一篇散文一樣。這樣使得你的代碼更易閱讀,無論是你還是其他使用者都是如此。
還沒有進入正題?好吧,讓我們回顧一個簡單的程式碼片段,來看看我們如何使用集合編寫粗、快、猛的代碼吧。
程式碼範例
讓我們構建一個真實的世界。假設我們查詢某些 API 介面並擷取到如下以數組儲存的結果集:
<?php// API 請求返回的結果$data = [ ['first_name' => 'John', 'last_name' => 'Doe', 'age' => 'twenties'], ['first_name' => 'Fred', 'last_name' => 'Ali', 'age' => 'thirties'], ['first_name' => 'Alex', 'last_name' => 'Cho', 'age' => 'thirties'],];
我們看到數組包含名字(first name)、姓氏(last name) 和年齡(age)範圍。現在,我們假設從屬記錄中擷取一名 年齡(age) 為 30 歲(thirties) 的使用者,然後依據 姓氏(last name) 進行 排序(sort)。最後,我們還希望返回的結果為 一個字串(single string),這樣每個使用者獨佔 一行(new line)。最後,我們還希望返回的結果為
這個需求看起來不難實現,現在讓我們看看使用 PHP 如何?這一功能:
// 依據姓氏排序usort($data, function ($item1, $item2) { return $item1['last_name'] <=> $item2['last_name'];});// 依據年齡範圍分組$new_data = [];foreach ($data as $key => $item) { $new_data[$item['age']][$key] = $item;}ksort($new_data, SORT_NUMERIC);// 從年齡為 30 歲組裡擷取使用者全名$result = array_map(function($item) { return $item['first_name'].' '.$item['last_name'];}, $new_data['thirties']);// 將數群組轉換為字串並以行分隔字元分隔$final = implode("\n", $result);// 譯註:原文是 $final = implode($results, "\n"); implode函數接收兩種順序的參數,為了保持與文檔一致所以我這邊做了調整。
我們的實現代碼超過 20 行,並且很不優雅。移除掉注釋及換行相關代碼,這段代碼會變得難以閱讀。再者,我們還需要藉助臨時變數以及 PHP 中內建的不友好的 sort 方法。
現在,讓我們看下藉助 Collection 類實現起來是多麼簡單吧:
collection($data)->where('age', 'thirties') ->sortBy('last_name') ->map(function($item){ return $item['first_name'].' '.$item['last_name']; }) ->implode("\n");
哇哦!我們的代碼從 20 行變成了 6 行。現在的代碼不僅順暢不少,並且在方法實現時無需藉助注釋告訴我們它們在處理什麼問題。
不過,還存在一個問題阻止我們的代碼不如完美階段... 就是用於比較 first name 和 last name 的 map 方法。坦白說,這真的不是什麼大問題,但是它為我們探索 macro(宏) 概念提供了動力。
擴充集合(Extending Collections)
Collection 類,同其它 Laravel 組件一樣,支援宏(macroable),就是說你可以給它添加方法隨後使用。
提示: 如果你希望新方法隨處可用,你應該將它們添加到服務提供中。我喜歡建立一個
MacroServiceProvider 實先這個功能,對於你來說隨你喜歡就好。
讓我們添加一個方法它會串連由數組提供的任意數量的欄位並返回字串結果:
Collection::macro('toConcatenatedString', function ($fields = [], $separator = ' ') { return $this->map(function($item) use ($fields, $separator) { return implode($separator, array_map(function ($el) use ($item) { return $item[$el]; }, $fields) ); })->implode("\n");});
添加完這個方法後,我們的代碼基本上就完美了:
collect($data)->where('age', 'thirties') ->sortBy('last_name') ->toConcatenatedString(['first_name', 'last_name']);
我們的代碼從混亂的 20 多行精簡到了 3 行,代碼乾淨整潔功能清晰任何人都可以立馬理解。
又一個樣本
現在讓我們看下第二個樣本,假設我們一個使用者列表,我們需要基於角色(role)過濾出來,然後進一步如果他們的註冊時間為 5 年或以上且 last name 以字母 A-M 開始的僅擷取第一個使用者。
資料類似如下:
<?php// API 請求返回的結果$users = [ ['name' => 'John Doe', 'role' => 'vip', 'years' => 7], ['name' => 'Fred Ali', 'role' => 'vip', 'years' => 3], ['name' => 'Alex Cho', 'role' => 'user', 'years' => 9],];
如果我們使用的是 PHP 實現,我們的代碼看下來如下:
$subset = [];foreach ($users as $user) { if ($user['role'] === 'vip' && $user['years'] >= 5) { if (preg_match('/\s[A-Z]/', $user['name'])) { $subset[] = $user; } }}return reset($subset)
注意: 你可以將第二個
if 語句移至第一個裡面,但是我個人喜歡在單個 if 語句中使用不超過兩個條件陳述式,因為我認為超過 2 個條件陳述式回事代碼難以閱讀。
這段代碼不至於太糟糕,但是我們依然需要使用臨時變數,我們還需要使用 reset 函數將指標重設到第一個使用者。我們的代碼還有四層縮排,這使得代碼解析變得更有挑戰性。
相反,我們來看看集合是如何處理這個問題的:
collect($users)->where('role', 'vip') ->map(function($user) { return preg_match('/\s[A-Z]/', $user['name']); }) ->firstWhere('years', '>=', '5');
我們將代碼簡化到了之前的一般左右,每一步過濾處理清晰明了,並且我們不需要引入臨時變數。
遺憾的是目前集合還不支援正則匹配,所以我們使用 map 方法,不過我們可以為這個功能建立一個宏:
Collection::macro('whereRegex', function($expression, $field) { return $this->map(function ($item) use ($expression, $field) { return preg_match($expression, $item[$field]); })});
得益於宏方法,我們的代碼現在看起來如下:
collect($users) -> where('role', 'vip') -> whereRegex('/\s[A-Z]/', 'name') -> firstWhere('years', '>=', 5);
注意: 為了簡單起見,我們的紅僅僅適用於數組集合。如果你計劃讓它們可以在 Eloquent 集合上使用,你需要在此情境下做相應的代碼處理才行。
不同的視角
我們可以繼續列出無數的樣本,但仍然無法涵蓋所有可用的集合方法,並且這從來都不是本文的真正目的。
需要注意的是,通過使用 Collection 類,您不僅可以獲得一個方法庫來簡化編程工作,還可以選擇一種從根本上改善代碼的方法。
你會情不自禁的將你的代碼結構從代碼塊重構簡化成一行,同時減少代碼的縮排,臨時變數的使用和技巧性方法,另外你還可以使用鏈式編程方法,這讓你的代碼更加便於閱讀和解析,此外最重要的是減少了編碼工作!
查看官方文檔擷取更多這個迷人的類庫的使用細節:https://laravel.com/docs/coll...
提示: 你還可以擷取這個 Collection 類獨立安裝包,在使用非 laravel 項目是會非常有協助。感謝 Tighten Co 團隊做出的努力 https://github.com/tightenco/...。
感謝閱讀,快樂編碼!
以上就是本文的全部內容,希望對大家的學習有所協助,更多相關內容請關注topic.alibabacloud.com!