PHP 日本研討會 2024
新增註解

使用者貢獻的註解 34 則註解

79
Dave at SymmetricDesigns dot com
16 年前
另一個在使用陣列的參考時需要注意的例子。似乎即使是對陣列單元未使用過的參考也會修改參考的*來源*。賦值語句的奇怪行為(這是否就是為什麼我看到它被寫成 =& 運算符的原因? - 儘管這不會發生在普通變數上)。
<?php
$array1
= array(1,2);
$x = &$array1[1]; // 未使用的參考
$array2 = $array1; // 參考現在也適用於 $array2!
$array2[1]=22; // (更改 [0] 不會影響 $array1)
print_r($array1);
?>
產生
陣列
(
[0] => 1
[1] => 22 // var_dump() 將在此處顯示 &
)

我透過重寫沒有參考的程式碼來修正了我的錯誤,但也可以使用 unset() 函式來修正
<?php
$array1
= array(1,2);
$x = &$array1[1];
$array2 = $array1;
unset(
$x); // 陣列複製現在不受上述參考的影響
$array2[1]=22;
print_r($array1);
?>
產生
陣列
(
[0] => 1
[1] => 2
)
16
Carlos
19 年前
在下面的範例中,如果您將函式變更為類似

function test_ref(&$arr) {
$time = time();
$size = sizeof($arr); // <--- 這會造成差異...
for($n=0; $n<$size; $n++) {
$x = 1;
}

echo "<br />使用參考的函式花費了 ".(time() - $time)." s";
}
33
ivan at mailinator dot com
15 年前
一點小陷阱(小心使用參考!)

<?php
$arr
= array('a'=>'first', 'b'=>'second', 'c'=>'third');
foreach (
$arr as &$a); // 不執行任何動作。也許?
foreach ($arr as $a); // 不執行任何動作。也許?
print_r($arr);
?>
輸出

陣列
(
[a] => first
[b] => second
[c] => second
)

在 foreach 之間加入 'unset($a)' 以取得「正確」的輸出

陣列
(
[a] => first
[b] => second
[c] => third
)
10
hkmaly at bigfoot dot com
20 年前
似乎 PHP 在參考方面有問題,像是它無法正確處理循環參考或正確釋放具有多個參考的結構。請參閱 http://bugs.php.net/?id=30053.

我對此有很大的問題,我希望如果 PHP 無法修復它,PHP 的某人可以在手冊中加入適當的警告和解釋。
12
alexander at gamerev dot org
10 年前
簡單來說,以下是一個說明參考是什麼的例子

<?php
$foo
= 5;
$bar = &$foo;
$bar++;

echo
$foo;
?>

上面的範例會輸出值 6,因為 $bar 參考了 $foo 的值,因此,當變更 $bar 的值時,您也會變更 $foo 的值。
13
gnuffo1 at gmail dot com
14 年前
如果您想知道特定變數的參考計數,那麼這裡有一個函式可以利用 debug_zval_dump() 來實現

<?php
function refcount($var)
{
ob_start();
debug_zval_dump($var);
$dump = ob_get_clean();

$matches = array();
preg_match('/refcount\(([0-9]+)/', $dump, $matches);

$count = $matches[1];

//新增 3 個參考,包括呼叫 debug_zval_dump() 時
return $count - 3;
}
?>

debug_zval_dump() 是一個令人困惑的函式,正如其文件中所解釋的那樣,它會在被呼叫時新增參考計數,因為該函式中存在參考。refcount() 會將這些額外的參考減去以取得傳回值。

當處理以參考方式賦值 (=&) 的變數時,無論是在賦值的右側還是左側,情況都會更加令人困惑,因此,上面的函式對於這些類型的變數來說並非真正有效。我會將它更多地用於物件實體。

然而,即使考慮到將變數傳遞給函式會使參考計數加一;這應該表示呼叫 refcount() 會加一,然後呼叫 debug_zval_dump() 又會再加一,refcount() 似乎從某處獲得了另一個參考;因此在回傳行中減去 3 而不是 2。不太確定那是從哪裡來的。

我只在 5.3 上測試過這個;由於 debug_zval_dump() 的特性,結果在其他版本上可能會完全不同。
12
php at REMOVEMEkennel17 dot co dot uk
19 年前
我在这篇文章中找到了一個關於 PHP4 中參考如何運作(以及一些常見的陷阱)的非常有用的總結:http://www.obdev.at/developers/articles/00002.html

