9.

PHP の配列|添字と連想配列・主要関数・in_array の落とし穴

編集
この記事の要点
  • PHP の配列は添字配列と連想配列が同じ型。実体は「順序付きハッシュマップ」
  • 書き方は []array() でも同じだが、いまは短縮記法が標準
  • 代入するとコピーされる。オブジェクトと違い、渡した先の変更が元に響かない
  • キーは intstring のみ。"1"1 に、true1 に、null"" に変換される
  • in_array()array_search()第 3 引数 true で厳密比較にする

作り方

// 添字配列(キーは 0 から自動採番)
$fruits = ['りんご', 'みかん', 'ぶどう'];
echo $fruits[0];              // りんご

// 連想配列
$user = [
    'name'  => '田中',
    'age'   => 30,
    'admin' => false,        // 末尾のカンマを残せる
];
echo $user['name'];           // 田中

// 混在もできる(同じ型なので)
$mixed = [0 => 'a', 'key' => 'b', 5 => 'c'];

// 多次元
$rows = [
    ['id' => 1, 'name' => '田中'],
    ['id' => 2, 'name' => '鈴木'],
];
echo $rows[1]['name'];        // 鈴木

$old = array('a', 'b');       // 古い書き方。動くが [] を使う

追加・更新・削除

$a = ['x'];

$a[] = 'y';                   // 末尾に追加(最も速い)
$a[10] = 'z';                 // キーを指定して追加
$a[] = 'w';                   // 次は 11 になる(最大の数値キー + 1)
array_push($a, 'v', 'u');     // 複数まとめて

$a[0] = 'X';                  // 更新

unset($a[0]);                 // 削除(キーは詰められない)
print_r(array_values($a));    // 詰め直したいときは array_values

$first = array_shift($a);     // 先頭を取り出す(以降のキーが振り直される)
$last  = array_pop($a);       // 末尾を取り出す
array_unshift($a, 'head');    // 先頭に追加

unset()キーを詰めません[0 => 'a', 2 => 'c'] のような穴あきになるため、JSON にすると配列ではなくオブジェクトとして出力されます。連番であることが必要なら array_values() を通してください。

キーの型変換ルール

$a = [];
$a["1"]   = 'a';      // int 1 になる
$a[1.9]   = 'b';      // 切り捨てられて int 1 → 上書き
$a[true]  = 'c';      // int 1 → 上書き
$a[null]  = 'd';      // "" (空文字)
$a["01"]  = 'e';      // "01" は数値扱いされない → 文字列キーのまま
var_dump($a);
// [1 => 'c', "" => 'd', "01" => 'e']

郵便番号や商品コードのように先頭が 0 の文字列はそのまま残りますが、"1" のような数値文字列は整数キーに変換されます。ID をキーにするときは、この違いで === の比較が食い違うことがあります。

ループ

foreach ($fruits as $fruit) {
    echo $fruit;
}

foreach ($user as $key => $value) {
    echo "{$key}: {$value}";
}

// 多次元は分割代入で受けられる
foreach ($rows as ['id' => $id, 'name' => $name]) {
    echo "{$id}: {$name}";
}

// 値を書き換えたいときは参照。使い終わったら必ず unset
foreach ($fruits as &$f) { $f = "【{$f}】"; }
unset($f);

for ($i = 0, $n = count($fruits); $i < $n; $i++) {
    echo $fruits[$i];         // 連番のときだけ使える
}

よく使う関数

やりたいこと関数
件数を数えるcount($a)
キーだけ / 値だけ取り出すarray_keys() / array_values()
各要素を変換するarray_map()
条件で絞り込むarray_filter()
1 つの値にまとめるarray_reduce() / array_sum()
含まれているかin_array() / array_search()
キーがあるかarray_key_exists() / isset()
並べ替えsort() usort() ksort() asort()
重複を除くarray_unique()
結合するarray_merge() / [...$a, ...$b]
一部を切り出すarray_slice()
文字列にする / 分けるimplode() / explode()
$nums = [1, 2, 3, 4, 5];

