今日もヤバさをI/O中。

新卒1年目のエンジニアブログです。基本的に何かが足りません。

LaravelJPConference 当日スタッフとして人生初参加してきたので、振り返ってみた!

2/16 開催の LaravelJPConference に当日スタッフとして参加してきました! conference2019.laravel.jp

人生で初めて大規模イベントの(当日)スタッフ参加です…!当日は進行を担当していました!

もちろん LaravelJPConference も、今年初の開催なので初めての参加ですw

ですが、スタッフも含め参加者は334名だったそうです! 初開催なのにすごい!

当日の様子やセッションについては、以下を見ていただければと思います!

ハッシュタグ#laraveljpcon

Laravel JP Conference 2019 スライドまとめ - Qiita

振り返り(YKPWT)

YKPWT を使って個人的な振り返りをしました! cocoeyes02.hatenadiary.jp

以下やったこと、Keep、Problem、わかったこと、次やることになります!

やったこと

  • Laravel Track の準備
    • 機械設備の仕様把握(PCの規格に合わせた表示変更、マイク音量調節、照明調節、空調など)
    • 設営(スピーカー台設置と後方のパネルの組み立て)
  • Laravel Track の進行
    • スピーカー対応
      • お水配布
      • 疎通チェック(スピーカーのPC に合わせて)
    • 司会
      • アナウンス(開始前 / 開始後)
      • 質疑応答
    • タイムキーパー
    • 機械設備操作
    • 質疑応答時のマイク運び
  • Closing Talk 後の片付け
    • 現状復旧
    • ゴミ片付け

Keep

当日スタッフとして
  • 連絡を見逃さないよう、定期的に slack で当日スタッフ用のチャンネルを見た
  • 誰も機械整備の仕様について詳しく知らなかったので、分かったことを随時 slack や口頭にて共有した
  • アナウンス内容を変える対応が何回かあったが、なんとか対応することができた
  • 設営担当の撤去の手伝いなど、特に割り振られていない仕事も少しやった
  • 初開催の LaravelJPConference だったが、大成功かつ無事終えることができた
  • イベント運営の経験を経て、対応力やナレッジなど得られるものがあった
一参加者として
  • Laravel や PHP 問わず知見や知識が深まった
    • しかもタダで!(今回当日スタッフはチケット代無料でした )
  • PHPer 界隈の知人がめっちゃ増えた(フォロワーも40人ぐらい増えた)
  • 自分の OSS 活動が評価されたようにも感じたし、他の人への勧め方など知見を得られた(ういろうさん @nyamucoro ありがとうございます!)
  • お昼御飯がめっちゃおいしかった(ランチサポンサーの株式会社デザインワン・ジャパンさんありがとうございます!)

Problem

当日スタッフとして
  • 事前にアナウンスのテキストを用意されていたので、iPad で確認できるよう持ってきていたが当日に iPad が初期化されていたことに気がついた 😇
  • アナウンス担当時に緊張し過ぎて、その時やってたセッションの内容が頭に入ってこなかった
  • Track がほぼ満員だった時、空き席への案内などの対応が満足にできなかった(コアスタッフの人に任せてしまった)
  • 事前説明会で言われたタスク以上のことが、あまりできなかった気がする
  • スマホの電池残量がギリギリだった(イベント終了時に7%)
一参加者として
  • 恒例(?)のじゃんけんで決勝まで上がったが最後で負けた :kanashii:

分かったこと

当日スタッフとして
  • イベントスタッフ用のワークスペースを用意する時、緊急連絡用のチャンネルがあるとすぐ報告できるし安心
  • 持ち場が固定のスタッフは持ち場以外の状況等が把握できないので、小さな出来事でも slack で共有してあげると良い
  • 会場の設備について、まだ把握していないのであればできるだけ早く理解して共有することが吉
  • イベントスタッフの経験豊富な人がいると、いろいろと円滑に進む(ありがたい。。。)
  • やっぱり午前中にトラブルが起きがち(逆に午後は安定する)
  • 定期的に slack を見たり、ツイートしたらすぐにスマホの電池残量が減る
  • 司会やばいぐらい緊張する
  • 当日スタッフとして参加すると、普通の参加以上に界隈の人と仲良くなれるチャンスがある