它處理了一些微妙的情況,我建議任何在參考方面遇到困難的人閱讀。
15
nathan
20 年前
在提到 php4 會自動建立參考的貼文中,這似乎不適用於物件。

https://php.dev.org.tw/manual/en/language.references.whatdo.php

「注意:不使用 & 運算子會導致建立物件的副本。如果在類別中使用 $this,它將對類別的目前實例進行操作。不使用 & 的賦值將複製實例(即物件),而 $this 將對副本進行操作,這並非總是理想的。通常,您會希望使用單個實例,因為效能和記憶體消耗的問題。」
20
midir
15 年前
這是一篇很好的雜誌文章(PDF 格式),詳細解釋了 PHP 參考機制的內部運作:http://derickrethans.nl/files/phparch-php-variables-article.pdf

它應該可以解釋 PHP 有時似乎表現出的一些奇怪行為,以及為什麼您無法建立「參考的參考」(與 C++ 不同),以及為什麼您絕不應該嘗試使用參考來加速傳遞大型字串或陣列(這不會有任何作用,或者會減慢速度)。

它是為 PHP 4 編寫的,但仍然適用。唯一的區別在於 PHP 5 如何處理物件:按值傳遞物件變數只會複製指向物件的內部指標。PHP 5 中的物件只有在您明確使用 clone 關鍵字時才會被複製。
9
mpapec
16 年前
奇怪的是,函式定義和對同一函式的呼叫都必須在它們前面加上 "&"。

$arr = array();
$ref =& oras($arr['blah'], array());
$ref []= "via ref";
print_r($arr);

/* result
陣列
(
[blah] => Array
(
[0] => via ref
)

)
*/

// perl like ||=
function &oras (&$v, $new) {
$v or $v = $new;
return $v;
}
11
iryoku at terra dot es
20 年前
您應該記住,php4 會將已賦值的變數「自動」保持參考狀態,直到它們被覆寫為止。因此,變數副本不是在賦值時執行,而是在修改時執行。假設你有這個

$var1 = 5;
$var2 = $var1; // 在此時,這兩個變數共享相同的記憶體位置
$var1 = 3; // 在這裡,$var1 和 $var2 擁有各自的記憶體位置,值分別為 3 和 5

不要在函式參數中使用參考來加速應用程式,因為這是自動完成的。我認為這應該寫在手冊中,因為這可能會導致混淆。

有關此處的更多資訊
http://www.zend.com/zend/art/ref-count.php
1
dallgoot
6 年前
經過一番頭痛之後,這是一個函數,可以檢查兩個變數 $a,$b 之間,其中一個是否是對另一個的參考。
這表示它們「指向」相同的值。
在以下環境測試過
PHP 7.2.2 (cli) (built: Jan 31 2018 19:31:17) ( ZTS MSVC15 (Visual C++ 2017) x64 )
希望這有幫助...
<?php

function are_references(&$a, &$b){
$mem = $a; //記住
$a = uniqid ("REFERENCE???", true ); //更改 $a
$same = $a === $b; //比較
$a = $mem; //還原 $a
return $same;
}
echo
"***distinct vars AND distinct values\n";
$a = "toto";
$b = "tata";

var_dump($a, $b, are_references($a, $b));
echo
"verify original values: $a, $b\n";

echo
"***distinct vars BUT SAME values\n";
$a = "toto";
$b = "toto";

var_dump($a, $b, are_references($a, $b));
echo
"verify original values: $a, $b\n";

echo
'*** $b is a reference of $a'."\n";
$a = "titi";
$b = &$a;

var_dump($a, $b, are_references($a, $b));
echo
"verify original values: $a, $b\n";

echo
'*** $a is a reference of $b'."\n";
$b = "titi";
$a = &$b;

var_dump($a, $b, are_references($a, $b));
echo
"verify original values: $a, $b\n";
?>
Result
***distinct vars AND distinct values
string(4) "toto"
string(4) "tata"
bool(false)
verify original values: toto, tata
***distinct vars BUT SAME values
string(4) "toto"
string(4) "toto"
bool(false)
verify original values: toto, toto
*** $b is a reference of $a
string(4) "titi"
string(4) "titi"
bool(true)
verify original values: titi, titi
*** $a is a reference of $b
string(4) "titi"
string(4) "titi"
bool(true)
verify original values: titi, titi
11
marco at greenlightsolutions dot nl
17 年前
我最近遇到了一個小問題,陣列複製導致其中一個元素的參考複製,而不是複製。

