LoginSignup
38
40

More than 3 years have passed since last update.

PHPの配列操作がめんどいのでRxPHPを導入する

Last updated at Posted at 2019-10-14

RxPHPを使ってみようと思った経緯

PHPで複雑な配列操作をしていると辛くなった事があったので、良い解決策がないかと思ってRxPHP調べたらいい感じにかけそうだったので使ってみた

PHPの配列操作はめんどくさい

PHPには配列操作用にarray_map、array_filter、array_reduceなど
配列が操作できる関数が色々ある
基本的にコールバック関数を使って操作する

配列操作の例 (3文字よりでかい単語だけ抽出して文字の合計を算出)

例1(一旦変数に渡す)
$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 }
);

これだといちいち変数に入れるんめんどい

例2(処理をネストする)
$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

さっきの例と同じコードをかく

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使った方がコード量は多くなったが、複雑な配列処理をめっちゃ書くプロジェクトがあれば、効力(可読性とか保守性とか)を発揮するはず
単純な処理しかない場合は、既存の関数で十分かなと思う

38
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
40