Apa itu petikan
Petikan dalam PHP bermakna mengakses kandungan pembolehubah yang sama dengan nama yang berbeza. Ini bukan seperti penunjuk C sebaliknya, rujukannya ialah alias jadual simbol. Ambil perhatian bahawa dalam PHP, nama pembolehubah dan kandungan pembolehubah adalah berbeza, jadi kandungan yang sama boleh mempunyai nama yang berbeza. Analogi terdekat ialah nama fail Unix dan fail itu sendiri - nama pembolehubah ialah entri direktori, dan kandungan pembolehubah ialah fail itu sendiri. Rujukan boleh dianggap sebagai pautan keras dalam sistem fail Unix.
Apa yang dilakukan oleh petikan
Rujukan PHP membenarkan dua pembolehubah menunjuk ke kandungan yang sama. Maksudnya, apabila melakukan ini:
<?php $a =& $b; ?>
Ini bermakna $a dan $b menunjuk kepada pembolehubah yang sama.
Nota:
$a dan $b adalah betul-betul sama di sini, bukannya $a menunjuk ke $b atau sebaliknya, tetapi $a dan $b menunjuk ke tempat yang sama.
Nota:
Jika tatasusunan dengan rujukan disalin, nilainya tidak akan dinyahrujuk. Perkara yang sama berlaku untuk menghantar nilai tatasusunan kepada fungsi.
Nota:
Jika pembolehubah yang tidak ditentukan ditetapkan melalui rujukan, diluluskan melalui rujukan atau dikembalikan melalui rujukan, pembolehubah itu akan dibuat secara automatik.
Contoh #1 Menggunakan rujukan kepada pembolehubah tidak ditentukan
<?php function foo(&$var) { } foo($a); // $a is "created" and assigned to null $b = array(); foo($b['b']); var_dump(array_key_exists('b', $b)); // bool(true) $c = new StdClass; foo($c->d); var_dump(property_exists($c, 'd')); // bool(true) ?>
Sintaks yang sama boleh digunakan dalam fungsi, yang mengembalikan rujukan dan dalam operator baharu (PHP 4.0.4 dan lebih baharu):
<?php $bar =& new fooclass(); $foo =& find_var($bar); ?>
Mulai PHP 5, new secara automatik mengembalikan rujukan, jadi menggunakan =& di sini adalah usang dan menghasilkan mesej peringkat E_STRICT.
Nota:
Tidak menggunakan operator & menyebabkan salinan objek dijana. Jika anda menggunakan $this dalam kelas, ia akan digunakan pada tika semasa kelas itu. Tugasan tanpa & akan menyalin contoh (cth. objek) dan $ini akan digunakan pada salinan, yang tidak selalu merupakan hasil yang diingini. Disebabkan masalah prestasi dan penggunaan memori, anda biasanya hanya mahu bekerja pada satu contoh.
Walaupun adalah mungkin untuk menyekat sebarang mesej ralat dalam pembina menggunakan operator @, seperti @new, ini tidak mempunyai kesan apabila menggunakan pernyataan &new. Ini adalah pengehadan enjin Zend dan akan menyebabkan ralat penghuraian.
Amaran
Jika rujukan diberikan kepada pembolehubah yang diisytiharkan sebagai global di dalam fungsi, rujukan hanya boleh dilihat di dalam fungsi. Ini boleh dielakkan dengan menggunakan tatasusunan $GLOBALS.
Contoh #2 Rujukan pembolehubah global dalam fungsi
<?php $var1 = "Example variable"; $var2 = ""; function global_references($use_globals) { global $var1, $var2; if (!$use_globals) { $var2 =& $var1; // visible only inside the function } else { $GLOBALS["var2"] =& $var1; // visible also in global context } } global_references(false); echo "var2 is set to '$var2'\n"; // var2 is set to '' global_references(true); echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable' ?>
Fikirkan $var global sebagai singkatan untuk $var =& $GLOBALS['var'];. Oleh itu, memberikan rujukan lain kepada $var hanya mengubah rujukan kepada pembolehubah tempatan.
Nota:
Jika pembolehubah dengan rujukan diberikan nilai dalam setiap pernyataan, objek yang dirujuk juga ditukar.
Contoh #3 Petikan dan pernyataan foreach
<?php $ref = 0; $row =& $ref; foreach (array(1, 2, 3) as $row) { // do something } echo $ref; // 3 - last element of the iterated array ?>
Perkara kedua yang dilakukan oleh rujukan ialah lulus pembolehubah melalui rujukan. Ini dicapai dengan mencipta pembolehubah tempatan dalam fungsi dan pembolehubah itu merujuk kandungan yang sama dalam skop panggilan. Contohnya:
<?php function foo(&$var) { $var++; } $a=5; foo($a); ?>
akan menukar $a kepada 6. Ini kerana dalam fungsi foo pembolehubah $var menunjuk kepada perkara yang sama yang $a tunjuk. Lihat Melewati Rujukan untuk penjelasan yang lebih terperinci.
Perkara ketiga yang dilakukan oleh rujukan ialah pemulangan rujukan.
Apa yang bukan petikan
Seperti yang dinyatakan sebelum ini, rujukan bukan petunjuk. Ini bermakna struktur berikut tidak akan menghasilkan kesan yang diharapkan:
<?php function foo(&$var) { $var =& $GLOBALS["baz"]; } foo($bar); ?>
Ini akan menyebabkan pembolehubah $var dalam fungsi foo terikat kepada $bar apabila fungsi dipanggil, tetapi kemudian terikat semula kepada $GLOBALS["baz"]. Tidak mungkin untuk mengikat $bar kepada pembolehubah lain dalam skop panggilan fungsi melalui mekanisme rujukan, kerana tiada pembolehubah $bar dalam fungsi foo (ia diwakili sebagai $var, tetapi $var hanya mempunyai kandungan berubah dan tiada panggilan simbol jadual nama-ke-nilai mengikat). Anda boleh menggunakan pulangan rujukan kepada pembolehubah rujukan yang dipilih oleh fungsi.
Lulus dengan rujukan
Anda boleh menghantar pembolehubah dengan merujuk kepada fungsi supaya fungsi itu boleh mengubah suai nilai hujahnya. Sintaksnya adalah seperti berikut:
<?php function foo(&$var) { $var++; } $a=5; foo($a); // $a is 6 here ?>
Perhatikan bahawa tiada simbol rujukan dalam panggilan fungsi - hanya dalam definisi fungsi. Definisi fungsi sahaja sudah cukup untuk parameter diluluskan dengan rujukan dengan betul. Dalam versi PHP terbaharu, jika anda menggunakan & in foo(&$a); anda akan mendapat amaran bahawa "rujukan laluan masa panggilan" tidak digunakan.
Perkara berikut boleh diluluskan dengan rujukan:
Pembolehubah, seperti foo($a)
Pernyataan baharu, seperti foo(foobar baharu())
Rujukan dikembalikan daripada fungsi, contohnya:
<?php function &bar() { $a = 5; return $a; } foo(bar()); ?>
Untuk penjelasan terperinci, lihat pemulangan rujukan.
Sebarang ungkapan lain tidak boleh diluluskan dengan rujukan, dan hasilnya tidak ditentukan. Sebagai contoh, contoh lulus melalui rujukan adalah tidak sah:
<?php function bar() // Note the missing & { $a = 5; return $a; } foo(bar()); // 自 PHP 5.0.5 起导致致命错误 foo($a = 5) // 表达式,不是变量 foo(5) // 导致致命错误 ?>
Syarat ini tersedia dalam PHP 4.0.4 dan versi yang lebih baru.
Kembalikan melalui rujukan
Pulangan rujukan digunakan apabila anda ingin menggunakan fungsi untuk mencari pembolehubah mana rujukan harus terikat. Jangan gunakan rujukan pulangan untuk meningkatkan prestasi, enjin cukup pintar untuk mengoptimumkannya sendiri. Hanya kembalikan rujukan jika ada sebab teknikal yang sah! Untuk mengembalikan rujukan, gunakan sintaks ini:
<?php class foo { public $value = 42; public function &getValue() { return $this->value; } } $obj = new foo; $myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42. $obj->value = 2; echo $myValue; // prints the new value of $obj->value, i.e. 2. ?>
本例中 getValue 函数所返回的对象的属性将被赋值,而不是拷贝,就和没有用引用语法一样。
Note: 和参数传递不同,这里必须在两个地方都用 & 符号——指出返回的是一个引用,而不是通常的一个拷贝,同样也指出 $myValue 是作为引用的绑定,而不是通常的赋值。
Note: 如果试图这样从函数返回引用:return ($this->value);,这将不会起作用,因为在试图返回一个表达式的结果而不是一个引用的变量。只能从函数返回引用变量——没别的方法。如果代码试图返回一个动态表达式或 new 运算符的结果,自 PHP 4.4.0 和 PHP 5.1.0 起会发出一条 E_NOTICE 错误。
<?php function &test(){ static $b=0;//申明一个静态变量 $b=$b+1; echo $b; return $b; } $a=test();//这条语句会输出$b的值为1 $a=5; $a=test();//这条语句会输出$b的值为2 $a=&test();//这条语句会输出$b的值为3 $a=5; $a=test();//这条语句会输出$b的值为6 ?>
$a=test()方式调用函数,只是将函数的值赋给$a而已,而$a做任何改变化,都不会影响到函数中的$b,而通过$a=&test()方式调用函数呢, 他的作用是将return $b中的$b变量的内存地址与$a变量的内存地址指向了同一个地方,即产生了相当于这样的效果($a=&b;) 所以改变$a的值,也同时改变了$b的值,所以在执行了 $a=&test(); $a=5; 以后,$b的值变为了5。
取消引用
当 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。例如:
<?php $a = 1; $b =& $a; unset($a); ?>
不会 unset $b,只是 $a。
再拿这个和 Unix 的 unlink 调用来类比一下可能有助于理解。
引用定位
许多 PHP 的语法结构是通过引用机制实现的,所以上述有关引用绑定的一切也都适用于这些结构。一些结构,例如引用传递和返回,已经在上面提到了。其它使用引用的结构有:
global 引用
当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用。也就是说和这样做是相同的:
<?php $var =& $GLOBALS["var"]; ?>
这意味着,例如,unset $var 不会 unset 全局变量。
使用unset($a)与$a=null的结果是不一样的。如果该块内存只有$a一个映射,那么unset($a)与$a=null等价,该内存的引用计数变为0,被自动回收;如果该块内存有$a和$b两个映射,那么unset($a)将导致$a=null且$b不变的情况,而$a=null会导致$a=$b=null的情况。
原因:某变量赋值为null,将导致该变量对应的内存块的引用计数直接置为0,被自动回收。
$this
在一个对象的方法中,$this 永远是调用它的对象的引用。
引用的作用
如果程序比较大,引用同一个对象的变量比较多,并且希望用完该对象后手工清除它,个人建议用 "&" 方式,然后用$var=null的方式清除. 其它时候还是用php5的默认方式吧. 另外, php5中对于大数组的传递,建议用 "&" 方式, 毕竟节省内存空间使用。
下面再来个小插曲 php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。
通俗的讲
1:如果有下面的代码
<?ph $a="ABC"; $b=$a; ?>
其实此时,$a与$b都是指向同一内存地址,而并不是$a与$b占用不同的内存。
2:如果在上面的代码基础上再加上如下代码
$a="EFG";
由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断 自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储。