<?php
$a
=array(1 => "A");
$b=&$a[1];
$c=$a; // 應該是深層複製
$c[1]="C";
var_dump($a[1]); // 產生 'C' 而不是 'A'
?>

經過一番搜尋,我發現這是一個已知的錯誤,修復它的成本太高(請參閱 http://bugs.php.net/bug.php?id=20993)。應該在此頁面上有一些關於此行為的文檔

「由於 PHP 內部運作的特殊性,如果建立對陣列單個元素的參考,然後複製陣列,無論是透過賦值還是在函式呼叫中按值傳遞,參考都會作為陣列的一部分被複製。這表示對任一陣列中任何此類元素的變更都將在另一個陣列(和其他參考)中複製,即使這些陣列具有不同的範圍(例如,一個是函式內部的參數,另一個是全域的)!在複製時沒有參考的元素,以及在複製陣列後賦給其他元素的參考,將會正常運作(即獨立於其他陣列)。」

然而,此段落似乎在某個時間點已從此頁面中移除,大概是因為它有點晦澀難懂。不過,註解部分似乎是處理這個問題的好地方。
15
dnhuff at acm dot org
16 年前
這在之前(下方)討論過,但值得重複

$a = null; ($a =& null; 無法解析) 與 unset($a); 不同

$a = null; 將 $a 的目標位置的值替換為 null 值;

如果您選擇使用像 $NULL = NULL; 這樣的慣例

那麼,您可以說 $a =& $NULL 來中斷之前對 $a 的任何參考賦值(當然將其設定為 $NULL),如果您忘記然後說 $a = '5',仍然可能會讓您陷入麻煩。現在 $NULL 將為 '5'。

結論:在需要時使用 unset。
11
Someone
8 年前
另一個在使用陣列的參考時需要注意的例子。似乎即使是對陣列單元未使用過的參考也會修改參考的*來源*。賦值語句的奇怪行為(這是否就是為什麼我看到它被寫成 =& 運算符的原因? - 儘管這不會發生在普通變數上)。
<?php
$array1
= array(1,2);
$x = &$array1[1]; // 未使用的參考
$array2 = $array1; // 參考現在也適用於 $array2!
$array2[1]=22; // (更改 [0] 不會影響 $array1)
print_r($array1);
?>
產生
陣列
(
[0] => 1
[1] => 22 // var_dump() 將在此處顯示 &
)

//以上由 Dave at SymmetricDesign dot com 註記//
//以下是我對這個簡單問題的看法。 //

這是一個正常的參考問題。

當您獲得對某個變數的記憶體參考時。
這個變數表示「記憶體本身」。(在上面的範例中,這會是 -> $x = &$array1[1]; // 未使用的參考)

您已將原始變數 ($array1) 複製到另一個變數 ($array2)。
而複製表示「將所有內容貼到自身上」。包括參考或指標等。因此,當您將 $array1 複製到 $array2 時,這個 $array2 具有與原始 $array1 相同的參考。表示 $x = &$array1[1] = &$array2[1]。
我又說了一遍。這個參考表示「記憶體本身」。
當您選擇將一些值插入 $array2[1] 時,
$x;參考會受到 $array2[1] 的值影響。因為在已分配的記憶體中,$array2[1] 是 $array1[1] 的副本。這表示 $array2[1] = $array1[1],也表示 &$array2[1] = &$array1[1],如上所述。這會導致記憶體的值重新分配到 $array1[1] 上。在這一刻,這個主題的問題通過 '$x' 這個記憶體本身來釐清。而這個問題通過取消設定 '$x' 來解決。取消設定這個參考會觸發 $array2[1] 的記憶體重新分配。這會關閉複製的那個($array1,也就是原始的)和副本($array2)之間的參考連結。這就是那個錯誤(顯然,它不是一個錯誤。它只是一個誤解)觸發的地方。關閉參考連結會使兩個陣列物件在記憶體中分離。而這個工作是透過 unset() 函數完成的。這個主題是 7 年前發布的,但我只是想澄清它不是一個錯誤。

如果我的筆記中有任何問題,請在上面註明。
7
sneskid at hotmail dot com
12 年前
目前還沒有內建的方法來檢查兩個變數是否參考到同一塊資料,但你可以進行「參考嗅探」測試。這很少需要,但可能非常有用。下面的函數是我在一個關於此比較限制的論壇中看到的此技術的略微修改版本。

<?php
function is_ref_to(&$a, &$b)
{
$t = $a;
if(
$r=($b===($a=1))){ $r = ($b===($a=0)); }
$a = $t;
return
$r;
}

$varA = 1;
$varB = $varA;
$varC =&$varA;

var_dump( is_ref_to($varA, $varB) ); // bool(false)
var_dump( is_ref_to($varA, $varC) ); // bool(true)
?>

上面的測試使用兩步驟流程,以達到 100% 的通用性。
但如果你確定被測試的變數不會是某個值,例如 null,則可以使用該值來允許一步檢查。

<?php
function is_ref_to_1step(&$a, &$b)
{
$t = $a;
$r=($b===($a=null));
$a = $t;
return
$r;
}
?>
8
sneskid at hotmail dot com
17 年前
(v5.1.4)
關於 var_dump 的一個很酷的事情是,它會顯示哪些變數是參考(在傾印陣列時),整數/null 用 '∫' 符號表示,而布林值/雙精度浮點數/字串/陣列/物件用 '&' 符號表示。我不知道為什麼符號有差異。
在嘗試了一陣子之後,我找到了一個更好的方法來實現分離(那是偶然發現的)。var_dump 可以顯示正在發生的事情。

<?php
function &detach($v=null){return $v;}

$A=array('x' => 123, 'y' => 321);
$A['x'] = &$A['x'];
var_dump($A);
/* x 變成它自己的參考...
array(2) {
["x"]=> ∫(123)
["y"]=> int(321)
}*/

$A['y']=&$A['x'];
var_dump($A);
/* 現在兩者都是參考
array(2) {
["x"]=> ∫(123)
["y"]=> ∫(123)
}*/

$z = 'hi';
$A['y']=&detach(&$z);
var_dump($A);
/* x 仍然是參考,y 和 z 共用
array(2) {
["x"]=> ∫(123)
["y"]=> &string(2) "hi"
}*/

$A['x'] = $A['x'];
$A['y']=&detach();
var_dump($A,$z);
/* x 回歸正常,y 是獨立的,z 仍然是 "hi"
array(2) {
["x"]=> int(123)
["y"]=> NULL
}*/
?>

為了使 detach 工作,您需要在函數宣告中使用 '&',並且每次呼叫它時都要使用。

當您知道變數是參考,並且想要賦予一個新值而不影響其他參考該記憶體區塊的變數時,請使用此方法。您可以在一步中用新的常數值、變數或新的參考來初始化它。
11
sneskid at hotmail dot com
18 年前
除了 'jw at jwscripts dot com' 寫的關於 unset 的內容之外;它也可以用來「分離」變數別名,使其可以再次在唯一的記憶體區塊上工作。

這是一個範例

<?php
define
('NL', "\r\n");

$v1 = 'shared';
$v2 = &$v1;
$v3 = &$v2;
$v4 = &$v3;

echo
'before:'.NL;
echo
'v1=' . $v1 . NL;
echo
'v2=' . $v2 . NL;
echo
'v3=' . $v3 . NL;
echo
'v4=' . $v4 . NL;

// 分離混亂的
$detach = $v1;
unset(
$v1);
$v1 = $detach;

// 分離漂亮的,但比較慢
eval(detach('$v2'));

$v1 .= '?';
$v2 .= ' no more';
$v3 .= ' sti';
$v4 .= 'll';

echo
NL.'after:'.NL;
echo
'v1=' . $v1 . NL;
echo
'v2=' . $v2 . NL;
echo
'v3=' . $v3 . NL;
echo
'v4=' . $v4 . NL;

function
detach($v) {
$e = '$detach = ' . $v . ';';
$e .= 'unset('.$v.');';
$e .= $v . ' = $detach;';
return
$e;
}
?>

輸出 {
之前
v1=shared
v2=shared
v3=shared
v4=shared

之後
v1=共用?
v2=不再共用
v3=仍然共用
v4=仍然共用
}

http://www.obdev.at/developers/articles/00002.html 說在 PHP 中沒有「物件參考」這種東西,但是透過分離 (detaching) 卻變得有可能。

希望 detach 或類似的東西,未來能成為一種語言結構。
6
jw at jwscripts dot com
20 年前
重複使用之前為參考的變數,而不先取消設定它們,會導致意料之外的行為。

以下程式碼

<?php

$numbers
= array();

for (
$i = 1; $i < 4; $i++) {
$numbers[] = null;
$num = count($numbers);
$index =& $numbers[$num ? $num - 1 : $num];
$index = $i;
}

foreach (
$numbers as $index) {
print
"$index\n";
}

?>

不會產生
1
2
3

而是會產生
1
2
2

在重新使用變數之前套用 unset($index) 可以修正此問題,並會產生預期的清單
1
2
3
4
gunter dot sammet at gmail dot com
18 年前
我嘗試使用遞迴函數傳遞陣列參考來建立一個具有 n 深度的陣列。到目前為止,我沒有太大的運氣,而且我在網路上找不到任何相關資訊。所以我最終使用了 eval(),而且它似乎運作良好
<?php
foreach(array_keys($this->quantity_array) AS $key){
if(
$this->quantity_array[$key] > 0){
$combinations = explode('-', $key);
$eval_string = '$eval_array';
foreach(
array_keys($combinations) AS $key2){
$option_key_value = explode('_', $combinations[$key2]);
$eval_string .= '['.$option_key_value[0].']['.$option_key_value[1].']';
}
$eval_string .= ' = '.$this->quantity_array[$key].';';
eval(
$eval_string);
}
}
?>

這會產生一個 n 維陣列,它將在 $eval_array 變數中可用。希望它能幫助到某些人!
6
Ed
18 年前
回覆 Slava Kudinov。當你以參考方式傳遞時,你的腳本執行時間較長的唯一原因是,你根本沒有修改你傳遞給函數的陣列。如果你這樣做,執行時間的差異會小得多。事實上,以參考方式傳遞如果僅僅是一點點的話,會更快。
4
shooo dot xz at gmail dot com
11 年前
嗨,我研究過一些參考的東西。
這是我注意到的一些事情。

問題:透過欄位排序 mysql 結果

$rewrite_self = gt::recombine(array('lang', 'id'), 'value_column', $sql_result);

public static function recombine($keys, $value, &$arr) {
$ref = array();
$main = &$ref;
foreach($arr as $data) {
foreach($keys as $key) {
if (!is_array($ref[$data[$key]])) $ref[$data[$key]] = array();
$ref = &$ref[$data[$key]];
}
$ref = $data[$value];
$ref = &$main;
}
return $main;
}

array(2) {
["pl"]=>
array(2) {
[2]=>
string(4) "value_column_str"
[3]=>
string(4) "value_column_str2"
}
["en"]=>
array(1) {
[13]=>
string(7) "value_column_str3"
}
}

享受吧!
6
Francis dot a at gmx dot net
19 年前
我不知道這是不是一個錯誤(我使用的是 PHP 5.01),但是當你在陣列上使用參考時應該要小心。
我有一個 for 迴圈,它速度慢得難以置信,我花了一些時間才發現大部分的時間都浪費在每次迴圈的 sizeof() 函數上,而且我花了更多時間才發現這個問題一定與我使用了陣列的參考有關。看看以下範例

function test_ref(&$arr) {
$time = time();
for($n=0; $n<sizeof($arr); $n++) {
$x = 1;
}
echo "<br />使用參考的函式花費了 ".(time() - $time)." s";
}

function test_val($arr) {
$time = time();
for($n=0; $n<sizeof($arr); $n++) {
$x = 1;
}
echo "<br />使用值的函數耗時:".(time() - $time)." 秒";
}

// 填入陣列
for($n=0; $n<2000; $n++) {
$ar[] = "test".$n;
}

test_ref($ar);
test_val($ar);
echo "<br />完成";

當我測試它時,第一個函數在 9 秒後完成,而第二個函數(儘管必須複製陣列)不到 1 秒就完成了。

當陣列大小縮小時,差異會不成比例地縮小
當使用 1000 個迴圈時,第一個函數執行了 1 秒,當使用 4000 個迴圈時,甚至在 30 秒後都還沒完成。
5
warnickr at gmail dot com
17 年前
我必須說,在理解所有關於 PHP 參考的解釋時,相當令人困惑,特別是因為我使用了大量的 C 指標。就我所知,PHP 參考在所有實際用途上都與 C 指標相同。我認為很多困惑來自於像下面顯示的範例,人們期望此範例的 C 指標版本會更改 $bar 參考的內容。

<?php
function foo(&$var)
{
$var =& $GLOBALS["baz"];
}
foo($bar);
?>

事實並非如此。實際上,這個範例的 C 指標版本(如下所示)會以完全相同的方式運作(它不會修改 bar 參考的內容)如同 PHP 參考版本一樣。

int baz = 5;
int* bar;
void foo(int* var)
{
var = &baz;
}
foo(bar);

在這種情況下,就像在 PHP 參考的情況下一樣,呼叫 foo(bar) 不會變更 bar 參考的內容。如果你想要變更 bar 參考的內容,那麼你需要使用雙重指標,如下所示

int baz = 5;
int* bar;
void foo(int** var)
{
*var = &baz;
}
foo(&bar);
5
trucex at gmail dot com
17 年前
回覆 Xor 和 Slava

我建議你多讀一些關於 PHP 如何處理記憶體管理的文章。舉以下程式碼為例

<?php

$data
= $_POST['lotsofdata'];
$data2 = $data;
$data3 = $data;
$data4 = $data;
$data5 = $data;

?>

假設我們將 10MB 的資料發佈到這個 PHP 檔案,PHP 會如何處理記憶體?

PHP 使用某種類似的表格,將變數名稱對應到該變數在記憶體中參考的資料。 $_POST 超級全域實際上會是執行中該資料的第一個實例,因此它將是記憶體中參考該資料的第一個變數。它會消耗 10MB。每個 $data 變數都只會指向記憶體中的相同資料。在你變更資料之前,PHP 不會複製它。

以值傳遞變數的作用與我對每個 $data 變數所做的相同。將新名稱指派給相同的資料,沒有顯著的額外負擔。只有當你修改傳遞給函數的資料時,它才必須為該資料分配記憶體。當你將資料傳遞給函數時,以參考方式傳遞變數基本上會執行相同的操作,只是修改它會修改記憶體中已有的資料,而不是將其複製到記憶體中的新位置。

如果為了學習目的,你選擇忽略對這兩種傳遞引數的方法進行基準測試的明顯毫無意義之處,你需要在將資料傳遞給函數時修改資料,才能獲得更準確的結果。
4
cesoid at yahoo dot com
18 年前
回覆 nathan 的文章(他是回覆 iryoku)。

需要注意的是,從程式設計師的角度來看,PHP 的行為與它在內部實際運作的方式有所不同。 Nathan 提到的關於(例如)`$something = $this` 會建立目前物件「副本」的說法,指的是從程式設計師的角度建立「副本」。也就是說,對程式設計師而言,在所有實際用途上,`$something` 都是一個副本,即使內部實際上尚未複製任何東西。例如,更改成員 `$something->somethingVar` 中的資料,不會更改您目前物件的資料(即不會更改 `$this->somethingVar`)。

它在內部實際運作的方式則完全不同。我測試了「複製」一個包含 200,000 個元素的陣列的物件,在您最終更改其中一個副本中的內容之前,幾乎不需要任何時間,因為它只會在必要時才在內部進行複製。原始的賦值操作耗時不到一毫秒,但是當我更改其中一個副本時,耗時大約四分之一秒。不過,只有在我更改 200,000 個元素的陣列時才會發生這種情況,如果我只更改物件的一個整數,耗時又會少於一微秒,因此解譯器似乎夠聰明,可以複製物件的部分變數,而不是全部變數。

結果是,當您將函式更改為傳參考時,只有在函式內部,被傳入的變數的資料被更改時,才會變得更有效率,在這種情況下,傳參考會導致您的程式碼更改原始副本的資料。如果您傳遞一個物件並在該物件中呼叫一個函式,該函式可能會在您不知情的情況下更改該物件,這表示只要原始副本可以被您在函式內對該物件的操作影響,您就應該以傳參考的方式傳遞物件。

我認為這件事情真正的寓意是:
1) 對於任何應該參考並影響原始副本的內容,都使用傳參考的方式傳遞。
2) 對於確定不會在函式中被更改的內容,不要使用傳參考的方式傳遞(對於物件而言,可能無法得知它在呼叫其函式之一時是否會更改自身)。
3) 如果需要在函式內部更改某些內容,但不影響原始副本,請不要以傳參考的方式傳遞,並傳遞需要更改的最小實際部分,而不是傳遞例如一個會只更改其中一個小整數的龐大陣列。