一参加者として
  • php 系のカンファレンスでやるじゃんけん大会は、前でじゃんけんをする人がなんの手を出すか予告するので、途中まではその手に勝つ手を出す
    • どこで裏切られるかを推測するのが勝利の鍵
その他
  • 自分のイベントアドリブ対応力の低さが露呈した
    • ホスピタリティが足りない
    • 経験値が足りない
  • デブなので立ち仕事やると、すぐに足に疲れが出てくる

次やること

  • 他のイベントにも参加して、イベントスタッフ経験を積む
    • 今度は自分が進行を円滑に進められるような人へ…
    • 自社のイベントスタッフやコアスタッフになることにも繋がるはず
  • 小さなことでもいいので、なるべく slack に流して共有する
    • ただし、緊急時の内容は、他の共有内容で流れてしまうとまずいので専用のチャンネルで共有する
  • スマホ充電用のモバイルバッテリーを持っていく
    • 持ち歩くことになるので、できるだけ小型の方が良い
  • 前日に自分が持っていくデバイスが正常に起動しているか確認する
  • 次のじゃんけん大会こそ、どこで裏切られるかを推測して景品をゲットする!!!!
  • 運動しよう…

最後に

拙い個人的な振り返りの共有になってしまいましたが、全体を振り返ってみても当日スタッフ参加はとても得るものが多いです!!

他のPHPカンファレンスでも当日スタッフを募集していると思いますので、参加されたことが無い方は是非参加をお勧めします!!!

2019年に開催される全国のPHPカンファレンスのまとめ - Qiita

日報の形式は「YKPWT」がオススメ

TL;DR

  • 日報は「YKPWT (やったこと Keep Problem 分かったこと 次やること)」がオススメだよ
  • KPT より優れている点
    • 当日の業務内容を報告できるよ
    • 良かったことの深掘りができるよ
  • YWT より優れている点
    • 良かったことを書いた方が、自身の成長を実感できるよ
    • やったこと→分かったことをいきなり書くより、やったこと→ Keep Problem →分かったことの順で書いた方が、日報に慣れていない人でも書きやすいし説明しやすいよ
  • あくまで個人的なオススメだから、実際に使ってみて自分に合ってるか判断してね

YKPWT とは

YKPWT は

  • Y やったこと
  • K Keep
  • P Problem
  • W 分かったこと
  • T 次やること

の略です。役割としては

  • Y → その日の業務、事実報告
  • K・P → 所感をまとめる
  • W 分かったこと → 所感から内省、分析
  • T 次やること → 得られた学びを行動につなげる

という構成になります。少し項目が多い感じは否めないですね。

YKPWT は内容から見てわかる通り YWT と KPT を混合させたフレームワークです。ただ混ぜただけのように思われるかもしれませんが、日報に関しては YWT や KPT よりも YKPWT の方が良いと個人的に感じます。

ちなみに YWT と KPT については、以下の記事でよくまとめられています。

yoshitsugumi.hatenablog.com

KPT より優れている点

その日の業務内容が書ける

日報は個人の振り返りだけでなく、報告先(上司やメンターなど)へその日何をやったのか報告する意味もあります。

KPT で振り返るとその日の業務内容を書く枠がなく、その日何をやったのか報告することができません。

良かったことの深掘りができる

日報に限らず KPT でありがちなことですが、Problem と Problem を解決する Try に意識を向けすぎて、 Keep の深堀りが足りないことがあります。「じゃあ良かったことはそのまま続けていただいて…」で終わってしまう例を、何度も見たことがあります。

Keep も深堀り次第では型化のキッカケを見つけたり、良かったことを見つけるスキルの向上になったりします。

YWT より優れている点

自分自身を褒める要素がある

日報のモチベーションの観点から、自身の成長を感じることは大事だと思います。

YWT は振り返りのフレームワークとしては優秀ですが、学びを得ることに特化しすぎている気がします。もちろん学びを得ることは、自身の成長に繋がる大事な点です。ですが学びを得ることだけでなく、その日の良かったことを確認するだけでも自身の成長を感じることが出来ます。

  • 他の人には当たり前のことでも、自分が今までできなかったことが出来た!
  • 学びになるようなことじゃないけど、いい感じの動きができた!

これらを学びにならないからといって、書かないのはもったいないです。

Y→W の難しさを緩和している

個人的に YWT で一番難しいことは、やったことから分かったことを考えることだと思っています。やったことから分かったことを加筆するとき、よく起きやすいのが…

  • 時間がかかっている、気がついたら 30 分近くも経っていた
  • やったことからどういう背景で分かったことが出てきたのか、報告先にうまく説明できない・伝わらない

だと思っています。

これはやったことから、分かったこと(≒ 学び)をいきなり思いつこうとするのが難しいからだと感じます。

YKPWT では、やったことと分かったことの間に「やったことの結果」を書く作業を追加しました。それは Keep と Problem です。

まずは良かった点と反省点を整理して、次に良かった点と反省点から学びを得るフローになっています。良かった点と反省点を出すことはそこまで敷居が高くないことと、自然と分かったことの理由づけができるので、質の高い Y→W を書くことが出来ます。

やったこと

管理画面の E2E テスト(nightmareJS)作成 6.5h

Keep

Problem

  • 間違って git reset をしてしまい、3時間分の作業が消えてしまった
  • nightmareJSで、ファイルのアップロードができなかった

わかったこと

  • CUI 以上に、GUI で全ファイルの git reset は簡単に出来てしまう
  • Vue インスタンスのプロパティの値を変えないと、nightmareJS を使って input の value を変えてもテストできない
  • nightmareJS 単体では、テスト中にファイルのアップロードができない
  • nightmareJS で悩んでいることを、nightmareJS の処理で解決する必要はない

次やること

  • GUI 上で git reset するときは、全ファイルではなく1ファイルずつ git reset する
  • vue 周りのテストをするときは、なるべく vue でテスト用のデータを用意する methods を作成する
  • ライブラリである nightmare-upload を使ってみる

最後に

この YKPWT は個人的なオススメです。人や環境によっては別のやり方のほうがあっているかもしれません。

ですが、日報をどう書けば良いか悩んでいる人は、まずこの YKPWT を試してみましょう。それから自分のやり方にあっているか考え、改良するか別のやり方にするか検討してはいかがでしょうか。

「メッセージが少なくとも 1 回配信されること」にまつわる SQS 使う上での注意点

この記事は Willgate Advent Calendar 2018 - Qiita の 9 日目の記事です。

以前弊社のブログで、 Amazon Simple Queue Service (以下 SQS と呼ぶ) を導入した例についての記事を書きました。

tech.willgate.co.jp

当時は「メッセージが少なくとも 1 回配信されることしか保証されていない」ということがイマイチピンときていなかったため、調べながら導入・実装に当たっていました。

今回は「メッセージが少なくとも 1 回配信されることしか保証されていない」ことで、実装時に何を気をつけなければいけないか分かったことをまとめます。

保証されていることは「メッセージが少なくとも 1 回配信されること」のみ

まず前提として、SQSは「メッセージが少なくとも 1 回配信されること」しか保証されていません。そのため以下のようなことが起こります。

  • 同じメッセージを重複して取得した
  • 別のシステムからA, B, C, Dという順番でメッセージを送信したが、受信するときにはB, D, A, Cという順番で取得した。
  • SQSにメッセージが存在してるにも関わらず、空のレスポンスが返ってきた
  • 削除済みのメッセージを取得した

一つずつ見ていきましょう。

同じメッセージを重複して取得した

「少なくとも 1 回配信」ということなので、同じメッセージを複数取得することがあります。

対処法としては、「メッセージ ID を見て、重複していた時には重複を消す」といった処理の追加が挙げられます。

別のシステムからA, B, C, Dという順番でメッセージを送信したが、受信するときにはB, D, A, Cという順番で取得した

SQS にはスタンダードキューと FIFO キューというものが存在します。この現象は SQS のスタンダートキューで起きる現象です。

「キューは普通、先入先出し(FIFO)じゃないの?」というツッコミが来そうですが…残念ながら、スタンダートキューではメッセージ送信の順番は保証されていません。もし、メッセージ送信の順番を保持してほしいならば、 FIFO キューを使いましょう。

2018/12/25 現在、東京リージョンでも FIFO キューを使用することができます。 aws.amazon.com

FIFO キューを使用しないならば、パッと思いつく限りだと「メッセージに送信時間を含ませ、メッセージをキューから受け取った後に送信時間でソートする」でしょうか?

確実にできる保証はないので、出来れば FIFO キューを使う方が良いかなと思います。

SQS にメッセージが存在してるにも関わらず、空のレスポンスが返ってくる

こちらバグではなく、どうやら仕様のようです。

docs.aws.amazon.com

Amazon SQS は分散システムであるため、キューにあるメッセージが非常に少ない場合は、受信したリクエストに対して空のレスポンスを表示する場合があります。

対策としては ReceiveMessageWaitTimeSeconds を1秒以上に設定する、いわゆるロングポーリングを設定することが挙げられます。

例えば、ReceiveMessageWaitTimeSeconds を10秒に設定すると、メッセージを取得するまで最大10秒待つことになります。10秒の間にメッセージを取得できなかった時は空のレスポンスが帰ってきます。

詳しくはこちらに書いてあります。

docs.aws.amazon.com

削除済みのメッセージを取得した

こちらもバグではなく、仕様だそうです。

docs.aws.amazon.com

この場合、使用できないサーバーではメッセージのコピーが削除されず、メッセージの受信時に、そのメッセージコピーをもう一度受け取る場合があります。

どういった目的で SQS を使用するかによりますが、既にそのメッセージを使った処理が行われているか判定するロジックが必要になります。

例えば、メッセージに DB へ登録するための ID が挿入されているとします。その時は「保存先の DB を参照し、既に ID が登録されていた時にはメッセージを削除する」といった処理が必要になってきます。

まとめ

最初は SQS 特有の注意点が多くて、戸惑うことや面倒だと思うことも多いと思います。 それでも享受できるメリットの方がはるかに大きいサービスだと思いますので、是非プロダクトにてご活用ください!

ソースコードリーディングはいいぞ

この記事は Willgate Advent Calendar 2018 - Qiita 2 日目の記事です。

皆さんソースコードリーディングしていますか?お恥ずかしながら、僕は最近読むようになりました!

実際やってみると、ソースコードリーディングによって得るものが多いことを知り、今では読書感覚でフレームワークやライブラリのソースコードを読むことも…

今回は、ソースコードリーディングによって何が得られるのかについて書きたいと思います!

結論:ソースコードリーディングはアウトプットするチャンスの塊

何故ソースコードリーディングが良いのか。それは、ソースコードリーディングがアウトプットに繋がりやすいからだと僕は思います。

僕自身、アウトプットのきっかけとなっているのがソースコードリーディングによるものが一番多いです。

チャンスその1:業務で活かせる

ライブラリやフレームワークなどのソースコードを読んでいくと、細かい挙動まで処理を把握することができます。

すると、「思わぬ挙動によってバグが発生してしまった!」なんていうことを防ぐことができます。どんどん読み進んでいけば、「あのライブラリ・フレームワークについてならこの人に聞くと良いよ」という評価を得ることもできるかも…!

特にフレームワークソースコードを読むと、徐々に「良い設計とはなんなのか?」ということも学べるので、設計の勉強にもなります。

チャンスその2:ブログ記事のネタになる

ソースコードを読んだ結果わかったことをブログに書くだけで、立派なアウトプットの 1 つとなります。

僕も Laravel の Collection メソッドについて記事を書いていますが、1 メソッドだけでもなかなかの分量になります。

参考; cocoeyes02.hatenadiary.jp

チャンスその3:OSS に参加できる

ソースコードを読み進めていくと、「あれ? 何故ここでは、こんな処理が無いのだろう?」「あれ、ここにエラーハンドリングが無いのは何故だろう?」など疑問点が出てくることがあります。それは、思想によるものだったり、単なる考慮漏れだったり…様々な理由があります。

そんな時、もちろん身近で詳しい人に聞くのもありですが、issue や pull request を立てるというのも手です!

僕自身もソースコードを読んでいて、疑問に思ったことや思ったことを何回か issue に立てています。

github.com

github.com

issue や pull request を立てると GitHub では 1 contributionとして扱われるので、commit 以外でもcontributionの草を生やしていくことができます。

最後に

今回あげたアウトプットチャンスは、あくまで一例です。他にも LT 会やセッションの登壇ネタになったり、読み進めていけば執筆のチャンス…なんていうこともあるかもしれません。

「最近アウトプットしていないなあ…」と悩んでいる人は、ぜひソースコードリーディングをお勧めします!

初めてのE2E テスト( nightmare )でハマったことと解決策

この記事は Willgate Advent Calendar 2018 - Qiita の23日目の記事です。素で忘れていたため、2日遅れの記事となってしまいました…反省ですね。

皆さんは普段から E2E テスト書いていますか? 僕は、業務で初めて nightmare を使った E2E テストを書きました。

今後 E2E テストを書く上で忘れないよう、ハマったことと解決策をいくつかピックアップして書きます!

なお、今回のE2E テストというのは Web ブラウザの E2E テストを指すものとします。

「 input type="date" で上手く日付を入力できない」

.type("input[name='date']", "2018/12/25") を入力すると… f:id:cocoeyes02:20181225180521g:plain

年が6桁まで入力され、"201812/02/05"という入力になってしまいました。

input type="date" は約 27 万年まで入力することができる

input type="date" は、約 27 万年まで入力することができます。

何故そうなるかは、こちらのサイトに詳しく書いてあります。 unarist.hatenablog.com

Date 型の最大値が約 27 万なので、約 27 万年まで入力できてしまうということですね。

max="9999-12-31" を 指定する

解決策も上記の参考サイトに書いてありました。

max="9999-12-31" を 指定することによって、年が 4 桁までしか入力できなくなり nightmare でもスムーズに入力できるようになります。

E2E テストでなくても、年を 6 桁で使用することは通常ないと思いますので max 属性の指定をお勧めします。

「window.confirm() が表示されない」

js で window.confirm() によるダイアログの確認はよく使用されているかと思いますが、nightmare のテスト中では window.confirm() が表示されません。

デフォルトで表示できないようになっている

Nightmare の Readme に、こんな一文が書いてあります。

Nightmare disables window.confirm from popping up by default, (略)

github.com

そもそもデフォルトでは、表示できないようになっているんですね。

デフォルトというからには、どこか設定を変えれば表示されるのでしょうか?(残念ながら、僕は見つけることができませんでした)

window.confirm() の処理を書き換える js ファイルを読み込む

今回の場合は .inject() を使用して、window.confirm() のダイアログで OK を押したように振る舞うメソッドを用意しました。以下は使用例です。

// hoge.js
clickSubmit = () => {
    var url = 'https://hoge.com/huga/create';
    $('.piyo-form').attr('action', url);
    $('.piyo-form').submit();
}
// (略)
.inject('js', 'hoge.js')
.click('.submit-btn') 
.evaluate(() => {
    clickSubmit();
    return true;
})
// (略)

.inject() を使うと、テスト中限定で css や js ファイルを読み込むことができます。

今回は window.confirm() の話でしたが、window.alert() や window.prompt() でも同じ方法で対処することができます。

E2E テストで悩んでいることを、E2E テストツール単体で全て解決する必要はない

今回対処した方法は、max 属性の設定だったり、メソッドの追加だったり…。

nightmare を使った tips というよりは、Web ブラウザでの E2E テスト全般の tips というような感じになったと感じます。

今後も E2E テストで悩むことがあったら、nightmare を使った解決策だけに限らず、広い視野で解決策を探りたいと思います。

