PHPとJavaScriptで未定義の配列のキーにアクセスしたときのエラーを防ぐ

未定義の配列のキーにアクセスしたときの判定処理です。
nullやundeined判定の記事はたくさんありますが、phpとjsの未定義の配列キーに関してまとめます。

# PHP:undefined array key 

未定義の配列のキーにアクセスしようとしたとき。
```array.php
$array = array('key1' => 'value1', 'key2' => 'value2');

echo $array['key1'];  // 出力: value1
echo $array['key3'];  // 警告: Undefined array key: key3
```
このときKey3は未定義なので、

:::note warn
Warning: Undefined array key: key3 in array.php on line ~
Warning: Trying to access array offset on value of type null in ~
:::

というようなエラーがphpのログに出るかと思います。
処理は継続されますが、その後の動作に影響を与える可能性があります。
PHP8から、このエラーはNoticeレベルからWarningとなりました。

### 判定処理
isset()やarray_key_exsit()を使います。
```array_judge.php
$array = array('key1' => 'value1', 'key2' => 'value2');

if (isset($array['key3'])) {
    echo $array['key3'];
} else {
    echo 'キーが存在しません';
}

// または

if (array_key_exists('key3', $array)) {
    echo $array['key3'];
} else {
    echo 'キーが存在しません';
}
```


### null判定→これはNG
後述するJSでの処理と混同しがちですが、null判定ではこのエラーは防げません。
```array_NG.php
if ($array['key3'] === null) {
    echo 'キーが存在しません';
} else {
    echo 'キーが存在します';
}
```
これはキーにアクセスしているのでエラーとなりますが、判定処理は可能です。
ちなみに、phpに` === undefined　`という判定はありません。

```NG.php
if (!$array['key3']) {
    echo '偽です';
} else {
    echo '真です';
}
```
これもだめです。要素がfalseの時はいいですが、未定義の場合、エラーが発生します。


# JavaScript:undefined
JSでは未定義の配列キーにアクセスするとundefinedとなります。処理は止まりません。
その後の処理に影響を与えるので、手前でエラー処理しておくのがいいでしょう。

```array1.js
var array = ['value1', 'value2'];

console.log(array[0]);  // 出力: value1
console.log(array[2]);  // 出力: undefined

// strictモードが有効な場合
'use strict';
console.log(array[0]);  // 出力: value1
console.log(array[2]);  // ReferenceError: array is not defined
```
>Strictモード（厳格モード）は、JavaScriptの実行コンテキスト内でコードをより厳密に解釈するためのモードです。Strictモードを有効にすると、いくつかの既存のJavaScriptの不具合や意図しない動作をエラーとして検出することができます。
by ChatGPT

### 判定処理
```judge.js
var array = ['value1', 'value2'];

if (array[2] === undefined) {
  console.log('要素は未定義です');
} 

//または
if (2 in array) {
  console.log(array[2]);
} else {
  console.log('要素が存在しません');
}

// または
if (array.hasOwnProperty(2)) {
  console.log(array[2]);
}else {
  console.log('要素が存在しません');
}
```

未定義の配列キーはundefinedなので、
```judge.js
if(array[2] == null ) {
    console.log('要素はnullまたはundefinedです');
}
```
:::note warn
==（等価演算子）は型の変換を行うため、nullもundefinedも判定は同じ。
~~これでも判定は可能だが、
配列の要素がfalseなどの偽の値である場合にも条件が真となってしまいます。~~
_コメントにてご指摘いただきました_
:::

### オブジェクトの場合
```object.js
var response = { name: 'Taro' };

if ('age' in response) {
  console.log(response.age);
} else {
  console.log('プロパティが存在しません');
}

// または

if (response.hasOwnProperty('age')) {
  console.log(response.age);
} else {
  console.log('プロパティが存在しません');
}
```

## nullとundefinedの判定（等価演算子と厳密等価演算子）
コメントに投稿いただいたこちらの記事がわかりやすいです。

http://nmi.jp/2022-10-17-Understanding-Undefined-And-Null

結果がnullの場合と、何もない（未定義）場合では、nullとundefinedの判定にどのような違いがあるのか、
==と===を比較。

```array.js
//要素がnull
var response1 = { result: null };
console.log(response1.result === null);  // 出力: true
console.log(response1.result === undefined);  // 出力: false

//未定義の場合
var response2 = { };
console.log(response2.result === null);  // 出力: false
console.log(response2.result === undefined);  // 出力: true
```
nullとundefinedでは型が違うので、===を使うときは、nullとundefinedの判定をわけるべき。

型判定しない場合↓
```array2.js
var response1 = { result: null };
console.log(response1.result == null);  // 出力: true
console.log(response1.result == undefined);  // 出力: true

var response2 = {};
console.log(response2.result == null);  // 出力: true
console.log(response2.result == undefined);  // 出力: true
```
どちらも同じ結果になりました。
~~上にも書いたように値がfalseの場合も、trueとなってしまうので、厳密比較したほうがいいでしょう。~~

## おまけ
以下の場合どうなるでしょう？
```NG.js
var array = ['value1', 'value2'];
if (!array[3]) {
    console.log('偽です');
} else {
    console.log('真です');
}
```
未定義なので、「偽です」とでます。
key3がnull の場合も[偽です]となります。
falseのときも「偽です」となるので、あいまい比較== と同じですね。
0のときも「偽です」となるので、注意が必要ですが、これのほうが便利ですね。
でもちゃんと厳密比較しましょう。