或者,更簡短的版本:只有在您需要參考原始副本時才使用傳參考的方式傳遞!(當您只需要更改一小部分時,不要傳遞龐大的陣列或長字串!)
3
jlaing at gmail dot com
20 年前
當嘗試使用特殊的 `$this` 變數進行物件參考時,我發現這樣做是行不通的。
class foo {
function bar() {
...
$this =& $some_other_foo_obj;
}
}

如果您想模擬此功能,您必須遍歷類別的變數並像這樣賦予參考。

$vars = get_class_vars('foo');
foreach (array_keys($vars) as $field) {
$this->$field =& $some_other_foo_obj->$field;
}

現在,如果您修改 `$this` 中的值,它們也會在 `$some_other_foo_obj` 中被修改,反之亦然。

希望這對某些人有所幫助!

p.s.
developer at sirspot dot com 關於物件參考的註解似乎對我而言不正確。

$temp =& $object;
$object =& $temp->getNext();

與以下程式碼的作用完全相同:

$object =& $object->getNext();

當您將 `$temp` 參考到 `$object` 時,它所做的只是將 `$temp` 作為與 `$object` 相同的記憶體別名,因此執行 `$temp->getNext();` 和 `$object->getNext();` 是在同一個物件上呼叫相同的函式。 如果您不相信我,請試試看。
1
jszoja at gmail dot com
8 年前
請注意對另一個參考的參考。 這樣做可能是不好的做法。

