【PHP】参照渡しの配列の要素をunsetしても参照は解除されない


タイトルの通りです。
参照渡し(参照の代入)が推奨できるかはさておき、挙動の一例として参考にしてください。

テストデータの作成

配列$foodsを作成し、$ref_foodsへ参照を代入します。

$foods = [
    'fruits' => [
        'apple',
        'orange'
    ],
    'vegetables' => [
        'carrot',
        'tomato'
    ]
];

$ref_foods = &$foods;

代入後、$ref_foods$foodsは同じ内容を指します。

var_dump($ref_foods);
/*
array(2) {
  ["fruits"]=>
  array(2) {
    [0]=>
    string(5) "apple"
    [1]=>
    string(6) "orange"
  }
  ["vegetables"]=>
  array(2) {
    [0]=>
    string(6) "carrot"
    [1]=>
    string(6) "tomato"
  }
}
*/

var_dump($foods);
/*
array(2) {
  ["fruits"]=>
  array(2) {
    [0]=>
    string(5) "apple"
    [1]=>
    string(6) "orange"
  }
  ["vegetables"]=>
  array(2) {
    [0]=>
    string(6) "carrot"
    [1]=>
    string(6) "tomato"
  }
}
*/

配列を丸ごとunsetした場合

unsetされた配列$ref_foodsは未定義の状態になります。
代入元の配列$foodsは変更されません。

unsetのタイミングで参照が解除されることが分かります。

unset($ref_food);

var_dump(isset($ref_food)); // bool(false)
var_dump(isset($food));     // bool(true)

var_dump($foods);
/*
array(2) {
  ["fruits"]=>
  array(2) {
    [0]=>
    string(5) "apple"
    [1]=>
    string(6) "orange"
  }
  ["vegetables"]=>
  array(2) {
    [0]=>
    string(6) "carrot"
    [1]=>
    string(6) "tomato"
  }
}
*/

配列の要素をunsetした場合

unsetされた配列の要素$ref_foods['fruits']だけでなく、代入元の配列の要素$foods['fruits']も未定義の状態になります。

unset($ref_foods['fruits']);

var_dump(isset($ref_foods['fruits'])); // bool(false)
var_dump(isset($foods['fruits']));     // bool(false)

$ref_foodsへ要素を代入すると$foodsにも反映されます。
参照が解除されていないことが分かります。

$ref_foods['fruits'][] = 'grape';

var_dump($ref_foods);
/*
array(2) {
  ["vegetables"]=>
  array(2) {
    [0]=>
    string(6) "carrot"
    [1]=>
    string(6) "tomato"
  }
  ["fruits"]=>
  array(1) {
    [0]=>
    string(5) "grape"
  }
}
*/

var_dump($foods);
/*
array(2) {
  ["vegetables"]=>
  array(2) {
    [0]=>
    string(6) "carrot"
    [1]=>
    string(6) "tomato"
  }
  ["fruits"]=>
  array(1) {
    [0]=>
    string(5) "grape"
  }
}
*/

まとめ

公式マニュアルを確認しましたが、根拠になりそうな情報が見つかりませんでした(-_-;)
PHP公式マニュアル: リファレンス渡し
PHP公式マニュアル: リファレンスの解除

参照渡しはコードの見通しが悪くなるので使いたくありませんが、動作を知ることは役に立ちます。
注意点をまとめました。

  • どのように参照が代入されているか(変数をそのままか、一部の要素だけか)
  • 処理の途中でunsetが実行されているか
  • 処理の途中で参照が解除されていないか

2022/03/24追記

記事中のコードでは配列の要素に参照は無いためタイトルの挙動になります。
参照に不慣れだとハマりやすい箇所だと思うので、記事は公開当初のままにしておきます。

参照については、こちらも参考にしてみてください。
Xdebugによる検証方法も掲載されているので、手を動かしながら学べます。
PHP公式マニュアル: 参照カウント法の原理

採用PR

弊社で一緒に働く仲間を募集しています。
全てのオタクを幸せにしたい方、是非ご覧ください!