PHPでelseを書きたくない時に使える回避手段

# はじめに

- 社内勉強会で発表する内容です
- ロジックの中でelseを使わなくなったので、どうやって回避しているのかをまとめています
- バリバリ主観が入っているので、そこは注意

---
自分で検証したやつ

**https://github.com/niisan-tokyo/replaceelse**

---
# if ~ else の回避手段

---
## オリジナル

```OriginalElse.php
class OriginalElse
{
    public function ifElse(bool $bool)
    {
        if ($bool === true) {
            return 'YES';
        } else {
            return 'NO';
        }
    }
}
```
---
## 書き換え

---
### 早期リターン

よく見るポピュラーな`else`の回避手段
オリジナルは、そもそもelseが不要だったりする
一応、どんなときでも使える

```ReplaceElse.php
class ReplaceElse
{

    /**
     * 早期リターン
     */
    public function ifElse(bool $bool)
    {
        if ($bool === true) {
            return 'YES';
        }

        return 'NO';
    }
}
```
---

### 初期値代入
`else`の中を初期値もしくはデフォルト値とみなし、`if`条件が来たら中身を書き直す方法
`if ~ else`が代入処理か、代入処理に変換する必要があるので、ちょっと面倒かも
巨大なデータを入れる場合でもない限り、初期値代入のコストはだいたい無視していい

```ReplaceElse.php
    /**
     * 初期値代入
     */
    public function ifElse2(bool $bool)
    {
        $str = 'YES';
        if ($bool === false) {
            $str = 'NO';
        }

        return $str;
    }
```
---
### 三項演算子
単純な`if ~ else`は三項演算子で書くと**目に優しい**
分岐処理がそれぞれ一行で住む場合に使用できる
初期値代入の亜種で、プログラムの行数をかなり節約できる
条件式が長い場合は条件式部分を分離しないと横に長くなって目に厳しい

```ReplaceElse.php
    /**
     * 三項演算子
     */
    public function ifElse3(bool $bool)
    {
        return ($bool === true) ? 'YES': 'NO';
    }
```
---
## if~elseまとめ

- elseを使わなくて書けます
- 個人的優先順位は 三項演算子 > 早期リターン > (メソッド化) > 初期値代入
- 三項演算子は条件式と相談して、可読性が落ちそうなほど長くなければ使う
- さっさとreturn できるならしちゃう
- 条件分岐がメソッドで切り出すほどでもなければ、初期値代入でお茶を濁す

---
# if ~ else if ~ else

---
## オリジナル
分岐条件が複数ある場合
書きたくない`else`がいくつもある...だと

```OriginalElse.php
    public function ifElseIf(int $num)
    {
        if ($num === 0) {
            $str = 'ZERO';
        } else if ($num === 1) {
            $str = 'ONE';
        } else if ($num === 2) {
            $str = 'TWO';
        } else {
            $str = 'OTHER';
        }

        return $str;
    }
```
---
## 書き換え
---
### switch文
個人的には**強く非推奨**
switch文のほうが早いよっていう言説をたまに聞くけど、今どきのCPUでは無視していいレベルだと思う
インデントが増えたりして可読性も悪くなる気がする
比較条件がゆるい比較なので、評価に使用する変数の型が可変な場合は注意

```ReplaceElse.php
    /**
     * switch文 (この場合は等価)
     */
    public function ifElseIf(int $num)
    {
        switch ($num) {
            case 0:
                $str = 'ZERO';
                break;
            case 1:
                $str = 'ONE';
                break;
            case 2;
                $str = 'TWO';
                break;
            default:
                $str = 'OTHER';
        }

        return $str;
    }
```
---
### 早期リターンつなぎ
都度return してelseをことごとく消していく方法
単純なロジックの中であれば上から条件を眺めていける

```ReplaceElse.php
    /**
     * 早期リターンつなぎ
     */
    public function ifElseif2(int $num)
    {
        if ($num === 0) {
            return 'ZERO';
        }

        if ($num === 1) {
            return 'ONE';
        }

        if ($num === 2) {
            return 'TWO';
        }

        return 'OTHER';
    }
```
---
### 配列とnull合体演算子
ちょっとアクロバティックなやり方で、php7以上が必須
分岐が多いけど単純な場合はこれを使う事が多い

```ReplaceElse.php
    /**
     * 配列 + null合体演算子
     */
    public function ifElseIf3(int $num)
    {
        $arr = [
            0 => 'ZERO',
            1 => 'ONE',
            2 => 'TWO'
        ];

        return $arr[$num] ?? 'OTHER';
    }
```
---
### 配列とnull合体演算子とメソッドコール
各if, elseif, elseの分岐で複雑な処理が入る場合は各々の処理をメソッドに分ける
メソッドのインターフェースが同じ場合に使える

```ReplaceElse.php
    /**
     * 配列 + null合体演算子 + メソッドコール
     */
    public function ifElseIf4(int $num)
    {
        $arr = [
            0 => 'getZero',
            1 => 'getOne',
            2 => 'getTwo'
        ];
        $method = $arr[$num] ?? 'getOther';
        return $this->{$method}();
    }

    private function getZero() { return 'ZERO'; }
    private function getOne() { return 'ONE'; }
    private function getTwo() { return 'TWO'; }
    private function getOther() { return 'OTHER'; }
```
---
## if ~ else ~ if まとめ

- こちらは優先順位がつけにくいが, 短い場合は早期リターンつなぎで、分岐が多くなってくると、配列 + null合体演算の組み合わせになる感じ
- 各分岐後の処理が大きくなると、メソッドに出しちゃう
- switch文は基本読みにくくなるのでやらない

---
# まとめ

- elseを書かなくても分岐処理は書けるし、else使わないほうが見やすい場合が多い
- 単純な分岐であれば三項演算子が見やすいが、条件が複雑であれば早期リターンを使うほうがスッキリする
- 複数分岐するのであれば配列を駆使するのもあり
- 他にも書き方があるとは思うが、とりあえずみやすさを優先するといいんじゃないかって思う