<?php
class Obj1 { public $name = 'Obj1'; }
class
Obj2 { public $name = 'Obj2'; }

$objects = [];
$toLoad = [ 'Obj1', 'Obj2' ];

foreach(
$toLoad as $i => $obj )
{
$ref = new $obj();
$objects[$i] =& $ref; // 對參考的參考
// $objects[$i] = $ref; // 這樣會有效
}

echo
$objects[0]->name;
// 輸出 'Obj2' !
?>
3
zoranbankovic at gmail dot com
14 年前
如果有人想直接將斜線加入多維陣列,可以使用像這樣的遞迴(傳參考)函式。
<?php
function slashit(&$aray, $db_link)
{
foreach (
$aray as $key => &$value)
if(
is_array($value)) slashit($value, $link);
else
$aray[$key] = mysql_real_escape_string($value, $db_link);
}

// 測試:
$fruits = array (
"fruits" => array("a" => "or'ange", "b" => "ban'ana", "c" => "apple'"),
"numbers" => array(1, 2, 3, 4, 5, 6),
"holes" => array("fir'st", 5 => "sec'ond", "thir'd"),
"odma" => "jugo'slavija"
);

// 您必須建立與資料庫的連結,或者可以使用 addslashes 來代替 mysql_real_escape_string 並從函式定義中移除 $link

