PHP の ksort
や array_filter
を使っていて整数キーを与えた配列をループさせた際のインデックスで少し戸惑ったのでメモ
環境
PHP v8.2.0
tehplayground.com 環境でテスト
PHP の配列のキーとインデックスは同じ整数でも別物
配列
key
は、整数 または 文字列です。 value には任意の型を指定できます。
PHP においては添字配列と連想配列の間に違いはなく、配列型は 1 つだけで、 同じ配列で整数のインデックスと文字列のインデックスを同時に使えます。
cf. PHP: 配列 - Manual
意図的に整数のキーを与えてもインデックスとは別にキーが保持されている
配列をループで回す際はあくまで インデックス の順番に取り出される
<?php function key_index(array $arr) { $index = 0; foreach($arr as $key => $item) { echo "{$index} - {$key}: {$item}\n"; $index+=1; } } key_index(['Ichigo', 'Aoi', 'Ran']); // 0 - 0: Ichigo // 1 - 1: Aoi // 2 - 2: Ran key_index([0 => 'Ichigo', 1 => 'Aoi', 3 => 'Ran']); // 0 - 0: Ichigo // 1 - 1: Aoi // 2 - 2: Ran // キーはあくまでキー key_index([1 => 'Akari', 3 => 'Sumire', 5 => 'Hinaki']); // 0 - 1: Akari // 1 - 3: Sumire // 2 - 5: Hinaki // キーとインデックスは別物なのでキーが整数でもインデックス順になっている key_index([5 => 'Shion', 3 => 'Otome', 4 => 'Sakura']); // 0 - 5: Shion // 1 - 3: Otome // 2 - 4: Sakura
array_search
で取得できるのはキー
<?php $arr = [1 => 'Akari', 3 => 'Sumire', 5 => 'Hinaki']; array_search('Akari', $arr, true); // => 1
array-slice
, array-splice
の位置指定はインデックス
array-slice
<?php $arr = [ 1 => 'Akari', 0 => 'Ichigo', 5 => 'Hinaki', 4 => 'Ran', 2 => 'Aoi', 3 => 'Sumire' ]; array_slice($arr, 1, 3); // array(3) { // [0]=> "Ichigo" // [1]=> "Hinaki" // [2]=> "Ran" // } // key を維持する場合は第三引数を true にする array_slice($arr, 1, 3, true); // array(3) { // [0]=> "Ichigo" // [5]=> "Hinaki" // [4]=> "Ran" // }
array-splice
array_splice はキーが整数の場合は振り直される
<?php $arr = [3 => 'Akari', 2 => 'Sumire', 1 => 'Hinaki']; array_splice($arr, 1, 0, 'Mizuki'); var_dump($arr); // array(4) { // [0]=> "Akari" // [1]=> "Mizuki" // [2]=> "Sumire" // [3]=> "Hinaki" // } $arr = ['a' => 'Ichigo', 'b' => 'Aoi', 'c' => 'Ran']; array_splice($arr, 1, 0, 'Mizuki'); var_dump($arr); // array(4) { // ["a"]=> "Ichigo" // [0]=> "Mizuki" // ["b"]=> "Aoi" // ["c"]=> "Ran" // }
array_filter
は配列の要素をインデックスの順番に取り出して捜査し新しい配列を返すが元の配列のキーが維持される
新しい配列を返すのでキーが数値の場合インデックスに振り直されそうなイメージだったが元のキーが維持される
<?php $arr = [ 1 => 'Akari', 0 => 'Ichigo', 5 => 'Hinaki', 4 => 'Ran', 2 => 'Aoi', 3 => 'Sumire' ]; $newArray = array_map(fn($item) => "{$item}♡", $arr); var_dump($newArray); // array(6) { // [1]=> "Akari♡" // [0]=> "Ichigo♡" // [5]=> "Hinaki♡" // [4]=> "Ran♡" // [2]=> "Aoi♡" // [3]=> "Sumire♡" // } $soleil = ['Ichigo', 'Aoi', 'Ran']; $newArray = array_filter($arr, fn($item) => in_array($item, $soleil, true)); var_dump($newArray); // array(3) { // [0]=> "Ichigo" // [4]=> "Ran" // [2]=> "Aoi" // }
所感
PHP で配列を扱う際に、この位置に要素を入れたいと思って添字に整数を使って $array[n] = $item
としても配列のインデックスは別なのでループさせた際に添え字の順番で取得されない。意図的な添字の順にしたい場合は ksort
で意図的に並び替える必要がある。
キーにインデックスと同じ整数値を使えるので言語仕様を覚えておかないと意図しないバグを出してしまいそうだな〜と思いました。(JavaScript がゆるふわなだけ説あり…)
そういう意味でユニットテスト大切にしたい…です!!
[参考]
- PHP: is there difference between Index, Element, Key, Value of an Array?... are they the same thing? - Stack Overflow
- PHP: array_filter - Manual
- PHP: 配列 - Manual
- PHP: array_search - Manual
- PHP: array_slice - Manual
- PHP: array_splice - Manual
- PHPUnit テストコードの書き方【入門】 - RAKUS Developers Blog | ラクス エンジニアブログ