stdClassの配列と連想配列の配列では配列を更新する方法が違う

ただの配列だと気が付きやすいのだが、連想配列の配列だと形が似ていて間違いやすいポイント。
# stdClassの配列を更新する方法
[stdClassはオブジェクトであり、オブジェクトを関数やforeachで渡すと参照コピーとなる。](https://cho-phper.hateblo.jp/entry/2016/08/12/011135)
[Manualにも説明がある。](http://php.net/manual/ja/language.oop5.cloning.php)

```php:updateArray.updateStdClassArray
/** @var array 各配列にある[otherName]を更新する値を格納している配列. */
private const NEW_OTHERNAME = [
    'アボカド' => '森のバター',
    'グラジオラス' => '阿蘭陀菖蒲',
];

/** stdClassの配列を更新する. */
public function updateStdClassArray()
{
    /** @var \stdClass[] $stdArray stdClassの配列. */
    $stdArray = [
        (object)['name' => 'イタリアンパセリ', 'otherName' => 'パースレー', 'gakumei' => 'Petroselinum neapolitanum', 'bunrui' => 'セリ科オランダゼリ属'],
        (object)['name' => 'グラジオラス', 'otherName' => '唐菖蒲', 'gakumei' => 'Gladiolus', 'bunrui' => 'アヤメ科グラジオラス属'],
        (object)['name' => 'アボカド', 'otherName' => 'ワニナシ', 'gakumei' => 'Persea americana', 'bunrui' => 'クスノキ科ワニナシ属'],
        (object)['name' => 'マロウ', 'otherName' => 'ウスベニアオイ', 'gakumei' => 'Malva sylvestris', 'bunrui' => 'アオイ科ゼニアオイ属'],
    ];

    var_dump($stdArray);

    foreach ($stdArray as $std) {
        $name = $std->name;
        if (array_key_exists($name, self::NEW_OTHERNAME)) {
            // NEW_OTHERNAMEに[name]の値が一致するキーがあれば[otherName]を更新する.
            $std->otherName = self::NEW_OTHERNAME[$name];
        }
    }

    var_dump($stdArray);
}
```

```bash
$ php updateArray.php 
array(4) {
  [0]=>
  object(stdClass)#2 (4) {
    ["name"]=>
    string(24) "イタリアンパセリ"
    ["otherName"]=>
    string(15) "パースレー"
    ["gakumei"]=>
    string(25) "Petroselinum neapolitanum"
    ["bunrui"]=>
    string(30) "セリ科オランダゼリ属"
  }
  [1]=>
  object(stdClass)#3 (4) {
    ["name"]=>
    string(18) "グラジオラス"
    ["otherName"]=>
    string(9) "唐菖蒲"
    ["gakumei"]=>
    string(9) "Gladiolus"
    ["bunrui"]=>
    string(33) "アヤメ科グラジオラス属"
  }
  [2]=>
  object(stdClass)#4 (4) {
    ["name"]=>
    string(12) "アボカド"
    ["otherName"]=>
    string(12) "ワニナシ"
    ["gakumei"]=>
    string(16) "Persea americana"
    ["bunrui"]=>
    string(30) "クスノキ科ワニナシ属"
  }
  [3]=>
  object(stdClass)#5 (4) {
    ["name"]=>
    string(9) "マロウ"
    ["otherName"]=>
    string(21) "ウスベニアオイ"
    ["gakumei"]=>
    string(16) "Malva sylvestris"
    ["bunrui"]=>
    string(30) "アオイ科ゼニアオイ属"
  }
}
array(4) {
  [0]=>
  object(stdClass)#2 (4) {
    ["name"]=>
    string(24) "イタリアンパセリ"
    ["otherName"]=>
    string(15) "パースレー"
    ["gakumei"]=>
    string(25) "Petroselinum neapolitanum"
    ["bunrui"]=>
    string(30) "セリ科オランダゼリ属"
  }
  [1]=>
  object(stdClass)#3 (4) {
    ["name"]=>
    string(18) "グラジオラス"
    ["otherName"]=>
    string(15) "阿蘭陀菖蒲" #<<<<<<<<<<<<<<<<<<<<<<<< 更新された。
    ["gakumei"]=>
    string(9) "Gladiolus"
    ["bunrui"]=>
    string(33) "アヤメ科グラジオラス属"
  }
  [2]=>
  object(stdClass)#4 (4) {
    ["name"]=>
    string(12) "アボカド"
    ["otherName"]=>
    string(15) "森のバター" #<<<<<<<<<<<<<<<<<<<<<<<< 更新された。
    ["gakumei"]=>
    string(16) "Persea americana"
    ["bunrui"]=>
    string(30) "クスノキ科ワニナシ属"
  }
  [3]=>
  object(stdClass)#5 (4) {
    ["name"]=>
    string(9) "マロウ"
    ["otherName"]=>
    string(21) "ウスベニアオイ"
    ["gakumei"]=>
    string(16) "Malva sylvestris"
    ["bunrui"]=>
    string(30) "アオイ科ゼニアオイ属"
  }
}
```

# 連想配列の配列を更新する方法
## 失敗事例 : foreachで連想配列はコピーされて別の連想配列になってしまうので更新されない。
```php:updateArray.udateAssociativeArray
// private const NEW_OTHERNAMEは同じ.
/** 連想配列の配列を更新する. */
public function udateAssociativeArray()
{
    /** @var array $associativeArray 連想配列の配列. */
    $associativeArray = [
        ['name' => 'イタリアンパセリ', 'otherName' => 'パースレー', 'gakumei' => 'Petroselinum neapolitanum', 'bunrui' => 'セリ科オランダゼリ属'],
        ['name' => 'グラジオラス', 'otherName' => '唐菖蒲', 'gakumei' => 'Gladiolus', 'bunrui' => 'アヤメ科グラジオラス属'],
        ['name' => 'アボカド', 'otherName' => 'ワニナシ', 'gakumei' => 'Persea americana', 'bunrui' => 'クスノキ科ワニナシ属'],
        ['name' => 'マロウ', 'otherName' => 'ウスベニアオイ', 'gakumei' => 'Malva sylvestris', 'bunrui' => 'アオイ科ゼニアオイ属'],
    ];

    var_dump($associativeArray);

    foreach ($associativeArray as $associative) {
        $name = $associative['name'];
        if (array_key_exists($name, self::NEW_OTHERNAME)) {
            // NEW_OTHERNAMEに[name]の値が一致するキーがあれば[otherName]を更新する.
            $associative['otherName'] = self::NEW_OTHERNAME[$name];
        }
    }

    var_dump($associativeArray);
}
```
```bash
$ php updateArray.php 
array(4) {
  [0]=>
  array(4) {
    ["name"]=>
    string(24) "イタリアンパセリ"
    ["otherName"]=>
    string(15) "パースレー"
    ["gakumei"]=>
    string(25) "Petroselinum neapolitanum"
    ["bunrui"]=>
    string(30) "セリ科オランダゼリ属"
  }
  [1]=>
  array(4) {
    ["name"]=>
    string(18) "グラジオラス"
    ["otherName"]=>
    string(9) "唐菖蒲"
    ["gakumei"]=>
    string(9) "Gladiolus"
    ["bunrui"]=>
    string(33) "アヤメ科グラジオラス属"
  }
  [2]=>
  array(4) {
    ["name"]=>
    string(12) "アボカド"
    ["otherName"]=>
    string(12) "ワニナシ"
    ["gakumei"]=>
    string(16) "Persea americana"
    ["bunrui"]=>
    string(30) "クスノキ科ワニナシ属"
  }
  [3]=>
  array(4) {
    ["name"]=>
    string(9) "マロウ"
    ["otherName"]=>
    string(21) "ウスベニアオイ"
    ["gakumei"]=>
    string(16) "Malva sylvestris"
    ["bunrui"]=>
    string(30) "アオイ科ゼニアオイ属"
  }
}
array(4) {
  [0]=> # 同じなので省略
  [1]=>
  array(4) {
    ["name"]=>
    string(18) "グラジオラス"
    ["otherName"]=>
    string(9) "唐菖蒲" #<<<<<<<<<<<<<<<<<<<<<<<< 更新されない。
    ["gakumei"]=>
    string(9) "Gladiolus"
    ["bunrui"]=>
    string(33) "アヤメ科グラジオラス属"
  }
  [2]=>
  array(4) {
    ["name"]=>
    string(12) "アボカド"
    ["otherName"]=>
    string(12) "ワニナシ" #<<<<<<<<<<<<<<<<<<<<<<<< 更新されない。
    ["gakumei"]=>
    string(16) "Persea americana"
    ["bunrui"]=>
    string(30) "クスノキ科ワニナシ属"
  }
  [3]=> # 同じなので省略
}
```

## 成功事例① : foreach内でコピーされた連想配列を配列に格納し直す。
```php:updateArray.udateAssociativeArray
// 同じなので省略
/** @var int $key 配列に格納し直すためにキーを持っておく. */
foreach ($associativeArray as $key => $associative) {
    $name = $associative['name'];
    if (array_key_exists($name, self::NEW_OTHERNAME)) {
        // NEW_OTHERNAMEに[name]の値が一致するキーがあれば[otherName]を更新する.
        $associative['otherName'] = self::NEW_OTHERNAME[$name];
        // コピーされた連想配列を配列に格納し直す.
        $associativeArray[$key] = $associative;
    }
}
// 同じなので省略
```
```bash
$ php updateArray.php 
# 変更前は同じ状態なので省略
array(4) {
  [0]=> # 同じなので省略
  [1]=>
  array(4) {
    ["name"]=>
    string(18) "グラジオラス"
    ["otherName"]=>
    string(15) "阿蘭陀菖蒲" #<<<<<<<<<<<<<<<<<<<<<<<< 更新された。
    ["gakumei"]=>
    string(9) "Gladiolus"
    ["bunrui"]=>
    string(33) "アヤメ科グラジオラス属"
  }
  [2]=>
  array(4) {
    ["name"]=>
    string(12) "アボカド"
    ["otherName"]=>
    string(15) "森のバター" #<<<<<<<<<<<<<<<<<<<<<<<< 更新された。
    ["gakumei"]=>
    string(16) "Persea americana"
    ["bunrui"]=>
    string(30) "クスノキ科ワニナシ属"
  }
  [3]=> # 同じなので省略
}
```

## 成功事例② : foreach内で参照コピーにする。
```php:updateArray.udateAssociativeArray
// 同じなので省略
/** @var array $associative 参照コピーにして値を更新する. */
foreach ($associativeArray as &$associative) {
    $name = $associative['name'];
    if (array_key_exists($name, self::NEW_OTHERNAME)) {
        // NEW_OTHERNAMEに[name]の値が一致するキーがあれば[otherName]を更新する.
        $associative['otherName'] = self::NEW_OTHERNAME[$name];
    }
    // 参照コピーを解除する.
    unset($associative);
}
// 同じなので省略
```
```bash
$ php updateArray.php 
# 変更前は同じ状態なので省略
array(4) {
  [0]=> # 同じなので省略
  [1]=>
  array(4) {
    ["name"]=>
    string(18) "グラジオラス"
    ["otherName"]=>
    string(15) "阿蘭陀菖蒲" #<<<<<<<<<<<<<<<<<<<<<<<< 更新された。
    ["gakumei"]=>
    string(9) "Gladiolus"
    ["bunrui"]=>
    string(33) "アヤメ科グラジオラス属"
  }
  [2]=>
  array(4) {
    ["name"]=>
    string(12) "アボカド"
    ["otherName"]=>
    string(15) "森のバター" #<<<<<<<<<<<<<<<<<<<<<<<< 更新された。
    ["gakumei"]=>
    string(16) "Persea americana"
    ["bunrui"]=>
    string(30) "クスノキ科ワニナシ属"
  }
  [3]=> # 同じなので省略
}
```
### 注意 : unsetを忘れると参照が残っちゃいます。

```bash:unsetを忘れると最後の要素に参照が残る
  [3]=>
  &array(4) { #<<<<<<<<<< 参照の「&」がくっついている。
    ["name"]=>
```

# 全貌
```php:updateArray.php
<?php
namespace App;

class updateArray
{
    /** @var array 各配列にある[otherName]を更新する値を格納している配列. */
    private const NEW_OTHERNAME = [
        'パセリ' => 'オランダゼリ',
        'アボカド' => '森のバター',
        'グラジオラス' => '阿蘭陀菖蒲',
        'ダイズ' => '畑の肉',
    ];

    /** stdClassの配列を更新する. */
    public function updateStdClassArray()
    {
        /** @var \stdClass[] $stdArray stdClassの配列. */
        $stdArray = [
            (object)['name' => 'イタリアンパセリ', 'otherName' => 'パースレー', 'gakumei' => 'Petroselinum neapolitanum', 'bunrui' => 'セリ科オランダゼリ属'],
            (object)['name' => 'グラジオラス', 'otherName' => '唐菖蒲', 'gakumei' => 'Gladiolus', 'bunrui' => 'アヤメ科グラジオラス属'],
            (object)['name' => 'アボカド', 'otherName' => 'ワニナシ', 'gakumei' => 'Persea americana', 'bunrui' => 'クスノキ科ワニナシ属'],
            (object)['name' => 'マロウ', 'otherName' => 'ウスベニアオイ', 'gakumei' => 'Malva sylvestris', 'bunrui' => 'アオイ科ゼニアオイ属'],
        ];

        var_dump($stdArray);

        foreach ($stdArray as $std) {
            $name = $std->name;
            if (array_key_exists($name, self::NEW_OTHERNAME)) {
                // NEW_OTHERNAMEに[name]の値が一致するキーがあれば[otherName]を更新する.
                $std->otherName = self::NEW_OTHERNAME[$name];
            }
        }

        var_dump($stdArray);
    }

    /** 連想配列の配列を更新する. */
    public function udateAssociativeArray()
    {
        /** @var array $associativeArray 連想配列の配列. */
        $associativeArray = [
            ['name' => 'イタリアンパセリ', 'otherName' => 'パースレー', 'gakumei' => 'Petroselinum neapolitanum', 'bunrui' => 'セリ科オランダゼリ属'],
            ['name' => 'グラジオラス', 'otherName' => '唐菖蒲', 'gakumei' => 'Gladiolus', 'bunrui' => 'アヤメ科グラジオラス属'],
            ['name' => 'アボカド', 'otherName' => 'ワニナシ', 'gakumei' => 'Persea americana', 'bunrui' => 'クスノキ科ワニナシ属'],
            ['name' => 'マロウ', 'otherName' => 'ウスベニアオイ', 'gakumei' => 'Malva sylvestris', 'bunrui' => 'アオイ科ゼニアオイ属'],
        ];

        var_dump($associativeArray);

        /** @var array $associative 参照コピーにして値を更新する. */
        foreach ($associativeArray as &$associative) {
            $name = $associative['name'];
            if (array_key_exists($name, self::NEW_OTHERNAME)) {
                // NEW_OTHERNAMEに[name]の値が一致するキーがあれば[otherName]を更新する.
                $associative['otherName'] = self::NEW_OTHERNAME[$name];
            }
    // 参照コピーを解除する.
    unset($associative);
        }

        var_dump($associativeArray);
    }
}

$clas = new updateArray();
$clas->updateStdClassArray();
$clas->udateAssociativeArray();
```