slashit($fruits, $dbLink);
echo
"<pre>"; print_r($fruits); echo "</pre>";
?>

// 輸出
陣列
(
[fruits] => Array
(
[a] => or\'ange
[b] => ban\'ana
[c] => apple\'
)

[numbers] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
)

[holes] => Array
(
[0] => fir\'st
[5] => sec\'ond
[6] => thir\'d
)

[odma] => jugo\'slavija
)
2
mramirez (at) star (minus) dev (dot) com
19 年前
對於來自 Pascal 的 PHP 程式設計師,
在物件 Pascal (Delphi) 中,
變數參考使用 "absolute" 關鍵字。

PHP 範例

<?php

global $myglobal;

$myglobal = 5;

function
test()
{
global
$myglobal;

/*local*/ $mylocal =& $myglobal;

echo
"local: " . $mylocal . "\n";
echo
"gloal: " . $myglobal . "\n";
}

test();

?>

Pascal 範例

program dontcare;

var myglobal: integer;

procedure test;
var mylocal ABSOLUTE myglobal;
begin
write("local: ", mylocal);
write("global: ", myglobal);
end;

begin
myglobal := 5;
test;
end.

順帶一提,對於區域變數而言,PHP 中的 "local" 關鍵字
可能會受到歡迎 :-)
2
nslater at gmail dot com
19 年前
除了 "Francis dot a at gmx dot net" 所做的筆記之外,您通常不應該在控制結構(例如 FOR)中使用 `sizeof()` 或 `count()` 等函式,因為對於每次迭代都會重複計算相同的值。 這可能會大大減慢速度,無論您是傳值還是傳參考。

