array_key_exists('key', $array)は、配列にそのキーがあればtrueを、なければfalseを返します。順番に注意してください。キーが先で、配列が後です。キーの下に格納された値がnullでもtrueを返し、これがisset()にはできない唯一のことです。
キーではなく値を確認するには、in_array()を使います。
array_key_existsとissetの違い
どちらもキーを確認します。意見が分かれるのは値がnullのときだけです。isset()はnullの値を「設定されていない」として扱い、array_key_exists()は配列に実際にあるものを報告します。
0と''はどちらでも設定済みとみなされ、違いが出るのはnullだけです。どちらを使うかは、データの中でnullが何を意味するかで決まります。
nullが「値がない」を意味するならisset()を使います。これがよくあるケースで、言語構造なので(少し速く)、ネストしたパスや未定義の変数も警告なしで受け付けます。nullが、存在しないキーと区別すべき本当の値ならarray_key_exists()を使います。nullとして送られたJSONのフィールド、NULLであるデータベースのカラム、クリアするために明示的にnullにしたオプションなどです。
複数の変数を一度に確認する方法など、ほかの使い方はissetのページで扱っています。
JSONのペイロードでnullと欠落を区別する
array_key_exists()だけが正しい答えを出す典型的なケースです。JSONからレコードを更新するAPIでは、nullとして送られたフィールドは「クリアする」、省かれたフィールドは「触らない」を意味します。isset()には両方が同じに見えます。
isset($patch[$field])だと、nullが欠落したフィールドに見えるので、電話番号は残ってしまいます。
key_exists()は同じ関数
key_exists()は初期のPHPから残っているarray_key_exists()の別名です。引数も結果も同じです。読む人が目にすると予想している、完全な名前のほうを使いましょう。
キーの型:"1"と1は同じキー
配列のキーは整数か文字列で、単純な10進数の整数を表す文字列は整数として保存されます。そのためarray_key_exists('1', $arr)はキー1を見つけ、その逆も同じです。'01'のような文字列は文字列のままで、別のキーです。
ネストしたキーと複数のキーを確認する
array_key_exists()が見るのは1つの階層です。nullが問題にならないネストしたパスなら、isset($a['x']['y'])がすべての階層を一度に確認します。問題になるパスなら、短いヘルパー関数で階層をたどります。複数のキーがすべて存在するかを確認するには、array_diff_key()と比較します。
array_flip($required)は名前のリストをキーに変えるので、array_diff_key()で入力のキーと比較できます。残ったものが足りないフィールドのリストで、そのままエラーメッセージに使えます。
オブジェクトにはproperty_existsが必要
古いPHPはarray_key_exists()にオブジェクトを受け付けていました。PHP 8では代わりにTypeErrorが投げられます。オブジェクトには、宣言済みまたは動的なプロパティを(nullに設定されていても)確認するproperty_exists()を使い、isset($obj->prop)は配列に対するisset()と同じように動きます。
最後の2行はもう1つの方法を示しています。get_object_vars()はオブジェクトのアクセス可能なプロパティを配列にするので、そのあとは配列の関数が使えます。
よくある質問
array_key_existsがtrueを返すのにissetがfalseを返すのはなぜですか?
キーにnullが入っているからです。isset($arr['k'])はキーが存在して値がnullでないときだけtrueですが、array_key_exists('k', $arr)はキーが配列にあれば常にtrueです。0、''、falseを含むそれ以外の値なら、どちらも同じ答えを返します。
PHPのkey_existsとは何ですか?
array_key_exists()の別名です。key_exists('id', $row)とarray_key_exists('id', $row)は同じ動きをします。ほとんどのコードは長いほうの名前を使います。
PHPでネストしたキーが存在するか確認するには?
各階層を確認します。isset($data['user']['address']['city'])はパス全体を一度に確認し、途中の階層が欠けていても警告を出しません。nullの値も存在するとみなす必要があるなら、array_key_exists()で階層ごとにたどります。
オブジェクトにarray_key_existsを使えますか?
使えません。PHP 8.0以降、オブジェクトを渡すとTypeErrorが投げられます。宣言されたプロパティにはproperty_exists($obj, 'name')を使うか、isset($obj->name)を使います。