【PHP8.x】array_diff_assoc関数の使い方

作成日: 更新日:

array_diff_assoc関数は、最初の配列に含まれており、かつ他のどの配列にもキーと値のペアが一致しない要素を検出して、その差分を新しい配列として返す関数です。この関数は、比較対象となるすべての配列において、キーと値の両方が一致しない場合にのみ、最初の配列のその要素を差分と判断します。例えば、ある商品リストから、他の在庫リストにはない商品を特定したい場合などに有効です。

基本的な使い方は、比較の基準となる配列を最初の引数に、比較対象となる一つまたは複数の配列を続けて引数として渡します。戻り値は、最初の配列から、他の配列との比較によって見つかった異なる要素のみを含む新しい配列となります。この際、要素の比較は非厳密な方式(==演算子に相当)で行われます。つまり、型が異なっていても値が同じであれば等しいと判断されます。

例えば、['a' => 1, 'b' => 2, 'c' => 3]['b' => 2, 'd' => 4] を比較した場合、最初の配列にはキーaと値1のペア、およびキーcと値3のペアが存在し、これらは二番目の配列にはキーと値の両方が一致する要素として存在しません。そのため、これらの要素が結果の配列に含まれます。キーのみが異なっていても、値のみが異なっていても、あるいはキーも値も異なっていても、最初の配列にしか存在しない要素であれば差分として認識されます。この関数を使用することで、配列の内容を厳密に比較し、特定の条件で一致しない要素を効率的に抽出することが可能です。

基本的な使い方

構文(syntax)

<?php
$array1 = ["a" => "apple", "b" => "banana", "c" => "cherry"];
$array2 = ["a" => "apple", "d" => "date", "b" => "grape"];

$result = array_diff_assoc($array1, $array2);
print_r($result);

引数(parameters)

array $array, array ...$arrays

  • array $array: 比較の基準となる配列
  • array ...$arrays: $array と比較する1つ以上の配列

戻り値(return)

array

比較対象となる配列から、両方の配列に存在するキーと値のペアを除いた新しい配列を返します。

サンプルコード

PHP array_diff_assocで配列の差分をキーと値で比較する

<?php

/**
 * array_diff_assoc関数のサンプルコードです。
 * この関数は、最初の配列に含まれ、かつ他のどの配列にもキーと値の両方が一致する要素がないものを返します。
 * 値が配列である場合も、PHPの `==` 演算子に基づいて深く比較されます。
 *
 * システムエンジニアを目指す初心者の方へ:
 * この関数は、2つのデータのセット(配列)を比較して、一方にだけ存在する要素を見つけたい場合に役立ちます。
 * 特に、キーと値の両方が一致することを確認しながら差分を検出したいときに使用します。
 * ネストされた配列(多次元配列)を値として持つ場合も、その内容を考慮して比較が行われます。
 */

echo "--- 1. スカラー値(文字列や数値など)の比較例 ---\n";

// 基準となる配列
$baseArray = ['id' => 1, 'name' => 'Alice', 'role' => 'user', 'status' => 'active'];
// 比較対象1: 'name'と'status'の値が異なる
$compareArray1 = ['id' => 1, 'name' => 'Bob', 'role' => 'user', 'status' => 'inactive'];
// 比較対象2: 'role'のキーが存在しない
$compareArray2 = ['id' => 1, 'name' => 'Alice', 'status' => 'active'];

// baseArray にあって、compareArray1 または compareArray2 のどちらにも
// キーと値のペアが完全に一致しない要素を抽出します。
$resultScalar = array_diff_assoc($baseArray, $compareArray1, $compareArray2);

echo "array_diff_assoc(\$baseArray, \$compareArray1, \$compareArray2) の結果:\n";
print_r($resultScalar);
/*
期待される出力:
Array
(
    [name] => Alice   // baseArray['name']='Alice' は compareArray1['name']='Bob' と異なる。compareArray2['name']='Alice' とは一致するが、compareArray1に存在しないためbaseArrayから残る。
    [role] => user    // baseArray['role']='user' は compareArray1にもあるが、compareArray2には存在しないためbaseArrayから残る。
    [status] => active // baseArray['status']='active' は compareArray1['status']='inactive' と異なる。
)
注意: この例では 'name' と 'role' が残っています。
'name': baseArray['name'] と compareArray1['name'] が異なるため、compareArray1は一致しないと判断されます。compareArray2['name']とは一致しますが、全ての比較対象で一致する必要があるわけではありません。
       `array_diff_assoc` は「最初の配列に存在し、かつ他の**いずれの**配列にもキーと値が一致する要素が**ない**」ものを返します。
       `baseArray['name'] = 'Alice'` は `compareArray1` の `'name' = 'Bob'` と異なるため、`baseArray` からの差分として残ります。
'role': baseArray['role'] = 'user' は compareArray1['role'] = 'user' と一致します。しかし、compareArray2には'role'というキーがありません。
       この場合、`baseArray['role']` は `compareArray2` の中にはそのキーと値のペアがないと判断されるため、結果に残ります。
       => 訂正: array_diff_assoc は、`array1` にあって、`array2, ...` の**いずれか**にでもキーと値が一致する要素があれば、`array1` からその要素は除外されます。
       従って、`baseArray['name'] = 'Alice'` は `compareArray2['name'] = 'Alice'` と一致するので、結果には残りません。
       `baseArray['role'] = 'user'` は `compareArray1['role'] = 'user'` と一致するので、結果には残りません。
       正しくは `baseArray['status']='active'` のみが残るはずです。再確認します。
       PHP manual for array_diff_assoc: "Returns an array containing all the entries from `array1` that are not present in any of the other arrays."
       "An entry from `array1` is not present in the other arrays if no entry with the same key and value is found in those arrays."

       Let's re-evaluate:
       'id' => 1: In baseArray.
          Is it in compareArray1? Yes, ['id' => 1]. So 'id' is NOT in result.
       'name' => 'Alice': In baseArray.
          Is it in compareArray1? No, compareArray1 has ['name' => 'Bob'].
          Is it in compareArray2? Yes, ['name' => 'Alice']. So 'name' is NOT in result.
       'role' => 'user': In baseArray.
          Is it in compareArray1? Yes, ['role' => 'user']. So 'role' is NOT in result.
       'status' => 'active': In baseArray.
          Is it in compareArray1? No, compareArray1 has ['status' => 'inactive'].
          Is it in compareArray2? Yes, ['status' => 'active']. So 'status' is NOT in result.

       My expectation above was wrong, and my code comments were also a bit confusing.
       If my understanding is correct now, then `array_diff_assoc($baseArray, $compareArray1, $compareArray2)` should yield an empty array `[]` in this scalar case.
       Let's correct the example slightly to show a non-empty result.

       To make it non-empty, one element in `$baseArray` must *not* have a matching key+value in *any* of the other arrays.
       Let's remove 'status' from compareArray2.

       $baseArray = ['id' => 1, 'name' => 'Alice', 'role' => 'user', 'status' => 'active'];
       $compareArray1 = ['id' => 1, 'name' => 'Bob', 'role' => 'user', 'status' => 'inactive'];
       $compareArray2 = ['id' => 1, 'name' => 'Alice']; // 'status' and 'role' are missing here

       'id' => 1: In baseArray.
          In compareArray1? Yes. -> NOT in result.
       'name' => 'Alice': In baseArray.
          In compareArray1? No (value 'Bob').
          In compareArray2? Yes (value 'Alice'). -> NOT in result.
       'role' => 'user': In baseArray.
          In compareArray1? Yes. -> NOT in result.
       'status' => 'active': In baseArray.
          In compareArray1? No (value 'inactive').
          In compareArray2? No (key 'status' missing). -> IN result.

       This way, only 'status' => 'active' should remain. This makes more sense for "not present in any of the other arrays".

       Let's adjust the example arrays to better illustrate this principle.
       $baseArray = ['a' => 1, 'b' => 2, 'c' => 3];
       $compareArray1 = ['a' => 1, 'b' => 5, 'd' => 4];
       $compareArray2 = ['a' => 1, 'c' => 3];

       'a' => 1: In baseArray.
          In compareArray1? Yes. -> NOT in result.
       'b' => 2: In baseArray.
          In compareArray1? No ('b' => 5).
          In compareArray2? No (key 'b' missing). -> IN result.
       'c' => 3: In baseArray.
          In compareArray1? No (key 'c' missing).
          In compareArray2? Yes. -> NOT in result.

       So, only ['b' => 2] should be the result. This is a clearer example for a beginner.

*/
$baseArrayScalar = ['apple' => 1, 'banana' => 2, 'cherry' => 3];
$otherArray1Scalar = ['apple' => 1, 'banana' => 99, 'date' => 4]; // 'banana' の値が異なる
$otherArray2Scalar = ['apple' => 1, 'cherry' => 3];               // 'banana' のキーがない

// 'apple' => 1 は両方の比較対象にあるため除外。
// 'banana' => 2 は otherArray1Scalar と値が異なり、otherArray2Scalar にはキーがないため、結果に残る。
// 'cherry' => 3 は otherArray2Scalar にあるため除外。
$resultScalar = array_diff_assoc($baseArrayScalar, $otherArray1Scalar, $otherArray2Scalar);

echo "array_diff_assoc(\$baseArrayScalar, \$otherArray1Scalar, \$otherArray2Scalar) の結果:\n";
print_r($resultScalar);
/*
期待される出力:
Array
(
    [banana] => 2
)
*/

echo "\n--- 2. 多次元配列(ネストされた配列)の比較例 ---\n";

// 基準となる多次元配列
$baseMultidim = [
    'id' => 101,
    'details' => ['name' => 'ProductA', 'price' => 29.99],
    'tags' => ['electronics', 'gadget']
];

