PHP

Underbar.phpの使い方

はじめに

PHPの配列操作の標準関数はJava8のStream APIやC#のLINQと比べてちょっと使いづらいです・・・(array_mapとかarray_filterとか)

そこで、Underbar.php

Underbar.phpはUnderscore.jsライクなコレクション処理のためのPHPのライブラリです。 Underscore.jsとの大きな違いとしてIteratorを利用した遅延リストが生成できる点が上げられます。

良さげですね。

準備

composer.json
{
    "require": {
        "emonkak/underbar.php": "dev-master"
    }
}

使用例

filter(抽出)

<?php
use Underbar\ArrayImpl as _;

// 配列
$arr = [1, 2, 3];
$arr = _::filter($arr, function ($e) {return $e % 2 !== 0;});

// array(2) {
//   [0] =>
//   int(1)
//   [2] =>
//   int(3)
// }

// 連想配列
$arr = [
    ['name' => 'Taro', 'age' => 20]
    , ['name' => 'Jiro', 'age' => 18]
    , ['name' => 'Hanako', 'age' => 20]
];
$arr = _::filter($arr, function ($e) {return $e['age'] === 20;});

// array(2) {
//   [0] =>
//   array(2) {
//     'name' =>
//     string(4) "Taro"
//     'age' =>
//     int(20)
//   }
//   [2] =>
//   array(2) {
//     'name' =>
//     string(6) "Hanako"
//     'age' =>
//     int(20)
//   }
// }

map(射影)

<?php
use Underbar\ArrayImpl as _;

// 配列
$arr = [1, 2, 3];
$arr = _::map($arr, function ($e) {return $e * 2;});

// array(3) {
//   [0] =>
//   int(2)
//   [1] =>
//   int(4)
//   [2] =>
//   int(6)
// }

// 連想配列
$arr = [
    ['name' => 'Taro', 'age' => 20]
    , ['name' => 'Jiro', 'age' => 18]
    , ['name' => 'Hanako', 'age' => 20]
];
$arr = _::map($arr, function ($e) {return strtoupper($e['name']);});

// array(3) {
//   [0] =>
//   string(4) "TARO"
//   [1] =>
//   string(4) "JIRO"
//   [2] =>
//   string(6) "HANAKO"
// }

sortBy(並べ替え)

<?php
use Underbar\ArrayImpl as _;

// 配列
$arr = [2, 3, 1];
$arr = _::sortBy($arr, function ($e) {return $e;});

// array(3) {
//   [0] =>
//   int(1)
//   [1] =>
//   int(2)
//   [2] =>
//   int(3)
// }

// 連想配列
$arr = [
    ['name' => 'Taro', 'age' => 22]
    , ['name' => 'Jiro', 'age' => 18]
    , ['name' => 'Hanako', 'age' => 20]
];
$arr = _::sortBy($arr, function ($e) {return $e['age'];});

// array(3) {
//   [0] =>
//   array(2) {
//     'name' =>
//     string(4) "Jiro"
//     'age' =>
//     int(18)
//   }
//   [1] =>
//   array(2) {
//     'name' =>
//     string(6) "Hanako"
//     'age' =>
//     int(20)
//   }
//   [2] =>
//   array(2) {
//     'name' =>
//     string(4) "Taro"
//     'age' =>
//     int(22)
//   }
// }

flatten(平坦化)

<?php
use Underbar\ArrayImpl as _;

// 配列
$arr = [1, [2], [3, [[4]]]];
$arr = _::flatten($arr);

// array(4) {
//   [0] =>
//   int(1)
//   [1] =>
//   int(2)
//   [2] =>
//   int(3)
//   [3] =>
//   int(4)
// }

// 連想配列
$arr = [
    [
        ['name' => 'Taro', 'age' => 22]
        , ['name' => 'Jiro', 'age' => 18]
    ]
    , ['name' => 'Hanako', 'age' => 20]
];
$arr = _::flatten($arr);

// array(6) {
//   [0] =>
//   string(4) "Taro"
//   [1] =>
//   int(22)
//   [2] =>
//   string(4) "Jiro"
//   [3] =>
//   int(18)
//   [4] =>
//   string(6) "Hanako"
//   [5] =>
//   int(20)
// }

chain(メソッドチェーン)

<?php
use Underbar\IteratorImpl as _;

// 配列
$arr = [3, 2, 1];
$arr = _::chain($arr)
    ->filter(function ($e) {return $e % 2 !== 0;})
    ->map(function ($e) {return $e * 2;})
    ->sortBy(function ($e) {return $e;})
    ->toArray();

// array(2) {
//   [0] =>
//   int(2)
//   [1] =>
//   int(6)
// }

// オブジェクト型
class Person
{
    public $name;
    public $age;

    public function __construct($name, $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

$people = [
    new Person('Taro', 20)
    , new Person('Jiro', 18)
    , new Person('Hanako', 20)
];
$person = _::chain($people)
    ->filter(function ($e) {return $e->age === 20;})
    ->map(function ($e) {return new Person(strtoupper($e->name), $e->age);})
    ->sortBy(function ($e) {return $e->name;})
    ->first();

// class Person#17 (2) {
//   public $name =>
//   string(6) "HANAKO"
//   public $age =>
//   int(20)
// }