引用类型(Reference)在许多计算机语言中都被使用,而且是作为一个非常强大而实用的特性存在。它有类似指针(Pointer)的实现,却又有不同于指针的表现。例如C++的引用,可以让不同变量指向同一个对象,同时又保有直接使用dot来获取对象成员,不用繁琐的使用dereference运算符(*)和Pointer to Member运算符(->)。Java和C#中就直接以引用为主要类型,尽量让开发人员避免使用指针。
PHP中也引入了引用类型,在对对象赋值传递上,基本可视为是同于Java/C#的引用传递(具体请见Objects and references)。但同时又支持在基础类型上通过引用运算符(&)来获得内容的引用。不过在实际的使用中,PHP的引用类型因为整个PHP设计结构而存在着许多的问题,使得在程序出现非预计的结果。
引用变量可被赋予新的引用
在C++中,引用类型的变量只能在其定义时被赋予引用值,所以我们只要追踪到变量的定义处就可以知道变量是在操作哪个内容。
但是PHP不同,PHP里模糊了变量的定义,可以不定义就使用的变量。所以可以让变量被多次赋予引用值。
复制代码 代码如下:
$x = 21;
$y = 7;
$z = &$x;
$z = &$y;
var_dump($x,$y,$z);
复制代码 代码如下:
int(21)
int(7)
int(7)
复制代码 代码如下:
$z = &$x;
unset($z);
$z = &$y;
复制代码 代码如下:
$x = 21;
$y = &$x;
$z = &$y
复制代码 代码如下:
$a = array(21, 7);
$b = $a;
$b[0] = 7;
var_dump($a);
echo '
';
var_dump($b);
//Output:
//array(2) { [0]=> int(21) [1]=> int(7) }
//array(2) { [0]=> int(7) [1]=> int(7) }
复制代码 代码如下:
$a = array(21, 7);
$c = & $a[0];
$b = $a;
$b[0]= "21";
$b[1]= "7";
var_dump($a);
echo '
';
var_dump($b);
echo '
';
var_dump($c);
echo '
';
// Output:
// array(2) { [0]=> &string(2) "21" [1]=> int(7) }
// array(2) { [0]=> &string(2) "21" [1]=> string(1) "7" }
// string(2) "21"
代码中$b跟之前的只是简单的赋值,只是在之前多了一部取第一个元素的引用,但理应还是拷贝了一个新的数组。可是结果却是对$b的修改,同时也改变了$a的第一个元素,而第二个元素没有影响。
出力からは異常な点もわかります。つまり、配列の最初の要素の型に余分な '&' 記号が含まれています。そしてこれが参照演算子です。つまり、配列の最初の要素が参照型になります。したがって、割り当ても値のコピーではなく参照コピーになります。
この問題は非常に奇妙で、開発中に多くの無用なトラブルを引き起こしました。当初、コピーされた配列は元の配列に関連していないと考えていましたが、この予期しない参照型のせいで、操作中に混乱してしまいました。元の配列が影響を受けます。
これが PHP のバグなのか、それとも意図的にこのように設計されているのかはわかりません。長い間オンラインで検索していましたが、この利便性について関連する説明はありません。これについては、Float Middle の「PHP: 配列要素への参照は危険です」と Symmetric Designs の「参照による PHP 配列へのアクセスに関する問題」だけです。 , しかし理由は明かされませんでした。
その後、PHP バグ レポートでいくつかの関連レポート (Bug6417、Bug7412、Bug15025、Bug20993) を確認しました。これはバグであり、後のバージョンでは修正されているという人もいます。詳細はわかりませんが、配列への参照の使用を避けることしかできません。
さらに興味深いのは、これらの参照の設定を解除して 1 つだけを残すと、配列要素は参照のない通常の型になるということです。
コードをコピーします コードは次のとおりです。
unset($b); c);
var_dump($a);
// 出力:
//array(2) { [0]=> string(2) "21"=> ; int( 7) }
実際、参照付きの foreach を使用して配列要素の値を変更したいのですが、これは主に PHP の配列が連想配列であるためです。この種の配列は長さが無限で、インデックスが不連続である可能性があり、文字列と整数が含まれるためです。同時にインデックスとして使用できます。」したがって、for ループを使用して整数インデックスを単純にインクリメントすることはできません。
もちろん、以下のコードのように $key を介して配列要素の値を直接変更することもできますが、これには効率上の問題が生じる可能性があります。
コードをコピーします コードは次のとおりです:
foreach ($array_var as $key => $value)
$array_var [$key] = $newValue
しかし、PHP 関数はさまざまな型を返すことができるため、表現として参照パラメーターを渡す必要はありません。本当に複数の戻り値が必要な場合でも、解決策として「主キーとして文字列を持つ配列」を返すことができますが、各要素がその結果に対応することをドキュメントで指摘する必要がある場合があります。
これを操作するより良い方法は、参照変数
を使用する必要がなくなったときに、すぐに変数に対して unset を使用してコンテンツとの接続を切り替えることです。また、変数が参照型でない場合でも、その変数が使用されていないことを 確認します 。その変数に対して unset を呼び出しても問題はありません。少なくとも、後で変数が再割り当てされたときに、前の結果に影響を与えないことが保証されます。