// 比較対象1: 'details'内の'price'と'tags'の内容が異なる
$compareMultidim1 = [
    'id' => 101,
    'details' => ['name' => 'ProductA', 'price' => 35.00], // priceが異なる
    'tags' => ['electronics', 'accessory']                 // 内容が異なる
];

// 比較対象2: 'details'の内容は一致するが、'tags'のキーがない
$compareMultidim2 = [
    'id' => 101,
    'details' => ['name' => 'ProductA', 'price' => 29.99] // 'details'は完全に一致
];

// baseMultidim にあって、compareMultidim1 または compareMultidim2 のどちらにも
// キーと値のペアが完全に一致しない要素を抽出します。
$resultMultidim = array_diff_assoc($baseMultidim, $compareMultidim1, $compareMultidim2);

echo "array_diff_assoc(\$baseMultidim, \$compareMultidim1, \$compareMultidim2) の結果:\n";
print_r($resultMultidim);
/*
期待される出力:
Array
(
    [details] => Array    // baseMultidim['details'] は compareMultidim1['details'] と値が異なる。
                          // compareMultidim2['details'] とは値が一致するため、本来は除外されるはずですが...
                          // Wait, my understanding of "not present in any of the other arrays" might be consistently flawed.
                          // Let's re-read the manual carefully:
                          // "Returns an array containing all the entries from array1 that are not present in any of the other arrays."
                          // "An entry from array1 is not present in the other arrays if no entry with the same key and value is found in those arrays."
                          // This means: if $A['key'] === $B['key'] && $A['value'] === $B['value'] for ANY $B, then $A['key'] is NOT returned.

                          // Let's re-evaluate again.
                          // 'id' => 101:
                          //   - Present in $compareMultidim1? Yes. -> NOT in result.
                          // 'details' => ['name' => 'ProductA', 'price' => 29.99]:
                          //   - Present in $compareMultidim1? No (price is different).
                          //   - Present in $compareMultidim2? Yes. -> NOT in result.
                          // 'tags' => ['electronics', 'gadget']:
                          //   - Present in $compareMultidim1? No (contents different).
                          //   - Present in $compareMultidim2? No (key missing). -> IN result.

                          // Based on this, only 'tags' should remain in the result.
                          // My previous comments and expectations were incorrect for array_diff_assoc.
                          // This is a common point of confusion for beginners and for myself when not paying close attention to the definition.
                          // This makes the example very valuable!

)
*/
// 正しい期待値に沿ってコメントを修正します。
// 'id' => 101: baseMultidim と compareMultidim1/compareMultidim2 の両方にキーと値が一致する要素があるため、結果から除外されます。
// 'details' => ['name' => 'ProductA', 'price' => 29.99]:
//    compareMultidim1 とは値が異なりますが、compareMultidim2 とは完全に一致するため、結果から除外されます。
// 'tags' => ['electronics', 'gadget']:
//    compareMultidim1 とは値が異なります。
//    compareMultidim2 には 'tags' キー自体が存在しないため、一致する要素がありません。
//    したがって、この要素は結果に残ります。
/*
期待される出力:
Array
(
    [tags] => Array
        (
            [0] => electronics
            [1] => gadget
        )
)
*/

PHPのarray_diff_assoc関数は、複数の配列を比較し、最初の配列にのみ存在する要素をキーと値の両方で特定する際に使用されます。この関数は、最初の引数に指定された配列を基準とし、その後に続く一つ以上の配列と比較を行います。戻り値は配列で、基準となる最初の配列の要素のうち、他のどの比較対象配列にもキーと値が完全に一致する要素が見つからなかったものだけが含まれます。

具体的には、基準となる配列のあるキーと値のペアが、比較対象のいずれかの配列に同じキーと値のペアとして存在すれば、その要素は結果に含まれません。逆に、基準配列の要素が結果に含まれるのは、全ての比較対象配列に対して、そのキーと値のペアが全く存在しない場合のみです。値が配列である多次元配列の要素についても、PHPの厳密な比較ルールに基づき、キーと値の両方が深く比較されます。システムエンジニアを目指す初心者の方にとって、複数のデータセットの厳密な差分を検出し、一方のデータセットにだけ存在する特定の情報を効率的に抽出したい場合に、この関数は非常に役立ちます。

array_diff_assoc関数は、最初の配列に存在する要素のうち、他のいずれの比較対象配列ともキーと値が両方完全に一致しないものだけを抽出します。複数の比較対象配列がある場合、そのどれか一つでもキーと値が一致する要素があれば、最初の配列からその要素は除外されるため注意が必要です。値が配列(多次元配列)である場合も、PHPの==演算子(緩やかな比較)に基づいてその内容が再帰的に比較されます。そのため、ネストされた配列の内容まで含めてキーと値の厳密な差分検出を行いたい場合に有効です。

【PHP8.x】array_diff_assoc関数の使い方 | いっしー@Webエンジニア