PHP初心者必見！エラーを防ぐために知っておくべき10のコーディングポイント！＋おまけ8

## はじめに

PHP は柔軟な言語ですが、書き方によっては `Notice` や `Warning` などのエラーが発生しやすくなります。
これらのエラーはコードの品質を低下させ、予期せぬバグの原因になることがあります。
本記事では、PHP で `Notice` や `Warning` を回避するために注意すべきコーディングのポイントを紹介します。

## 対象読者

- PHP を使い始めたばかりの初心者エンジニア
- PHP のエラーハンドリングに慣れていないエンジニア
- Notice や Warning エラーを減らし、安定したコードを作成したい方

## 事前準備

- 基本的な PHP の構文に慣れていること
- `error_reporting` と `display_errors` 設定の理解があること（開発環境でのエラーメッセージの表示に役立つ）

---

## 1. 未定義の変数を使用しない

### ❌ よくある間違い
```php
$sum = $a + $b; // $a, $b が未定義だと Notice 発生
```

### ✅ 解決策
- 変数を事前に定義する。
- `isset()` で存在チェックを行う。
- `null合体演算子（??）` を活用する。

```php
$a = 10;
$b = 20;
$sum = $a + $b;
```

```php
$sum = ($a ?? 0) + ($b ?? 0);
```

## 2. 配列のキー存在チェック

### ❌ よくある間違い
```php
echo $data['name']; // 'name' キーが未定義の場合、Notice 発生
```

### ✅ 解決策
- `isset()` または `array_key_exists()` を使用する。

```php
echo isset($data['name']) ? $data['name'] : 'デフォルト値';
```

```php
echo $data['name'] ?? 'デフォルト値';
```

## 3. ファイルの存在チェック

### ❌ よくある間違い
```php
$contents = file_get_contents('non_existent_file.txt'); // Warning 発生
```

### ✅ 解決策
- `file_exists()` で事前にチェックする。

```php
if (file_exists('non_existent_file.txt')) {
    $contents = file_get_contents('non_existent_file.txt');
} else {
    echo 'ファイルが見つかりません';
}
```

## 4. `include` や `require` のエラーハンドリング

### ❌ よくある間違い
```php
include 'config.php'; // ファイルが存在しない場合、Warning 発生
```

### ✅ 解決策
- `file_exists()` でチェックする。
- `@` 演算子は使用せず、適切な例外処理を行う。

```php
$file = 'config.php';
if (file_exists($file)) {
    include $file;
} else {
    echo '設定ファイルが見つかりません';
}
```

## 5. `foreach` で未定義の変数を使わない

### ❌ よくある間違い
```php
foreach ($items as $item) { // $items が未定義の場合、Warning 発生
    echo $item;
}
```

### ✅ 解決策
- `is_array()` または `empty()` でチェックする。

```php
if (!empty($items) && is_array($items)) {
    foreach ($items as $item) {
        echo $item;
    }
}
```

## 6. 関数の戻り値を適切にチェックする

### ❌ よくある間違い
```php
$result = some_function();
if ($result) {
    echo '成功';
} else {
    echo '失敗';
}
```

このコードでは、関数 `some_function()` が `false` や `null` を返す場合に期待通りに動作しない可能性があります。

### ✅ 解決策
- 厳密な型チェックを行う。
- `===` を使用する。

```php
$result = some_function();
if ($result !== false && $result !== null) {
    echo '成功';
} else {
    echo '失敗';
}
```

## 7. デフォルトのタイムゾーンを設定する

### ❌ よくある間違い
```php
echo date('Y-m-d H:i:s'); // タイムゾーンが未設定だと Warning 発生
```

### ✅ 解決策
- `date_default_timezone_set()` を使用する。

```php
date_default_timezone_set('Asia/Tokyo');
echo date('Y-m-d H:i:s');
```

## 8. `error_reporting` の適切な設定

開発環境では `E_ALL` を設定し、すべてのエラーを検出できるようにします。

```php
error_reporting(E_ALL);
ini_set('display_errors', 1);
```

本番環境ではエラーメッセージを表示せず、ログに記録するようにします。

