首頁  >  文章  >  後端開發  >  利用Laravel Collections類別如何寫程式碼

利用Laravel Collections類別如何寫程式碼

不言
不言原創
2018-07-10 14:02:341316瀏覽

這篇文章主要介紹了關於利用Laravel Collections類別如何寫程式碼,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

Laravel 提供了一些超讚的組件,在我看來,它是目前所有Web 框架中提供元件支援最好的一個。它不僅提供了開箱即用的視圖(views)、身份認證(authentication)、會話(sessions)、快取(caching)、Eloquent、佇列(queues)、資料校驗(data validation)等元件。甚至還提供了開發工具(Valet 和 Homestead)。

但是,這個框架功能中最強大的一個特性常常被萌新們視而不見 - Collection(集合) 類別。在這篇文章,我們將探討如何使用集合提升編碼效率、程式碼的易讀行,並寫出更精簡的編碼。

預覽

最初接觸到使用集合的場景來自於研發人員使用 Eloquent 執行資料庫查詢,並從返回資料中使用 foreach 語句遍歷取得模型集合。

不過,初學者可能並沒有註意到,集合提供了超過 90 個以上的方法來操作底層資料。更棒的是幾乎所有的方法都支援鍊式操作,能夠讓你的程式碼讀起來就像一篇散文一樣。這使得你的程式碼更容易閱讀,無論是你還是其他使用者都是如此。

還沒進入正題?好吧,讓我們回顧一個簡單的程式碼片段,來看看我們如何使用集合編寫粗、快、猛的程式碼。

程式碼範例

讓我們建立一個真實的世界。假設我們查詢某些 API 介面並取得到如下以陣列保存的結果集:

<?php
// API 请求返回的结果
$data = [
    [&#39;first_name&#39; => '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 = [
    [&#39;name&#39; => '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/...。

感谢阅读,快乐编码!

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

关于Laravel的Eloquent ORM的解析

以上是利用Laravel Collections類別如何寫程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn