RxPHPを使ってみようと思った経緯
PHPで複雑な配列操作をしていると辛くなった事があったので、良い解決策がないかと思ってRxPHP調べたらいい感じにかけそうだったので使ってみた
PHPの配列操作はめんどくさい
PHPには配列操作用にarray_map、array_filter、array_reduceなど
配列が操作できる関数が色々ある
基本的にコールバック関数を使って操作する
配列操作の例 (3文字よりでかい単語だけ抽出して文字の合計を算出)
$languages = ['PHP', 'PYTHON', 'RUBY', 'GOLANG'];
$lengths = array_map(
function ($lang) { return str_len($lang) },
$languages
);
$filterd = array_filter(
$lengths,
function ($length) { return $length > 3 }
);
$sum = array_reduce(
$filtered,
function ($x, $y) { return $x + $y }
);
これだといちいち変数に入れるんめんどい
$languages = ['PHP', 'PYTHON', 'RUBY', 'GOLANG'];
$sum = array_reduce(
array_filter(
array_map(
function ($lang) { return str_len($lang) },
$languages
),
function ($length) { return $length > 3 }
),
function ($x, $y) {
return $x + $y
}
);
ネストして見にくいしコードの修正がしにくくてめんどい
Javascriptみたいにメソッドチェーンで書きたいと思ってたらRxPHPで書けそうだった
JSで書いた場合
const languages = ['PHP', 'PYTHON', 'RUBY', 'GOLANG'];
const sum = languages
.map(lang => lang.length)
.filter(length => length > 3)
.reduce((x, y) => x + y);
JSみたいにメソッドチェーンで書けると見やすいし、いちいち変数を作らなくていい
RxPHPを使ってみる
RxPHPはReactive ProgrammingをするためのライブラリReactiveXらしく、オブザーバーパターンとかイテレーターパターンとか使ってるみたい
配列以外にも、イベント処理とか非同期処理にも使えるけど、PHPではライブラリ(ReactPHPとか)入れないと使えないので、普通は配列以外では使わんかなと思うので、とりあえずややこしい話はどうでもいい
RxPHPの構成要素
Observable, Observer, Operatorぐらい分かっとけば配列操作では困らないと思う
Observable
データをぶん投げるやつ
Observer
データをObservableから受け取って処理する
Operator
Observerに渡す前にデータを加工できる
PHP関数のarray_map, array_filter, array_reduceみたいなやつ
他色々処理ができる
何種類あるかは知らん
Stream
ObservableからObserverまでの流れをStreamと言ってるみたい
RxPHPでコードを書いてみる
インストール
composer require reactivex/rxphp
さっきの例と同じコードをかく
use Rx\Observable;
use Rx\Scheduler;
use Rx\Scheduler\ImmediateScheduler;
// スケジューラーの設定
$immediateScheduler = new ImmediateScheduler();
Scheduler::setDefaultFactory(function () use ($immediateScheduler) {
return $immediateScheduler;
});
// 配列処理
const languages = ['PHP', 'PYTHON', 'RUBY', 'GOLANG'];
Observable::fromArray(languages) // Observable
->map(function ($lang) { // Operator
return str_len($lang);
})
->filter(function ($length) { // Operator
return $length > 3;
})
->reduce(function ($x, $y) { // Operator
return $x + $y;
})
->subscribe( //Observer
function ($sum) {
print("合計は$sum")
},
// どっかでエラーが出たら発火
function (\Exception $ex) {
print('失敗したよ')
},
// 投げたデータの処理が全て完了したら発火
function () {
print('完了したよ')
});
Schedulerを設定しないと怒られたので設定
Schedulerは、どう実行するのか(スレッド分けたり、処理の順番変えたり)決められるが、PHPはライブラリ入れんとスレッド分けれんし基本逐次処理なので即座に実行してくれるimmediateSchedulerを設定する
なんでimmediateSchedulerがデフォルト設定じゃないんかな?
設定しなくてもいい気がするのでなんかミスってるかも
Rx\ObservableのfromArrayメソッドで配列を投げる
map・filter・reduceメソッドがOperatorにあたる
subscribeがObserverにあたって、データ受け取り時、処理エラー時、完了時にそれぞれ処理が書ける
まとめ
この記事では、RxPHP使った方がコード量は多くなったが、複雑な配列処理をめっちゃ書くプロジェクトがあれば、効力(可読性とか保守性とか)を発揮するはず
単純な処理しかない場合は、既存の関数で十分かなと思う