PHP
PHP7

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

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


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