通常最好在定義迴圈控制結構之前計算靜態值。

範例

<?php

$intSize
= sizeof($arrData);

for(
$i = 0; $i < $intSize; $n++) {
// 執行一些操作
}

?>
1
Youssef Omar
14 年前
這段程式碼旨在展示當你將物件 A 作為另一個物件 B 的屬性傳遞時,透過物件 B 修改物件 A 的屬性所造成的影響。

<?php
// 作為物件傳遞到另一個類別的資料類別
class A{
public
$info;
function
__construct(){
$this->info = "eeee";
}
}

// B 類別用於修改 A 物件中的 info 屬性
class B_class{
public
$A_obj;

function
__construct($A_obj){
$this->A_obj = $A_obj;
}
public function
change($newVal){
$this->A_obj->info = $newVal;
}
}

// 從 A 建立資料物件
$A_obj = new A();
// 印出 info 屬性
echo 'A_obj info: ' . $A_obj->info . '<br/>';

// 建立 B 物件並將上面建立的 A_obj 傳遞進去
$B_obj = new B_class($A_obj);
// 通過 B 物件印出 info 屬性,以確保它具有相同的值 'eeee'
echo 'B_obj info: ' . $B_obj->A_obj->info . '<br/>';

// 修改 info 屬性
$B_obj->change('xxxxx');
// 通過 B 物件印出 info 屬性,以確保它將值更改為 'xxxxxx'
echo 'B_obj info after change: ' . $B_obj->A_obj->info . '<br/>';
// 從 A_obj 印出 info 屬性,以查看透過 B_obj 所做的變更是否影響到它
echo 'A_obj info: ' . $A_obj->info . '<br/>';

