私は普段PHPとJavaScript(厳密にはLaravelとTypescript)を触る機会が多いのですが、片方に慣れるともう片方でとんでもない勘違いすることがあるので、まとめることにしました。
両方、配列に関する内容です。
1つ目
関数・メソッドの引数に配列を渡すとき、PHPでは配列が値として渡される。
一方、JavaScriptでは配列への参照が値として渡されるため、配列の中身を変更すると呼び出し元にも影響する。
PHP
function addThree(array $arr) {
$arr[] = 3;
}
// 実行
$arr = [1, 2];
addThree($arr);
$result = $arr; // -> [1, 2] 変化なし
JavaScript
function addThree(arr) {
arr.push(3);
}
const arr = [1, 2];
addThree(arr);
const result = arr; // -> [1, 2, 3] 変化あり
この二つの仕様を取り違え、JavaScriptを触っているときにPHPと同じ感覚でいると、配列の中身が気付かぬうちに書き変わっていたりします。
またPHPでは、配列を格納した変数をコピーする際も、参照のコピーにはなりません。JavaScriptでは参照をコピーするので注意。
PHP
$user1 = ["name" => "田中"];
$user2 = $user1;
$user2["name"] = "吉田";
$result1 = $user1["name"]; // 田中
$result2 = $user2["name"]; // 吉田
連想配列でも同じ。
2つ目
空配列について、PHPではfalsyだが、JavaScriptではtruthy
PHP
$arr = [];
if ($arr) {
// 実行されない。
} else {
// 実行される!!
}
JavaScript
const arr = [];
if (arr) {
// 実行される!!
} else {
// 実行されない。
}
これも、この二つの仕様を取り違えるととんでもないことになる。
こういう取り違えを起こさないために。
そもそもPHPとJavaScriptでは配列の扱いが異なる、という点を意識すると覚えやすいです。
- JavaScriptでは、配列はオブジェクトとして扱われる。
- PHPでは、配列はオブジェクトとは別の「配列」という型として扱われる。
PHPにおける配列の扱いまとめ。
- 通常(
&等を用いない場合)、関数・メソッドの引数に配列を渡すときや、変数に代入する時、値として扱われる。 - 空配列はfalsy(偽値)として扱われる。
余談1
「1つ目」のJavaScriptの説明にて、「一方、JavaScriptでは配列への参照が値として渡される」と、少し周りくどい記述をしました。
その理由は、以下のように参照ごと上書きした場合は、元の変数に影響は出ないからです。
function replaceArr(arr) {
arr = [3, 4];
}
const originalArr = [1, 2];
replaceArr(originalArr);
const result = originalArr; // -> [1, 2] 変化なし
arr = [3, 4]; の時点で、関数内の変数 arr に対して、新しい配列への参照が上書きされる形で代入されます。
呼び出し元の originalArr は元の配列への参照を保持したままなので、影響を受けません。
要するに、参照そのものが渡っている訳ではありません。
対象がオブジェクトである場合は、PHPも似た挙動になります。
(繰り返しますが、PHPにおいて配列はオブジェクトではないです)
余談2
PHPには「コピーオンライト」という仕組みがある(らしい)ので、値渡しといっても、値が変更されるまでは内部的にデータを共有している(ようです)。
実際に値を変更するタイミングで、必要に応じてデータがコピーされる仕組みになっている(ようです)。
ここら辺は私もまだ勉強不足なので、気になる方は調べてみてください。
公式のリファレンスだと、以下に「コピーオンライト」のワードが出てますね。
https://www.php.net/manual/ja/function.debug-zval-dump.php
余談3
Laravel(PHPのフレームワークの一つ)では、配列と同じような形でCollectionを使う機会も多いですが、このCollectionはしっかりオブジェクトです。
変数に代入したり関数・メソッドの引数として渡したりすると、参照がコピーされ、中身が空でもtruthy(真値)として扱われます。
余談4
本記事内では、参照という言葉を気軽に使ってしまっていますが、PHPにおける「参照」という言葉の扱いは、少し気をつけなきゃいけないっぽいです。
詳細は以下の公式リファレンスを参照
https://www.php.net/manual/ja/language.oop5.references.php