ビジネスとIT活用に役立つブログBlog


「Functional PHP」PHPのための関数型プリミティブライブラリを触ってみた

この記事をシェアする:
今回はFunctional PHPの学習用テストコードを書いてFunctional PHPを触ってみたいと思います。

1. Functional PHPとは

PHPのための関数型プリミティブの機能セットです。
2020年11月現在ではGitHubのスターを1.7k稼いでいるライブラリです。

2. 開発環境(Docker)の準備

筆者の環境

  • Windows 10 Home
  • WSL2
  • Docker Desktop for Windows

検証ではPHP7.4.11を使用します。

PHPのDockerfileの作成

まずは Dockerfileをプロジェクト直下のphpディレクトリに配置します。

php/Dockerfile

後でFunctional PHPをインストールする時に使用するので composer:2.0.3 もここでインストールします。

docker-compose.ymlの作成

 docker-compose.yml をプロジェクト直下に作成します。

docker-compose.yml

Dockerイメージのビルド

Dockerイメージをビルドします。

ビルドしたDockerイメージでPHP7.4.11の実行を確認します。

DockerイメージのビルドとPHP7.4.11の実行環境の動作確認ができました。

ここまでのディレクトリ構成

3. Functional PHPのインストール

Functional PHPを Packagist からcomposerでインストールしていきます。

以下のコマンドでインストールします。

 docker-compose コマンドの実行オプションで -u $(id -u):$(id -g) を指定する事でrootユーザーでvendorディレクトリが作られることを回避します。

学習テスト用にPHPUnitもインストールします。

 composer.json にautoload-devの設定を追加します。

composer.json

phpunit.xml.distも追加しておきます。

phpunit.xml.dist

ここまでのディレクトリ構成

Functional PHPを触ってみる準備が完了しました。

4. map コレクションの各要素をマッピング

mapはコレクションの各要素にコールバック関数を適用して結果を返す関数です。

ドキュメントとテストコードを見ながらmapを使ってみます。

以下はコレクションの各要素にプラス1する関数を適用するテストコードです。

tests/MapTest.php

実行結果

1から10の配列やイテレータの各要素にコールバック関数が適用された結果が取得できました。

5. select (filter) コールバックを使用してリスト内の各要素をフィルタリング

selectはコレクションの各要素にコールバック関数を適用してフィルタリングした結果を返す関数です。 JavaScriptの配列型オブジェクトAPIのfilterと同じ用途ですね。

Functional PHPにもエイリアスとしてfilter関数が定義されています。

こちらもドキュメントとテストコードを見ながらfilterを使ってみます。

以下はコレクションの各要素で偶数の数値を抽出するテストコードです。

tests/SelectTest.php

実行結果

テストが通りませんでした。
結果を見るとコレクションのインデックスを維持した結果を返すようです。

テストコードを修正して再度テストを実行してみます。

再実行結果

テストが通るようになりました。

JavaScriptのfilter関数がお馴染みの方はselect関数のエイリアスとしてfilter関数も定義されていますので好みで使う関数を選べるようになっています。

6. 実行速度の計測

どのくらい実行速度に差が出るか比較してみます。

1から100万までの数値が入った配列の各要素を1加算する処理の実行時間を簡易的な方法ですが計測してみました。

書き方 実行時間
foreach 0.38007283210754
array_map 0.5925190448761
Functional\map 1.2633831501007

Oh… 😱

動作速度が遅く速度が求められる要件では注意が必要ですね。

計測で使用したソースコード

7. まとめ

for文でコレクションのループ中に何かしら処理を行う場合には、一時変数に結果を代入する事が多く、下の例では一時変数 result が可変になります。

好みにもよると思いますが、 筆者は上の例では簡単な処理なので脳内でどういう状態かを把握できますが、 複雑な処理になってきた場合に、一時変数が脳内のメモリを圧迫していきます。
その点、一時変数を使わない、変数を不変に保つようなmapなどの関数型な操作は便利だと思います。

ただし、計測の通り実行速度は確実にその他の方法よりも遅くなるので速度が求められる要件では注意が必要です。 その他でもテストコードを書いていて配列以外の型を渡した場合でも結果が全てプリミティブな配列に変換されてしまうのが少し気になりました。

簡易的ですがFunctional PHPのご紹介は以上です。
公式のGitHubではその他の関数型プリミティブのドキュメントがありますので、 興味のある方は覗いてみてください。


この記事のカテゴリ:

SNSで最新の情報を
受け取ることができます!