php.netの配列関数の役割を大雑把に分類してみた

# はじめに
Advent Calendarに参加するのは初めてです。
普段投稿している記事より多くの方に見られるかと思いますので、緊張しますね・・・

ちなみに自分のPHP歴は1年半ほどで、実務経験に至っては異業種（事務職）から転職してちょうど4ヶ月経ったところです。

まだ新参者ですが、この視点が皆様のお役に立てば嬉しいです。

# なぜ配列関数をテーマにしたのか？
[YYPHP Advent Calendar 2018](https://qiita.com/advent-calendar/2018/yyphp)の[suin](https://qiita.com/suin)さんの記事に影響を受けました。

>[PHPの効率的な学習法: YYPHP60回開催を通じて、先輩PHPerから得られた35の知見](https://qiita.com/suin/items/edb067f2e5df713e966d)

こちらに[学びのガイドライン](https://qiita.com/suin/items/edb067f2e5df713e966d#%E5%AD%A6%E3%81%B3%E3%81%AE%E3%82%AC%E3%82%A4%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3)として、PHPの公式マニュアルである[php.net](http://php.net/manual/ja/index.php)に関する記事が紹介されています。
>[php.net(PHP公式マニュアル)](https://qiita.com/suin/items/79a6851f83ac5dfdca94)

さらにこの中で、YYPHP参加者の意見として`「配列系の関数は全て目を通すと信じられないほどはかどる」`との紹介がありますが、これに共感したからです。

私は既存のコードを読むのも自分でコードを書くのも大変時間がかかります。やばいです。そして配列が登場すると値の受け渡し、処理の流れが途端に追い難くなります。

なので、配列関数がその解決の糸口になるのではと思い、今回の記事のテーマにしました。

# php.netの配列関数

現在、[php.net 配列関数](http://php.net/manual/ja/ref.array.php)では`82個`の配列関数が紹介されています。
多いのか少ないのか正直わかりません。

今回の執筆にあたり、各配列関数の``説明〜例（最初の例だけ）``を読んでみました。完璧に覚えるのは不可能なので、自分の中にインデックスを作成するイメージです。

さらに関数の役割を分類できれば使いやすいのではと思い、私の独断と偏見で分類しました。

なお、配列関数全てを分類したわけではありません。分類したのは関数の役割です。（情報量が多すぎると概要すら掴めなくなる恐れがあるので・・・）

紹介する配列関数も、分類した中で一番簡単に説明できるものを選びました。

では、始めます。

# 編集系
これらの機能が、単独または組み合わされて動く関数です。（配列関数の解説は[php.net 配列関数](http://php.net/manual/ja/ref.array.php)から抜粋しました。）

- 追加
- 削除
- 置換
- 分割
- 抽出

### array_push
一つ以上の要素を配列の最後に追加する。（追加）

追加する要素が1つの場合は、`$fruits[] = "banana";`の書き方が勧められています。（by公式）

```test.php
$fruits = array('apple', 'orange');

var_dump(array_push($fruits, "banana"));
// 出力結果: int(3)

var_dump($fruits);
// 出力結果:
// array(3) {
//   [0]=>
//   string(5) "apple"
//   [1]=>
//   string(6) "orange"
//   [2]=>
//   string(6) "banana"
// }
```

### array_pop
配列の末尾から要素を取り除く。（削除）

```test.php
$fruits = array('apple', 'orange', 'banana');

var_dump(array_pop($fruits));
// 出力結果: string(6) "banana"

var_dump($fruits);
// 出力結果:
// array(2) {
//   [0]=>
//   string(5) "apple"
//   [1]=>
//   string(6) "orange"
// }
```

### array_splice
配列の一部を削除し、他の要素で置換する。（削除・置換）

```test.php
$fruits = array('apple', 'orange', 'banana');

var_dump(array_splice($fruits, 2, 1, "lemon"));
// 出力結果:
// array(1) {
//   [0]=>
//   string(6) "banana"
// }

var_dump($fruits);
// 出力結果:
// array(3) {
//   [0]=>
//   string(5) "apple"
//   [1]=>
//   string(6) "orange"
//   [2]=>
//   string(5) "lemon"
// }
```

### array_chunk
配列を分割する。（分割）

```test.php
$fruits = array('apple', 'orange', 'banana', 'lemon', 'peach');

var_dump(array_chunk($fruits, 2));
// 出力結果:
// array(3) {
//   [0]=>
//   array(2) {
//     [0]=>
//     string(5) "apple"
//     [1]=>
//     string(6) "orange"
//   }
//   [1]=>
//   array(2) {
//     [0]=>
//     string(6) "banana"
//     [1]=>
//     string(5) "lemon"
//   }
//   [2]=>
//   array(1) {
//     [0]=>
//     string(5) "peach"
//   }
// }
```
### array_filter
コールバック関数を使用して、配列の要素をフィルタリングする。（抽出）

```test.php
function number_check($num)
{
    if ($num % 2 === 1) {
        return true;
    } else {
        return false;
    }
}

$number = array(1, 2, 3, 4, 5);

var_dump(array_filter($number, "number_check"));
// 出力結果:
// array(3) {
//   [0]=>
//   int(1)
//   [2]=>
//   int(3)
//   [4]=>
//   int(5)
// }
```

### array_column
入力配列から単一のカラムの値を返す。（抽出）

```test.php
$members = array(
    array(
        'name' => 'John',
        'sex'  => 'male',
        'age'  => 35,
    ),
    array(
        'name' => 'Kate',
        'sex'  => 'female',
        'age'  => 30,
    ),
    array(
        'name' => 'Peter',
        'sex'  => 'male',
        'age'  => 25,
    ),
);

var_dump(array_column($members, 'name'));
// 出力結果:
// array(3) {
//   [0]=>
//   string(4) "John"
//   [1]=>
//   string(4) "Kate"
//   [2]=>
//   string(5) "Peter"
// }
```

# 情報取得系

### count
変数に含まれるすべての要素、 あるいはオブジェクトに含まれる何かの数を数える。

```test.php
$number = array(1, 2, 3, 4);

var_dump(count($number));
// 出力結果: int(4)
```

# 検索系

### in_array
配列に値があるかチェックする。

```test.php
$fruits = array('apple', 'orange', 'banana', 'lemon', 'peach');

var_dump(in_array("apple", $fruits));
// 出力結果: bool(true)
```

### array_search
指定した値を配列で検索し、見つかった場合に対応する最初のキーを返す。

```test.php
$fruits = array('apple', 'orange', 'banana', 'lemon', 'peach');

var_dump(array_search("lemon", $fruits));
// 出力結果: int(3)
```

# ソート系

### sort
配列をソートする。

```test.php
$number = array(1, 2, 3);
$fruits = array('apple', 'orange', 'banana');

var_dump(sort($number));
// 出力結果: bool(true)

var_dump(sort($fruits));
// 出力結果: bool(true)

foreach ($number as $num) {
    echo $num."\n";
}
// 出力結果: 
// 1
// 2
// 3

foreach ($fruits as $fruit) {
    echo $fruit."\n";
}
// 出力結果: 
// apple
// banana
// orange
```

# 複数配列系
## 比較
### array_diff
配列の差を計算する。

```test.php
$array1 = array("a" => "apple", "c" => "orange", "banana", "lemon", "plum");
$array2 = array("b" => "apple", "orange", "c" => "banana", "lemon", "peach");
$result = array_diff($array1, $array2);

echo "<pre>";
var_dump($result);
echo "</pre>";
// 出力結果:
// array(1) {
//   [2]=>
//   string(4) "plum"
// }
```

### array_intersect
配列の共通項を計算する。

```test.php
$array1 = array("a" => "apple", "c" => "orange", "banana", "lemon", "plum");
$array2 = array("b" => "apple", "orange", "c" => "banana", "lemon", "peach");
$result = array_intersect($array1, $array2);

echo "<pre>";
var_dump($result);
echo "</pre>";
// 出力結果:
// array(4) {
//   ["a"]=>
//   string(5) "apple"
//   ["c"]=>
//   string(6) "orange"
//   [0]=>
//   string(6) "banana"
//   [1]=>
//   string(5) "lemon"
// }
```

## 結合
### array_merge
ひとつまたは複数の配列をマージする。

```test.php
$array1 = array("a" => "apple", "b" => "orange", "banana", "lemon");
$array2 = array("b" => "apple", "c" => "banana","orange", "lemon", "peach");
$result = array_merge($array1, $array2);

var_dump($result);
// 出力結果:
// array(8) {
//   ["a"]=>
//   string(5) "apple"
//   ["b"]=>
//   string(5) "apple"
//   [0]=>
//   string(6) "banana"
//   [1]=>
//   string(5) "lemon"
//   ["c"]=>
//   string(6) "banana"
//   [2]=>
//   string(6) "orange"
//   [3]=>
//   string(5) "lemon"
//   [4]=>
//   string(5) "peach"
// }
```

# その他
## 値同士の計算
### array_sum
配列の中の値の合計を計算する。

```test.php
$number = array(1, 2, 3, 4);

echo array_sum($number);
// 出力結果: 10
```

### array_product
配列の値の積を計算する。

```test.php
$number = array(1, 2, 3, 4);

echo array_product($number);
// 出力結果: 24
```
 
## 配列・変数間の変換
### list
配列と同様の形式で、複数の変数への代入を行う。

```test.php
$member = array('John', 'male', 35);
list($name, $sex, $age) = $member;

echo "$name, $sex, $age";
// 出力結果: John, male, 35
```

### compact
変数名とその値から配列を作成する。

```test.php
$name = "John";
$sex  = "male";
$age  = 35;
$member = compact("name", "sex", "age");

echo "<pre>";
var_dump($member);
echo "</pre>";
// 出力結果:
// array(3) {
//   ["name"]=>
//   string(4) "John"
//   ["sex"]=>
//   string(4) "male"
//   ["age"]=>
//   int(35)
// }
```
 
## ポインタ移動
ポインタを移動させる。

ポインタは、PHPのバージョンによって[foreach](http://php.net/manual/ja/control-structures.foreach.php)における挙動が異なるそうです。

```test.php
$fruits = array('apple', 'orange', 'banana', 'lemon', 'peach');

$fruit = current($fruits); // $fruit = 'apple';
$fruit = next($fruits);    // $fruit = 'orange';
$fruit = prev($fruits);    // $fruit = 'apple';
$fruit = end($fruits);     // $fruit = 'peach';
$fruit = reset($fruits);   // $fruit = 'apple';
```

# 注目したこと
初学者向けですが、ここに注目すると良いかもしれません。

### 対象は値か、キー（添字）か、その両方か
関数によって対象とするものが違います
間違った関数を使用すると、意図しない結果になってしまいます。

- array_diff（値だけを確認して、配列の差を計算する。）
- array_diff_key（キーだけを確認して、配列の差を計算する。）
- array_diff_assoc（キーと値の両方を確認して、配列の差を計算する。）

似た名前が存在する関数は要注意です。

### 返り値と配列自身の変化
配列の末尾から要素を取り除く`array_pop`をもう一度見てみます。
この場合、返り値は削除した要素`banana`になり、配列`$fruits`自身もその要素が削除されます。

```test.php
$fruits = array('apple', 'orange', 'banana');

var_dump(array_pop($fruits));
// 出力結果: string(6) "banana"

var_dump($fruits);
// 出力結果:
// array(2) {
//   [0]=>
//   string(5) "apple"
//   [1]=>
//   string(6) "orange"
// }
```

今度は配列を分割する`array_chunk`を見てみます。
こちらは、返り値に関数を使用した後の配列がそのまま入っています。

元の配列`$fruit`自身に変化はありません。（下記のコードには記載されていませんが。）

```test.php
$fruits = array('apple', 'orange', 'banana', 'lemon', 'peach');

var_dump(array_chunk($fruits, 2));
// 出力結果:
// array(3) {
//   [0]=>
//   array(2) {
//     [0]=>
//     string(5) "apple"
//     [1]=>
//     string(6) "orange"
//   }
//   [1]=>
//   array(2) {
//     [0]=>
//     string(6) "banana"
//     [1]=>
//     string(5) "lemon"
//   }
//   [2]=>
//   array(1) {
//     [0]=>
//     string(5) "peach"
//   }
// }
```

詳細は[php.net 配列関数](http://php.net/manual/ja/ref.array.php)の`説明`と`返り値`の項目に説明されていますので、読むことを強くお勧めします。

### 実際に動かしてみる
- 配列関数の`例`をコピーして、実際に動かしてみます。
- さらに値や引数を変えて遊んでみます。
- さらに随所で`var_dump`すると処理の流れがわかりやすいです。

配列関数に限らずですが(`・ω・´)

関数によっては、配列の値の型によって動作が変わるものがあります。

`var_dump`は配列や変数の内容確認はもちろんのこと、それらの`型`をチェックできるので、習慣にしておくと良いです。

### コールバック関数がよく使われる
コールバック関数が使える配列関数も多いです。内容はユーザーが定義できるので、関数のカスタマイズができます。

名前に`u`が入る関数が多いです。もちろんそれ以外にも存在します。

- array_udiff（データの比較にコールバック関数を用い、配列の差を計算する。）
- array_walk（配列の全ての要素にユーザー定義の関数を適用する。）
- usort（ユーザー定義の比較関数を使用して、配列を値でソートする。）

コールバック関数は`callable`という型（タイプヒント）で表されています。関数の引数に、文字列としてコールバック関数を与えます。

実はこの記事を書いていて、初めて存在を知りました・・・

>[コールバック](http://php.net/manual/ja/language.types.callable.php)

### 再帰処理がされているかどうか
まず、再帰処理がうまく説明できません。

>[「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典 再帰処理](https://wa3.i-3-i.info/word14899.html)

・・・・・・イメージはだいたい掴めたかも。

実際に、再帰処理の有無で動作が違う`array_merge_recursive`と`array_merge`を見比べてみます。

```test.php
$array1 = array("color" => array("favorite" => "red"), 5);
$array2 = array(10, "color" => array("favorite" => "green", "blue"));

$result1 = array_merge_recursive($array1, $array2);
var_dump($result1);
// 出力結果:
// array(3) {
//   ["color"]=>
//   array(2) {
//     ["favorite"]=>
//     array(2) {
//       [0]=>
//       string(3) "red"
//       [1]=>
//       string(5) "green"
//     }
//     [0]=>
//     string(4) "blue"
//   }
//   [0]=>
//   int(5)
//   [1]=>
//   int(10)
// }

$result2 = array_merge($array1, $array2);
var_dump($result2);
// 出力結果:
// array(3) {
//   ["color"]=>
//   array(2) {
//     ["favorite"]=>
//     string(5) "green"
//     [0]=>
//     string(4) "blue"
//   }
//   [0]=>
//   int(5)
//   [1]=>
//   int(10)
// }
```

多次元配列になっている`color`の部分に注目です。

再帰処理がされている場合は、`$array1（マージ元）のred`、`$array2（マージ先）のgreen, blue`が全て存在していますが、そうでない場合はマージ先の値に上書きされ、マージ元である`$array1の値red`が消えています。

・・・・・・。
まだ理解がふわふわしているので、この辺りは実際にコード書いて試しながら慣れていこうと思います。

# フレームワークにもあるよ
フレームワークにも独自の関数が定義されています。``ヘルパ関数``です。

力が尽きかけているので、１つだけ使ってみます。

## Laravelのヘルパ関数
### array_get
指定された値を「ドット」記法で指定された値を深くネストされた配列から取得する。

```test.php
$array = ['member' => ['John' => ['age' => 35]]];
$age = array_get($array, 'member.John.age');

var_dump($age);
// 出力結果: int(35)
```

多次元配列を対象とする関数が多そうですね。

公式サイトもかなり充実してます。
>[Laravel 5.5 ヘルパ](https://readouble.com/laravel/5.5/ja/helpers.html)

PHPとフレームワークに同じ機能を持つ関数がある場合、どちらを使用すべきか判断できると良いのですが！

# 参考記事
配列関数を分類した記事はあまり見かけませんでしたが、以下に参考記事を紹介します。

>[本当に使える！PHPerなら知っておきたい便利な配列関数79選！！ ver.2015](http://tech.connehito.com/entry/2015/10/28/170312)

# おわりに
流石に、配列関数82個は読むのが大変でした。（流し読みでも！）

しかし、「配列関数でこんなことができる」は、「配列はこうやって使うことが多い」に繋がっているかと思います。

コードを掲載した関数は、全て自分の端末で手を動かして確認したものです。今回それを記事としてアウトプットし皆様に読んでいただき、素敵な思い出にもなりました。

ここまでお読みいただき本当にありがとうございます。
皆様良いクリスマスを(^ ^) 

明日12/6は@kasyuuさんです。
何とかタスキはつなげました・・・よろしくお願いします！