Eloquent ORM vs Query Builder (+ DB Facade )

Laravel で データ取得の方法と述べると、Eloquent ORM と Query Builder (+ DB Facade )の2つが上げられると思います。

今回は、二つのメリットとデメリットを見比べつつ、どういう状況で使えば良いのかを書きます。

Eloquent ORM

Eloquent ORMは、Laravel が提供している O/R マッパです。

ActiveRecord ライクにデータの取得ができます。

メリット

O/R マッパ のメリットを享受できる

  • SQL という別の言語を、アプリケーション( Laravel )に介入せず済む
  • テーブル同士の関係性を定義できる
  • 再利用性や拡張性が高い

など...

今回は、O/R マッパについて述べるわけではないので、詳しくは書きません。

色々柔軟に設定できる

何ができるかは、ドキュメントを読めば一目瞭然です。

Eloquent:利用の開始 5.7 Laravel

  • 独自のグローバルスコープ適応による、独自メソッド実装
  • 特定のイベントをフックにした処理の実行(いわゆるObserverパターン)

拡張性に優れた機能を、有していると言えます

デメリット

O/R マッパ のデメリットを享受する

  • SQL が書けなくても、データ取得ができる
  • ぱっと見、どういうクエリを発行しているのかわからない
  • Eloquent O/R マッパは ActiveRecord パターンで実装されているので、ActiveRecord パターンを覚える必要がある

など...

こちらも、O/R マッパについて述べるわけではないので、詳しくは書きません。

ですが、「ぱっと見、どういうクエリを発行しているのかわからない」は、次のデメリットで関連して触れることになります。

特定のメソッドを使うと、サブクエリを使って実行する

例えば has や whereHas では、exists を使ったサブクエリを実行します。

参考: qiita.com

当然ながら、サブクエリを実行するわけなので、クエリの実行時間が長いことになります。中には join 句を使えばサブクエリにしなくて良いような内容も、サブクエリで実行します。

このデメリットは、O/R マッパのデメリットで挙げた「ぱっと見、どういうクエリを発行しているのかわからない」が躊躇に現れていると思います。

どういう時に使えば良いか

  • パフォーマンスよりも安全性を取りたい
  • 確実に、リレーションに沿ったデータ取得をしたい
  • 特定の状況下での条件付けや、処理の実行を実装したい

Query Builder (+ DB Facade )

Laravel が提供しているクエリを生成するためのメソッド群。

SQL ライクにクエリを書くことができる( Query Builder )他、SQL をそのまま書いて実行する( DB Facade )こともできます。

メリット

Eloquent と比べて高速

join 句を使ったクエリを書けば、Eloquent でサブクエリを使って取得している処理よりも早くなります。

また、以下 URL では、同じ実行結果でも、Eloquent O/R マッパ に比べて Query Builder (+ DB Facade )の方が早いことを主張しています。

参考:https://www.youtube.com/watch?v=3TJfR1Ta4GU

どういうクエリを実行しているのかはわかりやすい

SQL 文と書き方に大きな差はないので、なんのクエリが発行されているかは非常にわかりやすいです。

SQL を書けさえすれば学習コストは低い

どんなメソッドがあるかは覚える必要があるものの、それ以外に必要なことは、SQL 文を書けることだけです。

デメリット

自力で考慮しなければいけない点がある

  • テーブル同士の結合は自身で行う必要があるため、リレーションを正しく把握して反映する必要がある
  • 論理削除の条件は、自分で条件指定する
  • そもそも SQL 文で間違った書き方を書いてはいけない

など...

これらを正しく考慮できていないと、意図しないデータを取得してしまう場合があります。

また、個人開発ではなくチームによる開発であれば、レビュアーが上記の点を考慮してコードレビューしなければなりません。

どういう時に使えば良いか

  • 複雑な条件や大量のデータを扱うので、パフォーマンスを求めたい(検索画面、一覧画面とか)
  • 複雑な条件のクエリを、発行したい

allメソッド Collectionメソッドソースコードリーディング100本ノック1本目

メソッド概要

コレクション 5.6 Laravel