print_r(array_map(fn($n) => $n * 10, $nums));        // [10,20,30,40,50]
print_r(array_filter($nums, fn($n) => $n % 2 === 0)); // [1=>2, 3=>4] キーは保たれる
echo array_sum($nums);                                 // 15
echo implode(', ', $nums);                             // 1, 2, 3, 4, 5

// 連想配列から特定の列だけ抜き出す
print_r(array_column($rows, 'name'));                  // ['田中','鈴木']
print_r(array_column($rows, 'name', 'id'));            // [1=>'田中', 2=>'鈴木']

array_filter() はキーを保ちます。そのまま json_encode() すると配列ではなくオブジェクトになるため、必要なら array_values() を通します。

結合の 2 種類

$a = ['x' => 1, 'y' => 2];
$b = ['y' => 99, 'z' => 3];

print_r(array_merge($a, $b));   // ['x'=>1, 'y'=>99, 'z'=>3]  後ろが勝つ
print_r($a + $b);               // ['x'=>1, 'y'=>2,  'z'=>3]  前が勝つ

// 数値キーの扱いが違う
print_r(array_merge([1, 2], [3]));   // [1, 2, 3]      振り直される
print_r([1, 2] + [3, 4, 5]);         // [1, 2, 5]      キー 0,1 は前が勝つ

設定値に既定値を当てるときは $config + $defaults、リストを繋げるときは array_merge()、と覚えると迷いません。

比較・検索の落とし穴

$a = ['1', '2', '3'];

var_dump(in_array(1, $a));          // true   ← 型を無視して比較している
var_dump(in_array(1, $a, true));    // false  厳密比較

var_dump(array_search('2', $a));       // int(1)
var_dump(array_search('x', $a));       // false
// 0 が返る場合と false が返る場合を == で区別できない
if (array_search('1', $a) !== false) { /* 見つかった */ }

// 配列同士の比較
var_dump([1,2] == [1,2]);           // true   同じキーと値
var_dump([1,2] === [1,2]);          // true   順序と型も同じ
var_dump(['a'=>1,'b'=>2] === ['b'=>2,'a'=>1]);  // false  順序が違う
var_dump(['a'=>1,'b'=>2] ==  ['b'=>2,'a'=>1]);  // true   == なら順序を見ない

in_array() の第 3 引数は必ず true にするのが安全です。省略すると in_array(0, ['abc']) のような判定が PHP のバージョンによって変わります。

配列とオブジェクトの変換

$obj = (object)['name' => '田中'];   // 配列 → stdClass
echo $obj->name;

$arr = (array)$obj;                   // オブジェクト → 配列
print_r($arr);

$json = json_encode($user, JSON_UNESCAPED_UNICODE);
$back = json_decode($json, true);     // true で連想配列として受け取る

詳細は オブジェクトを配列に変換する方法 を参照してください。

関連

編集
Post Share
子ページ
  1. オブジェクトを配列に変換する方法
同階層のページ
  1. 基本事項
  2. HTMLへの埋め込み
  3. 変数
  4. 可変変数
  5. 定数
  6. データ型
  7. キャスト
  8. エスケープ文字
  9. 配列
  10. 演算子
  11. 代入の際の注意点
  12. 条件分岐
  13. 繰り返し処理
  14. クラスとインスタンス
  15. コンストラクタ
  16. 関数
  17. スーパーグローバル変数
  18. スコープ
  19. staticについて
  20. yieldについて
  21. ファイルのアップロード方法
  22. DB接続方法
  23. SQL実行方法
  24. カプセル化の具体例
  25. 継承の構文
  26. オーバーライド
  27. ポリモーフィズム(多様性)の具体例
  28. 抽象クラス・メソッドの構文と具体例
  29. GET通信
  30. try catchで全てのエラーを拾う方法

最近更新/作成されたページ