なぜ連想配列という概念があるのにオブジェクトという概念が必要なのか

## この記事を書くに至った経緯

筆者はこれまでオブジェクトというのは、連想配列で処理を書ける部分をわざわざ別なクラスで定義して本処理で行うという無駄な行為ではあるものの、過去の人の作法蔑ろにしないための儀式だと認識していました。

しかし、いろいろな経験を経てオブジェクトのありがたみがわかったためこの記事を書くこととしました。

※「下記のどっちがいい？」って効かれたら連想配列の方が余計なこと考えずに済みそうに見えませんか？

```php:連想配列の書き方とオブジェクトの書き方
// 連想配列の使い方
testArray["greeting"] = 'hello';
echo testArray["greeting"] . 'world!' // hello world!

// オブジェクトの使い方
class testObject       // ←こいつ作る意味あります？と思っていた
{
    private string $greeting;
    
    public function setGreeting(string $greeting): void
    {
      $this->greeting = $greeting;
    }
    
    public function getGreeting(): string
    {
      return $this->greeting = $greeting;
    }
}

testObject = new testObject::class;
testObject->setGreeting('hello');
echo testObject->getGreeting() . 'world!' // hello world!
```


## 結論
さっそく結論ですが、なぜ概念が分かれているのかというと、**楽に使えてほしい**場合と多少面倒でも**安全に使えてほしい**場合があるからでした。

具体的な例で言うと連想配列には下記のようなデメリットがあり、そこを補えるのがオブジェクトという概念だったのです。

```php:例１格納している型を変更できてしまう
testArray["greeting"] = 'hello';

// 途中で配列以外の処理が挟まる
$GREETING_ARRAY=['good morning','hello','good night','bye'];
echo 'エッホエッホ'; 
testArray["greeting"] = 1; // ← 型を変えているためバグの温床になる
echo 'いい子は' . $GREETING_ARRAY[testArray["greeting"]] . 'everybody! って挨拶するって伝えなきゃ';
echo 'エッホエッホ'; 

echo testArray["greeting"] . 'world!' // 1 world! // ← 本当は hello world! にしたかった
```

```php:例2 タイポに弱い
testArray["greting"] = 'hello'; // ← エラーの原因になっていると気付きにくい
echo testArray["greeting"] . 'world!' // Notice: Undefined index // ← エディタの静的解析が効かず、本番でエラーになっていると気づくことがままある
```



## オブジェクトだとどのように防ぐことができるのか
先ほど述べた連想配列のデメリットを、オブジェクトを利用する下記のように防ぐことができます。

```php:例１格納している型を変更できてしまうのを防げる
class testObject
{
    private string $greeting;
    
    public function setGreeting(string $greeting): void
    {
      $this->greeting = $greeting;
    }
    
    public function getGreeting(): string
    {
      return $this->greeting = $greeting;
    }
}

testObject = new testObject::class;
testObject->setGreeting('hello');

// 途中で配列以外の処理が挟まる
$GREETING_ARRAY=['good morning','hello','good night','bye'];
echo 'エッホエッホ'; 
testObject->setGreeting(1); // ← エディタに`invalid argument error`の表示が出てこの使い方ができないことに気づける。呼び出した画面やコンソールでもエラーが出て間違いに気づける。
echo 'いい子は' . $GREETING_ARRAY[testObject->getGreeting();] . 'everybody! って挨拶するって伝えなきゃ';
echo 'エッホエッホ'; 

echo testObject->getGreeting() . 'world!' // このままだとこの処理に到達しないが、hello world! が守られる
```

```php:例2 タイポに強い
class testObject
{
    private string $greeting;
    
    public function setGreeting(string $greeting): void
    {
      $this->greeting = $greeting;
    }
    
    public function getGreeting(): string
    {
      return $this->greeting = $greeting;
    }
}

testObject = new testObject::class;
testObject->setGreting('hello'); // ← エディタで赤波線がでてきて間違いに気づける
echo testObject->getGreeting() . 'world!' // エラーになるが、コーディング中に気づきやすくなる
```

このように、記述量は増えるし実装中は型の部分でよく怒られるので実装中はイラッとするのですが、実は壊れにくいシステムを作ることができるのがオブジェクトという概念なのです。

## それぞれのメリット・デメリットの比較表

| 項目 | 連想配列 | オブジェクト |
| --- | --- | --- |
| 実装コスト | ◯ | ✕ |
| 型安全 | ✕ | ◯ |
| エディタによる補完 | ✕ | ◯ |




## 補足
わざわざこんな小さい部分にこだわるのかと思われる方が多いかなと思うので、自分の経験を少し書かせていただきます。

今参画している現場で`echo testArray["greeting"] . 'world!' // 1 world!`と同じ理由の現象（型違い）でエラーが起きました。それは大きい処理を実行するバッチで、暫定対応に1時間ほどかかるものでした。

そのためこのロジックが直るまでは毎日１時間取られるようなことが起きました。当日やるはずだった業務が間に合わなくなるのでもちろんそれらは残業対応でこなしました。

一見なんともないただのエラーなのですが、特にDB周りの処理を行う部分だとその後のエラー対応が死ぬほど大変になるので、小さいエラーを見過ごさないのも大事であることを知っていただけたらと思っています。

あと、バッチエラーが出ると（しょうがないことではありますが）責任者の方の機嫌が悪くなるのも結構辛くて、他の仕事が進めにくくなることもままありました。ともあれツケが回ってくるというのを身をもって知ることになるので、それが嫌な方はバグが起きないための細かい気配りとしてオブジェクトは有効であると知っておいていただけると良いかなと思います。


## まとめ

- 連想配列は素早い実装に有効だけど、型とキー名ミスがバグの温床になる
- オブジェクトは実装がめんどくさいけどバグりにくい
- バグった時の対応工数はオブジェクト実装の100倍かかるから、長く使うならオブジェクトにしておいた方が良い