helper-array.md 11.6 KB
Newer Older
1 2 3 4 5 6
ArrayHelper
===========

[PHP の充実した配列関数](http://php.net/manual/ja/book.array.php) への追加として、Yii の配列ヘルパは、配列をさらに効率的に扱うことを可能にするスタティックなメソッドを提供しています。


7
## 値を取得する <span id="getting-values"></span>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

配列、オブジェクト、またはその両方から成る複雑な構造から値を取得することは、標準的な PHP を使う場合、何度も繰り返さねばならない面倒くさい仕事です。
最初に `isset` でキーの存在をチェックしなければならず、次に、キーが存在していれば値を取得し、存在していなければ、デフォルト値を提供しなければなりません。

```php
class User
{
    public $name = 'Alex';
}

$array = [
    'foo' => [
        'bar' => new User(),
    ]
];

$value = isset($array['foo']['bar']->name) ? $array['foo']['bar']->name : null;
```

Yii はこれをするための非常に便利なメソッドを提供しています。

```php
$value = ArrayHelper::getValue($array, 'foo.bar.name');
```

メソッドの最初の引数は、どこから値を取得しようとしているかを指定します。
二番目の引数は、データの取得の仕方を指定します。これは、以下の一つとすることが出来ます。

- 値を読み出すべき配列のキーまたはオブジェクトのプロパティの名前。
- ドットで分離された配列のキーまたはオブジェクトのプロパティ名のセット。上の例で使用した形式。
- 値を返すコールバック。

コールバックは次の形式でなければなりません。

```php
$fullName = ArrayHelper::getValue($user, function ($user, $defaultValue) {
    return $user->firstName . ' ' . $user->lastName;
});
```

三番目のオプションの引数はデフォルト値であり、指定されない場合は `null` となります。
以下のようにして使用します。

```php
$username = ArrayHelper::getValue($comment, 'user.username', 'Unknown');
```

値を取得して、その直後にそれを配列から削除したい場合は、`remove` メソッドを使うことが出来ます。

```php
$array = ['type' => 'A', 'options' => [1, 2]];
$type = ArrayHelper::remove($array, 'type');
```

このコードを実行した後では、`$array` には `['options' => [1, 2]]` が含まれ、`$type``A` となります。
`getValue` メソッドとは違って、`remove` は単純なキー名だけをサポートすることに注意してください。


66
## キーの存在をチェックする <span id="checking-existence-of-keys"></span>
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

`ArrayHelper::keyExists` は、大文字と小文字を区別しないキーの比較をサポートすることを除いて、[array_key_exists](http://php.net/manual/ja/function.array-key-exists.php) と同じ動作をします。
例えば、

```php
$data1 = [
    'userName' => 'Alex',
];

$data2 = [
    'username' => 'Carsten',
];

if (!ArrayHelper::keyExists('username', $data1, false) || !ArrayHelper::keyExists('username', $data2, false)) {
    echo "username を提供してください。";
}
```

85
## カラムを取得する <span id="retrieving-columns"></span>
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

データ行またはオブジェクトの配列から、あるカラムの値を取得する必要があることがよくあります。
良くある例は、ID のリストの取得です。

```php
$data = [
    ['id' => '123', 'data' => 'abc'],
    ['id' => '345', 'data' => 'def'],
];
$ids = ArrayHelper::getColumn($array, 'id');
```

結果は `['123', '345']` となります。

追加の変形が要求されたり、値の取得方法が複雑であったりする場合は、無名関数を二番目の引数として指定することが出来ます。

```php
$result = ArrayHelper::getColumn($array, function ($element) {
    return $element['id'];
});
```


109
## 配列を再インデックスする <span id="reindexing-arrays"></span>
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

指定されたキーに従って配列にインデックスを付けるために、`index` メソッドを使うことが出来ます。
入力値の配列は、多次元配列であるか、オブジェクトの配列でなければなりません。
キーは、サブ配列のキーの名前、オブジェクトのプロパティの名前、または、配列要素を与えられてキーの値を返す無名関数とすることが出来ます。

キーの値が null である場合、対応する配列要素は破棄されて、結果には入りません。
例えば、

```php
$array = [
    ['id' => '123', 'data' => 'abc'],
    ['id' => '345', 'data' => 'def'],
];
$result = ArrayHelper::index($array, 'id');
// 結果は次のようになります
// [
//     '123' => ['id' => '123', 'data' => 'abc'],
//     '345' => ['id' => '345', 'data' => 'def'],
// ]

// 無名関数を使う
$result = ArrayHelper::index($array, function ($element) {
    return $element['id'];
});
```


137
## マップを作成する <span id="building-maps"></span>
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

多次元配列またはオブジェクトの配列からマップ (キー-値 のペア) を作成するためには `map` メソッドを使うことが出来ます。
`$from``$to` のパラメータで、マップを構成するキー名またはプロパティ名を指定します。
オプションで、グループ化のためのフィールド `$group` に従って、マップをグループ化することも出来ます。
例えば、

```php
$array = [
    ['id' => '123', 'name' => 'aaa', 'class' => 'x'],
    ['id' => '124', 'name' => 'bbb', 'class' => 'x'],
    ['id' => '345', 'name' => 'ccc', 'class' => 'y'],
);

$result = ArrayHelper::map($array, 'id', 'name');
// 結果は次のようになります
// [
//     '123' => 'aaa',
//     '124' => 'bbb',
//     '345' => 'ccc',
// ]

$result = ArrayHelper::map($array, 'id', 'name', 'class');
// 結果は次のようになります
// [
//     'x' => [
//         '123' => 'aaa',
//         '124' => 'bbb',
//     ],
//     'y' => [
//         '345' => 'ccc',
//     ],
// ]
```


173
## 多次元配列の並べ替え <span id="multidimensional-sorting"></span>
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

`multisort` メソッドは、オブジェクトの配列または入れ子にされた配列を、一つまたは複数のキーによって並べ替えることを手助けします。
例えば、

```php
$data = [
    ['age' => 30, 'name' => 'Alexander'],
    ['age' => 30, 'name' => 'Brian'],
    ['age' => 19, 'name' => 'Barney'],
];
ArrayHelper::multisort($data, ['age', 'name'], [SORT_ASC, SORT_DESC]);
```

並べ替えの後には、`$data` に次のデータが入っています。

```php
[
    ['age' => 19, 'name' => 'Barney'],
    ['age' => 30, 'name' => 'Brian'],
    ['age' => 30, 'name' => 'Alexander'],
];
```

並べ替えで参照するキーを指定する二番目の引数は、一つのキーであれば文字列、複数のキーであれば配列を取ることが出来ます。
さらに、次のような無名関数でも構いません。

```php
ArrayHelper::multisort($data, function($item) {
    return isset($item['age']) ? ['age', 'name'] : 'name';
});
```

三番目の引数は並べ替えの順序です。
一つのキーによる並べ替えの場合は、`SORT_ASC``SORT_DESC` のいずれかです。
複数の値による並べ替えの場合は、並べ替えの順序の配列を渡して、値ごとに違う順序で並べ替えることが出来ます。

最後の引数は並べ替えのフラグで、PHP の [sort()](http://php.net/manual/ja/function.sort.php) 関数に渡されるのと同じ値を取ることが出来ます。


213
## 配列の型を検出する <span id="detecting-array-types"></span>
214 215 216 217 218 219 220 221 222 223 224 225 226 227

配列が添字配列であるか連想配列であるかを知ることが出来ると便利です。例を挙げましょう。

```php
// キーは指定されていない
$indexed = ['Qiang', 'Paul'];
echo ArrayHelper::isIndexed($indexed);

// 全てのキーは文字列
$associative = ['framework' => 'Yii', 'version' => '2.0'];
echo ArrayHelper::isAssociative($associative);
```


228
## 値を HTML エンコード / デコードする <span id="html-encoding-values"></span>
229 230 231 232 233 234 235 236 237 238 239 240 241

文字列の配列の中にある特殊文字を HTML エンティティ にエンコード、または、HTML エンティティからデコードするために、下記の関数を使うことが出来ます。

```php
$encoded = ArrayHelper::htmlEncode($data);
$decoded = ArrayHelper::htmlDecode($data);
```

デフォルトでは、値だけがエンコードされます。
二番目の引数を `false` として渡すことによって、配列のキーもエンコードすることが出来ます。
エンコードにはアプリケーションの文字セットが使用されますが、三番目の引数によってそれを変更することも出来ます。


242
## 配列をマージする <span id="merging-arrays"></span>
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

```php
  /**
    * 二つ以上の配列を再帰的に一つの配列にマージします。
    * 各配列に同じ文字列のキー値を持つ要素がある場合は、(array_merge_recursive とは違って)
    * 後のものが前のものを上書きします。
    * 両方の配列が、同じキーを持つ配列型の要素を持っている場合は、再帰的なマージが実行されます。
    * 添字型の要素については、後の配列の要素が前の配列の要素の後に追加されます。
    * @param array $a マージ先の配列
    * @param array $b マージ元の配列。追加の配列を三番目の引数、四番目の引数、、、として指定可能です。
    * @return array マージされた配列 (元の配列は変更されません。)
    */
    public static function merge($a, $b)
```


259
## オブジェクトを配列に変換する <span id="converting-objects-to-arrays"></span>
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303

オブジェクトまたはオブジェクトの配列を配列に変換する必要があることがよくあります。
最もよくあるのは、REST API によってデータ配列を提供するなどの目的で、アクティブレコードモデルを変換する場合です。
そうするために、次のコードを使うことが出来ます。

```php
$posts = Post::find()->limit(10)->all();
$data = ArrayHelper::toArray($post, [
    'app\models\Post' => [
        'id',
        'title',
        // 結果配列のキー名 => プロパティの値
        'createTime' => 'created_at',
        // 結果配列のキー名 => 無名関数が返す値
        'length' => function ($post) {
            return strlen($post->content);
        },
    ],
]);
```

最初の引数が変換したいデータです。この例では、`Post` AR モデルを変換しようとしています。

二番目の引数は、クラスごとの変換マップです。
ここでは、`Post` モデルの変換マップを設定しています。
変換マップの配列が、一連のマップを含んでいます。各マップは以下のいずれかの形式を取ります。

- フィールド名 - そのままインクルードされる。
- キー/値 のペア - 配列のキー名にしたい文字列と、値を取得すべきモデルのカラムの名前。
- キー/値 のペア - 配列のキー名にしたい文字列と、値を返すコールバック。

変換の結果は以下のようになります。


```php
[
    'id' => 123,
    'title' => 'test',
    'createTime' => '2013-01-01 12:00AM',
    'length' => 301,
]
```

特定のクラスについて、配列に変換するデフォルトの方法を提供するために、そのクラスの [[yii\base\Arrayable|Arrayable]] インタフェイスを実装することが出来ます。