1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-03-11

ただの配列だと気が付きやすいのだが、連想配列の配列だと形が似ていて間違いやすいポイント。

stdClassの配列を更新する方法

stdClassはオブジェクトであり、オブジェクトを関数やforeachで渡すと参照コピーとなる。
Manualにも説明がある。

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);
}
$ 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で連想配列はコピーされて別の連想配列になってしまうので更新されない。

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);
}
$ 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内でコピーされた連想配列を配列に格納し直す。

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;
    }
}
// 同じなので省略
$ 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内で参照コピーにする。

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);
}
// 同じなので省略
$ 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を忘れると参照が残っちゃいます。

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

全貌

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();
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?