PHP発展編: 制御構造のよくある問題を回避しよう

制御構造はPHPプログラミングの根幹でありながら、複雑になるとバグや読みづらさの原因になりやすい重要なポイントです。
本記事は、独学エンジニアというサイトで学んだ内容をもとに、自分用の備忘録としてまとめました。


https://dokugaku-engineer.com/course/serverside

---

## **1. はじめに**

制御構造（条件分岐や繰り返し処理）はコードの中でも重要な部分でありながら、複雑になるとバグが発生しやすく、読みづらくなります。

そのため、制御構造はシンプルで読みやすく保つことが重要です。

---

## **2. よくある問題とその対策**

---

### **(1) 複雑な式**

### **問題:**

複雑な条件式は、コードを読んだ際に意図が分かりづらくなります。

```php
if ($userStatus === 'complete' && $userPayment === 'paid') {
    // 処理
}

```

### **対策:**

- **ブール変数** を使用する
    - 条件式の一部を変数に置き換えることで分かりやすくする。

```php
$isComplete = $userStatus === 'complete';
$isPaid = $userPayment === 'paid';

if ($isComplete && $isPaid) {
    // 処理
}

```

- **ブール関数** を使用する
    - 条件式を関数化し、意図を明確化する。

```php
function hasPaid($user) {
    return $user['payment'] === 'paid';
}

if (hasPaid($user)) {
    // 処理
}

```

---

### **(2) 否定的な論理式**

### **問題:**

否定的な論理式（`!`）は理解に時間がかかりやすい。

```php
if (!$isValid) {
    // 処理
}

```

### **対策:**

肯定的な論理式に書き換えることで、コードを直感的に理解しやすくする。

```php
if ($isValid) {
    // 処理
} else {
    // エラー処理
}

```

### **補足:** ドモルガンの法則

- 否定を含む複数条件式は、**ドモルガンの法則** を使ってシンプル化できます。

```php
// ドモルガンの法則を使う前
if (!($isComplete || $isPaid)) {
    // 処理
}

// ドモルガンの法則を使った後
if (!$isComplete && !$isPaid) {
    // 処理
}

```

---

### **(3) かっこのない複雑な論理式**

### **問題:**

条件式がかっこで明確に区切られていない場合、評価順序が分かりづらく、バグを生む可能性があります。

```php
if ($price > 50 && $price < 100) {
    // 処理
}

```

### **対策:**

かっこを使って評価順序を明示する。

```php
if (($price > 50) && ($price < 100)) {
    // 処理
}

```

---

### **(4) 数値を含む式の順序**

### **問題:**

数値の範囲を判定する式が分かりづらい。

```php
if ($min < $number && $number < $max) {
    // 処理
}

```

### **対策:**

数直線の順序に沿って記述することで、範囲のイメージを把握しやすくする。

```php
if ($min <= $number && $number <= $max) {
    // 処理
}

```

---

### **(5) 深いネスト**

### **問題:**

条件分岐やループのネストが深くなると、コードの可読性が著しく低下します。

```php
if ($condition1) {
    if ($condition2) {
        if ($condition3) {
            // 処理
        }
    }
}

```

### **対策:**

ネストを浅くする工夫を行う。

1. **条件を1つの式にまとめる**
    
    ```php
    if ($condition1 && $condition2 && $condition3) {
        // 処理
    }
    
    ```
    
2. **`if-else` の代わりに早期リターンを使用**
    
    ```php
    if (!$condition1) {
        return;
    }
    if (!$condition2) {
        return;
    }
    if (!$condition3) {
        return;
    }
    // 処理
    
    ```
    
3. **関数に分割**
    
    ```php
    if (isEligible($user)) {
        // 処理
    }
    
    function isEligible($user) {
        return $condition1 && $condition2 && $condition3;
    }
    
    ```
    

---

### **(6) 制御構造の複雑さを測る**

制御構造が複雑かどうかを測る1つの方法として、以下の計算法を利用できます。

### **手順:**

1. 初期値を **1** とする。
2. 次の要素が出現するごとに **+1** する。
    - `if`
    - `for`
    - `while`
    - `&&` または `||`
    - `case`（`switch` 文）
3. 合計値を確認する。

### **結果の目安:**

- **1〜5点:** 問題なし（適切な範囲）
- **6〜10点:** 見直しを検討
- **11点以上:** 処理の分割が必要

### **例:**

```php
if ($status === 'active' && $age > 18 || $isAdmin) {
    // 処理
}

```

- 初期値: 1
- `if`: +1
- `&&`: +1
- `||`: +1
- 合計: **4点** → 適切な範囲

---

## **3. 制御構造をシンプルに保つ理由**

制御構造が複雑だと、以下の問題を引き起こします：

- **コードの可読性が低下**
- **バグの発生率が増加**
- **メンテナンス性の低下**

そのため、シンプルに保つことが重要です。

---

## **4. 今回のまとめ**

### **よくある問題と対策**

1. **複雑な式**
    - ブール変数や関数で簡潔化する。
2. **否定的な論理式**
    - 肯定的な論理式に書き換える。
3. **かっこのない複雑な論理式**
    - かっこを使って評価順序を明示する。
4. **数値を含む式**
    - 数直線の順序に沿って記述する。
5. **深いネスト**
    - ネストを浅くする工夫を行う。

### **制御構造の複雑さを測る**

- 制御構造の点数を計測し、複雑すぎる場合は処理を分割してシンプル化する。

---

今回の内容は、私自身が独学エンジニアの学習を進める中で得た知見をまとめたものです。
制御構造の扱い方に悩んでいる方や学習中の方の参考になれば幸いです。