```php
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/path/to/error.log');
```

## 9. 変数のスコープに注意する

### ❌ よくある間違い
```php
function example() {
    $x = 10;
}
echo $x; // Notice: Undefined variable
```

### ✅ 解決策
- 関数内の変数はローカルスコープなので外からは参照できません。
- 変数を返す、またはグローバル変数を使う。

---

## 10. 配列の要素にアクセスする際のインデックスの型に注意する

### ❌ よくある間違い
```php
$data = array('a' => 1, 'b' => 2);
echo $data[1]; // Notice: Undefined index
```

### ✅ 解決策
- 正しいキーでアクセスする。

```php
echo $data['a']; // 正しいキーでアクセス
```

---

## 11. 数値の除算におけるゼロ除算のエラー

### ❌ よくある間違い
```php
$div = 10 / 0; // Warning: Division by zero
```

### ✅ 解決策
- 除算前にゼロチェックを行う。

```php
if ($b != 0) {
    $div = $a / $b;
} else {
    echo 'ゼロ除算エラー';
}
```

---

## 12. リソース型を正しく扱う

### ❌ よくある間違い
```php
$file = fopen('file.txt', 'r');
fclose($file);  // fclose でファイルポインタを閉じる前にエラーが発生した場合、Warning 発生
```

### ✅ 解決策
- エラーハンドリングを行い、リソースが正常にオープンされたかを確認する。

```php
$file = fopen('file.txt', 'r');
if ($file) {
    fclose($file);
} else {
    echo 'ファイルオープンエラー';
}
```

---

## 13. NULL の比較に注意する

### ❌ よくある間違い
```php
$value = null;
if ($value == '0') { // Notice: Trying to compare null with string
    echo '一致';
}
```

### ✅ 解決策
- `===` 演算子を使用して、型と値を厳密に比較する。

```php
if ($value === null) {
    echo 'nullと一致';
}
```

---

## 14. `empty()` の使い方

### ❌ よくある間違い
```php
if (empty($data['key'])) {  // Warning if $data is not set
    echo 'キーが空';
}
```

### ✅ 解決策
- `isset()` で存在を確認した後、`empty()` を使う。

```php
if (isset($data['key']) && empty($data['key'])) {
    echo 'キーが空';
}
```

---

## 15. `filter_var()` の使用

### ❌ よくある間違い
```php
$email = 'invalid_email';
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {  // Warning 発生
    echo '有効なメールアドレス';
}
```

### ✅ 解決策
- `filter_var()` の戻り値を明示的に確認する。

```php
if (filter_var($email, FILTER_VALIDATE_EMAIL) !== false) {
    echo '有効なメールアドレス';
} else {
    echo '無効なメールアドレス';
}
```

---

## 16. `unset()` した変数を参照しない

### ❌ よくある間違い
```php
unset($x);
echo $x;  // Notice: Undefined variable
```

### ✅ 解決策
- `unset()` 後はその変数にアクセスしない。

```php
unset($x);
if (isset($x)) {
    echo $x;
} else {
    echo '変数はunsetされました';
}
```

---

## 17. 定義されていないクラスやメソッドの呼び出しを避ける

### ❌ よくある間違い
```php
$object = new MyClass();
$object->someMethod(); // Fatal error: Uncaught Error: Call to a member function
```

### ✅ 解決策
- クラスが存在するかを確認してからインスタンス化する。

```php
if (class_exists('MyClass')) {
    $object = new MyClass();
    $object->someMethod();
} else {
    echo 'クラスが存在しません';
}
```

---

## 18. ループでの不必要な変数再定義を避ける

### ❌ よくある間違い
```php
foreach ($array as $item) {
    $sum = 0;
    $sum += $item;
}
```

### ✅ 解決策
- ループ外で初期化して、無駄な再定義を避ける。

```php
$sum = 0;
foreach ($array as $item) {
    $sum += $item;
}
```

---

## まとめ

PHP では `Notice` や `Warning` を適切に回避するためには、変数の初期化、型の一致、適切なエラーハンドリングが重要です。
記事で紹介した方法を実践し、安定したコードを書くために役立ててください:wink: