Code Fix

中級

配列を別の変数に代入するとコピーされる(参照ではない)

PHPの配列はオブジェクトと違い、代入すると中身がまるごとコピーされます。コピー先の配列を変更しても、元の配列には影響しません。

なぜエラーが出ないのか

出力: 1,2,3 / 1,2,3
(エラーなし)
PHPは何も報告しません。文法として正しいためです
出力: 1,2,3 / 1,2,3
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  <?php
 2  $a = [3, 1, 2];
 3  $b = &$a     ;
             ^
 4  sort($b);
 5  echo implode(",", $a) . " / " . implode(",", $b);
出力: 1,2,3 / 1,2,3期待: 3,1,2 / 1,2,3 (エラーにはなりません)

&$aで参照渡しにすると$bは$aと同じ配列を指すため、sort($b)が$aまで並べ替えてしまいます。単に$aと書けば値がコピーされ、元の配列は影響を受けません。

直し方: &$a を $a にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  <?php
 2  function sortInPlace(&$arr     ) {
                              ^
 3      sort($arr);
 4      return $arr;
 5  }
 6  $original = [5, 3, 4];
 7  $sorted = sortInPlace($original);
 8  echo implode(",", $original) . " / " . implode(",", $sorted);
出力: 3,4,5 / 3,4,5期待: 5,3,4 / 3,4,5 (エラーにはなりません)

引数を&$arrという参照渡しにすると、関数内のsort()が呼び出し元の$originalまで並べ替えてしまいます。PHPの配列引数は既定で値渡しなので、&を付けなければ元の配列は安全です。

直し方: &$arr を $arr にします。

この問題を解いてみる →

パターン3

 1  <?php
 2  $cart = ["apple", "banana"];
 3  $backup = &$cart     ;
                   ^
 4  $backup[] = "cherry";
 5  echo count($cart) . " / " . count($backup);
出力: 3 / 3期待: 2 / 3 (エラーにはなりません)

&$cartとして参照渡しにすると$backupと$cartが同じ配列を共有し、$backupへの追加が$cartにも反映されてしまいます。

直し方: &$cart を $cart にします。

この問題を解いてみる →

パターン4

 1  <?php
 2  $a = [9, 7, 8];
 3  $b = &$a     ;
             ^
 4  sort($b);
 5  echo implode(",", $a) . " / " . implode(",", $b);
出力: 7,8,9 / 7,8,9期待: 9,7,8 / 7,8,9 (エラーにはなりません)

&$aで参照渡しにすると$bは$aと同じ配列を指すため、sort($b)が$aまで並べ替えてしまいます。

直し方: &$a を $a にします。

この問題を解いてみる →

パターン5

 1  <?php
 2  function reverseInPlace(&$arr     ) {
                                 ^
 3      rsort($arr);
 4      return $arr;
 5  }
 6  $original = [1, 3, 2];
 7  $sorted = reverseInPlace($original);
 8  echo implode(",", $original) . " / " . implode(",", $sorted);
出力: 3,2,1 / 3,2,1期待: 1,3,2 / 3,2,1 (エラーにはなりません)

引数を&$arrという参照渡しにすると、関数内のrsort()が呼び出し元の$originalまで並べ替えてしまいます。

直し方: &$arr を $arr にします。

この問題を解いてみる →

よくある誤解

JavaScriptやJavaの配列の感覚で「代入は参照を共有するはず」と思い込むと、PHPでは逆の結果になります。同じ配列を共有したい場合は明示的に参照渡し(&)を使う必要があります。

実務での勘所

PHPは代入のたびに実際に配列の中身を複製しているわけではありません。内部的にはCopy-on-Write(COW)という最適化が働いており、代入した直後は元の配列とメモリ上のデータを共有したままです。どちらか一方の変数を実際に変更しようとした瞬間に、初めて本当の複製が作られます。この仕組みのおかげで、「代入すればコピーされる」という分かりやすい言語仕様を保ちながら、変更されない限り無駄なメモリコピーを避けるという実行効率も両立しています。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)