Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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

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

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

なぜ配列関数をテーマにしたのか?

YYPHP Advent Calendar 2018suinさんの記事に影響を受けました。

PHPの効率的な学習法: YYPHP60回開催を通じて、先輩PHPerから得られた35の知見

こちらに学びのガイドラインとして、PHPの公式マニュアルであるphp.netに関する記事が紹介されています。

php.net(PHP公式マニュアル)

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

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

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

php.netの配列関数

現在、php.net 配列関数では82個の配列関数が紹介されています。
多いのか少ないのか正直わかりません。

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

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

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

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

では、始めます。

編集系

これらの機能が、単独または組み合わされて動く関数です。(配列関数の解説はphp.net 配列関数から抜粋しました。)

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

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における挙動が異なるそうです。

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 配列関数説明返り値の項目に説明されていますので、読むことを強くお勧めします。

実際に動かしてみる

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

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

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

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

コールバック関数がよく使われる

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

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

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

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

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

コールバック

再帰処理がされているかどうか

まず、再帰処理がうまく説明できません。

「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典 再帰処理

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

実際に、再帰処理の有無で動作が違うarray_merge_recursivearray_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が消えています。

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

フレームワークにもあるよ

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

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

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 ヘルパ

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

参考記事

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

本当に使える!PHPerなら知っておきたい便利な配列関数79選!! ver.2015

おわりに

流石に、配列関数82個は読むのが大変でした。(流し読みでも!)

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

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

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

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away