allメソッドはコレクションの裏の配列表現を返します。

<?php

collect([1, 2, 3])->all();

// [1, 2, 3]

裏の配列表現なんて仰々しい事を言っていますが、単純にコレクションの中身を配列で返すだけのメソッドです。

ソースコードリーディング

allメソッド

では早速、ソースコードリーディングをやって行きましょう。

<?php

/**
 * Get all of the items in the collection.
 *
 * @return array
 */
public function all()
{
    return $this->items;
}

itemsプロパティの値を取得する。以上。第3部完ッ!!

…これだけだと切なすぎるので、items プロパティに何の値が代入されているのか construct を見ましょう。

Collectionのconstruct

<?php

/**
 * Create a new collection.
 *
 * @param  mixed  $items
 * @return void
 */
public function __construct($items = [])
{
    $this->items = $this->getArrayableItems($items);
}

$items を引数にして、getArrayableItems メソッドを呼び出しています。

とりあえず getArrayableItems メソッドの中身を覗きましょう。

getArrayableItemsメソッド

<?php

/**
 * Results array of items from Collection or Arrayable.
 *
 * @param  mixed  $items
 * @return array
 */
protected function getArrayableItems($items)
{
    if (is_array($items)) {
        return $items;
    } elseif ($items instanceof self) {
        return $items->all();
    } elseif ($items instanceof Arrayable) {
        return $items->toArray();
    } elseif ($items instanceof Jsonable) {
        return json_decode($items->toJson(), true);
    } elseif ($items instanceof JsonSerializable) {
        return $items->jsonSerialize();
    } elseif ($items instanceof Traversable) {
        return iterator_to_array($items);
    }

    return (array) $items;
}

Collection や Arrayable から配列を作成するメソッドのようです。 条件式が複数あるので、一つずつ何をしているのか処理を追っていきましょう。

条件式:is_array($items)

<?php

if (is_array($items)) {
    return $items;
}

$items が配列だったら、そのまま $items を返します。 配列なら、わざわざ変換する必要はありませんからね。

条件式:$items instanceof self

<?php

} elseif ($items instanceof self) {
    return $items->all();
}

$items のインスタンスが self(Collection) だったら、all メソッドを実行しその返り値を返します。

ここで、ちょっとした例を出してみます。

<?php

// IN: $items = new Collection([1])
$this->items = $this->getArrayableItems(new Collection([1]));
$this->items = new Collection([1])->all();
$this->items = $this->getArrayableItems([1]);
$this->items = [1];


// IN: $items = new Collection(new Collection([1]))
$this->items = $this->getArrayableItems(new Collection(new Collection([1])));
$this->items = new Collection(new Collection([1]))->all();
$this->items = $this->getArrayableItems(new Collection([1]));
$this->items = new Collection([1])->all();
$this->items = $this->getArrayableItems([1]);
$this->items = [1];

つまり、2次元の Collection でも3次元の Collection でも、1次元の Collection にしてくれます。以下が実際に実行した結果です。

<?php

dd(new Collection(new Collection([1])));
Collection {#450 ▼
  #items: array:1 [▼
    0 => 1
  ]
}

dd(new Collection(new Collection(new Collection([1]))));
Collection {#450 ▼
  #items: array:1 [▼
    0 => 1
  ]
}

条件式:$items instanceof Arrayable

<?php

} elseif ($items instanceof Arrayable) {
    return $items->toArray();
} 

$items のインスタンスが Arrayable だったら、toArray メソッドを実行しその返り値を返します。

Arrayable

Arrayable は、Laravel が提供しているinterfaceです。

<?php

namespace Illuminate\Contracts\Support;

interface Arrayable
{
    /**
     * Get the instance as an array.
     *
     * @return array
     */
    public function toArray();
}

toArray メソッドのみが定義されています。

別クラスに Arrayable を implements した上で、変換処理を記述した toArray メソッドを実装する、という使い方でしょうか。

配列じゃない別クラスでもtoArrayメソッドを使うことで、配列へ変換できるようにするため用意されている interface のようですね。

条件式:$items instanceof Jsonable

<?php

} elseif ($items instanceof Jsonable) {
    return json_decode($items->toJson(), true);
}

$items のインスタンスが Jsonable だったら、json_decode 関数を実行しその返り値を返します。

json_decode 関数の第二引数が true なので、$items は配列にデコードされます。

Jsonable

jsonable は、 Laravel が提供している interface です。

<?php

namespace Illuminate\Contracts\Support;

interface Jsonable
{
    /**
     * Convert the object to its JSON representation.
     *
     * @param  int  $options
     * @return string
     */
    public function toJson($options = 0);
}

toJson メソッドのみが定義されています。

こちらも別クラスに Jsonable を implements した上で、変換処理を記述した toJson メソッドを実装する、という使い方でしょうか。

json 形式じゃない別クラスでも toJson メソッドを使うことで、json 形式へ変換できるようにするため用意されている interface のようですね。

Arrayable とちょっとだけ似ている気がします。

条件式:$items instanceof JsonSerializable

<?php

} elseif ($items instanceof JsonSerializable) {
    return $items->jsonSerialize();
}

$items のインスタンスが JsonSerializable だったら、jsonSerialize メソッドを実行しその返り値を返します。

JsonSerializable

JsonSerializable は php が提供している interface です。 ( PHP: JsonSerializable - Manual )

<?php

/**
 * Objects implementing JsonSerializable
 * can customize their JSON representation when encoded with
 * <b>json_encode</b>.
 * @link http://php.net/manual/en/class.jsonserializable.php
 */
interface JsonSerializable  {

    /**
    * Specify data which should be serialized to JSON
    * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
    * @return mixed data which can be serialized by <b>json_encode</b>,
    * which is a value of any type other than a resource.
    * @since 5.4.0
    */
    public function jsonSerialize ();

}

jsonSerialize 関数のみが定義されています。( PHP: JsonSerializable::jsonSerialize - Manual )

別クラスに JsonSerializable を implements した上で、 jsonSerialize 関数を定義し、配列への変換処理を記述する。

使い方自体は Arrayable や Jsonable と一緒のようですね。

条件式:$items instanceof Traversable

<?php

} elseif ($items instanceof Traversable) {
    return iterator_to_array($items);
}

$items のインスタンスが Traversable だったら、iterator_to_array 関数を実行しその返り値を返します。

Traversable

Traversable は php が提供している interface です。( PHP: Traversable - Manual )

<?php

/**
 * @link https://wiki.php.net/rfc/iterable
 */
interface iterable {}

/**
 * Interface to detect if a class is traversable using &foreach;.
 * @link http://php.net/manual/en/class.traversable.php
 */
interface Traversable extends iterable {
}

iterable を継承していることと( PHP: rfc:iterable )、コメントの内容からforeachで繰り返し可能なクラスに実装するようです。

抽象 interface なので Traversable 単体では動きません。ですので、Traversable を継承している Iterator もしくは IteratorAggregate に、foreachをした時の細かい挙動を実装する必要があります。

その上で、iterator_to_array を使って配列へと変換していきます。( PHP: iterator_to_array - Manual )

<?php

/**
 * Copy the iterator into an array
 * @link http://php.net/manual/en/function.iterator-to-array.php
 * @param Traversable $iterator <p>
 * The iterator being copied.
 * </p>
 * @param bool $use_keys [optional] <p>
 * Whether to use the iterator element keys as index.
 * </p>
 * @return array An array containing the elements of the iterator.
 * @since 5.1.0
 */
function iterator_to_array ($iterator, $use_keys = true) {}

条件式:上記に当てはまらないとき

<?php

return (array) $items;

上記に当てはまらなかった時は、配列に漢のキャストをします。

最後に

と言うわけで、Collection メソッドソースコードリーディング100本ノック1本目が終わりました!

all メソッドの内容だけでは寂しいと深掘っていったら、 Laravel どころか php の内部実装まで触れてしまいました。

次は avg と average メソッドです!

マサカリや「ここちげえぞ!!!」と言う怒りのコメントまで、お待ちしております!