?>

結果

A_obj info: eeee
B_obj info: eeee
B_obj info after change: xxxxx
A_obj info: xxxxx
1
jasonpvp at gmail dot com
16 年前
在迴圈中修改多維陣列的值

$var=array('a'=>array(1,2,3),'b'=>array(4,5,6));

foreach ($var as &$sub) {
foreach ($sub as &$element) {
$element=$element+1;
}
}

var_dump($var);

------------------------------
產生
------------------------------
array(2) {
["a"]=>
array(3) {
[0]=>
int(2)
[1]=>
int(3)
[2]=>
int(4)
}
["b"]=>
array(3) {
[0]=>
int(5)
[1]=>
int(6)
[2]=>
int(7)
}
}
1
grayson at uiuc dot edu
19 年前
我發現了參照的一個微妙特性,它導致我的 PHP 應用程式出現錯誤。簡而言之,如果物件將其成員之一傳遞給以參照作為引數的外部函數,則外部函數可以將該成員轉換為記憶體中匿名位置的參照。

為什麼這會是問題?稍後,當您使用 $a = $b 複製物件時,副本和原始物件會共用記憶體。

解決方案:如果您想要使用參照修改物件成員的函數,則您的物件絕不應該直接將該成員傳遞給函數。它應該先建立該成員的副本。然後將該副本傳遞給函數。然後將該副本的新值複製到您的原始物件成員中。

以下是一些可以重現此特性並演示解決方法的程式碼。

function modify1 ( &$pointer_obj ){
$pointer_obj->property = 'Original Value';
}

function modify2 ( &$pointer_obj ){
$newObj->property = 'Original Value';
$pointer_obj = $newObj;
}

class a {
var $i; # 具有屬性的物件

function corrupt1(){
modify1 ($this->i);
}

function doNotCorrupt1(){
$tmpi = $this->i;
modify1 ($tmpi);
$this->i = $tmpi;
}

function corrupt2(){
modify2 ($this->i);
}

function doNotCorrupt2(){
$tmpi = $this->i;
modify2 ($tmpi);
$this->i = $tmpi;
}

}

$functions = array ('corrupt1', 'corrupt2', 'doNotCorrupt1', 'doNotCorrupt2');

foreach ($functions as $func){

$original = new a;

### 使用四個 $functions 其中之一將一些資料載入到原始物件中
$original->$func();

$copy = $original;

$copy->i->property = "Changed after the copy was made.";

echo "\n{$func}: \$original->i->property = '" . $original->i->property . "'";
}

該腳本產生輸出

corrupt1: $original->i->property = 'Changed after the copy was made.'
corrupt2: $original->i->property = 'Changed after the copy was made.'
doNotCorrupt1: $original->i->property = 'Original Value'
doNotCorrupt2: $original->i->property = 'Original Value'
To Top