2024 年 PHP 日本研討會

傳回參考

當您想要使用函式來尋找參考應繫結至哪個變數時,以參考傳回會很有用。不要使用以參考傳回來提高效能。引擎會自行自動最佳化。只有在您有合理的技術理由時才傳回參考。要傳回參考,請使用以下語法

<?php

class Foo
{
public
$value = 42;

public function &
getValue()
{
return
$this->value;
}
}

$obj = new Foo();
$myValue = &$obj->getValue(); // $myValue 是 $obj->value 的參考,其值為 42
$obj->value = 2;
echo
$myValue; // 輸出 $obj->value 的新值,即 2

?>
在此範例中,會設定由 getValue 函式返回的物件屬性,而不是像未使用參考語法時返回的副本。

注意 與參數傳遞不同,這裡您必須在兩個地方都使用 & 符號 — 表示您要透過參考返回,而不是副本,並且表示應該為 $myValue 進行參考綁定,而不是一般的賦值。

注意 如果您嘗試使用以下語法從函式返回參考:return ($this->value); 這將*不會*生效,因為您嘗試透過參考返回一個*表達式*的結果,而不是一個變數。您只能從函式返回變數的參考 — 其他都不行。

要使用返回的參考,您必須使用參考賦值

<?php

function &collector()
{
static
$collection = array();
return
$collection;
}

$collection = &collector();
$collection[] = 'foo';

?>
要將返回的參考傳遞給另一個需要參考的函式,您可以使用以下語法
<?php

function &collector()
{
static
$collection = array();
return
$collection;
}

array_push(collector(), 'foo');

?>

注意 請注意,array_push(&collector(), 'foo'); 將*不會*生效,它會導致致命錯誤。

新增筆記

使用者貢獻的筆記 18 則筆記

Spad-XIII
16 年前
補充 minikomp.com 網站上 pixel 的範例
<?php

function &func(){
static
$static = 0;
$static++;
return
$static;
}

$var1 =& func();
echo
"var1:", $var1; // 1
func();
func();
echo
"var1:", $var1; // 3
$var2 = func(); // 未使用 & 的賦值
echo "var2:", $var2; // 4
func();
func();
echo
"var1:", $var1; // 6
echo "var2:", $var2; // 仍然是 4

?>
szymoncofalik at gmail dot com
13 年前
有時候,您會希望使用返回參考的函式返回 NULL,以表示元素鏈的結束。然而,這會產生 E_NOTICE。這裡有一個小技巧,可以防止這種情況發生

<?php
class Foo {
const
$nullGuard = NULL;
// ... 一些宣告和定義
public function &next() {
// ...
if (!$end) return $bar;
else return
$this->nullGuard;
}
}
?>

這樣做可以避免出現通知,例如:

<?php
$f
= new Foo();
// ...
while (($item = $f->next()) != NULL) {
// ...
}
?>

您也可以使用全域變數
global $nullGuard;
return $nullGuard;
stanlemon at mac dot com
17 年前
我還沒看到有人提到 PHP5 中的方法鏈。當一個物件被 PHP5 中的一個方法返回時,預設情況下它是以參考方式返回的,新的 Zend Engine 2 允許您鏈式調用從這些返回物件的方法。例如,考慮以下程式碼

<?php

類別 Foo {

受保護的
$bar;

公開 function
__construct() {
$this->bar = new Bar();

echo
"Foo\n";
}

公開 function
getBar() {
return
$this->bar;
}
}

類別
Bar {

公開 function
__construct() {
echo
"Bar\n";
}

公開 function
helloWorld() {
echo
"Hello World\n";
}
}

函式
test() {
return new
Foo();
}

test()->getBar()->helloWorld();

?>

請注意我們是如何呼叫 test() 函式的,它並非在物件上呼叫,而是返回一個 Foo 的實例,接著呼叫 Foo 的方法 getBar(),該方法返回一個 Bar 的實例,最後呼叫 Bar 的方法 helloWorld()。熟悉其他直譯式語言(例如 Java)的人應該會認出這個功能。 不知何故,這個變更似乎沒有被很好地記錄,所以希望有人會覺得這很有幫助。
obscvresovl at NOSPAM dot hotmail dot com
19 年前
返回參考的範例

<?

$var = 1;
$num = NULL;

函式 &blah()
{
$var =& $GLOBALS["var"]; # 與 global $var; 相同;
$var++;
return $var;
}

$num = &blah();

echo $num; # 2

blah();

echo $num; # 3

?>

注意:如果您從函式中移除 &,則第二次 echo 將會是 2,因為沒有 & 的情況下,變數 $num 包含的是其回傳值,而不是其回傳的參考。
sandaimespaceman at gmail dot com
16 年前
&b() 函式返回全域範圍內 $a 的參考。

<?php
$a
= 0;
函式 &
b()
{
全域
$a;
return
$a;
}
$c = &b();
$c++;
echo
"
\$a:
$a
\$b:
$c
"
?>

它會輸出

$a: 1 $b: 1
fabian dot picone at gmail dot com
6 年前
此注意事項似乎不適用於 PHP 7

「注意:如果您嘗試使用以下語法從函式返回參考:return ($this->value); 這將不起作用,因為您嘗試返回表達式的結果,而不是變數的參考。您只能從函式返回變數的參考——不能返回其他任何東西。自 PHP 5.1.0 起,如果程式碼嘗試返回動態表達式或 new 運算子的結果,則會發出 E_NOTICE 錯誤。」

錯誤回報:以下程式碼執行沒有錯誤輸出。結果與沒有使用大括號包住 $this-value 相同。

<?php

class foo {
public
$value = 42;

public function &
getValue() {
return (
$this->value);
}
}

$obj = new foo;
$myValue = &$obj->getValue();
$obj->value = 2;
echo
$myValue;
rwruck
18 年前
關於回傳參考時使用括號的說明僅在您嘗試回傳的變數尚未包含參考時才成立。

<?php
// 將回傳一個參考
function& getref1()
{
$ref =& $GLOBALS['somevar'];
return (
$ref);
}

// 將回傳一個值(並發出一個通知)
function& getref2()
{
$ref = 42;
return (
$ref);
}

// 將回傳一個參考
function& getref3()
{
static
$ref = 42;
return (
$ref);
}
?>
civilization28 at gmail dot com
10 年前
Zayfod 上面的例子很有用,但我覺得需要更多說明。應該指出的是,以參考傳入的參數可以更改為參考其他內容,導致稍後對局部變數的更改不會影響傳入的變數。

<?php

function & func_b ()
{
$some_var = 2;
return
$some_var;
}

function
func_a (& $param)
{
# $param 此處為 1
$param = & func_b(); # 此處更改了參考,並且
# "func_a (& $param)" 中的 "&"
# 根本不再有效。
# $param 此處為 2
$param++; # 對 $var 沒有影響。
}

$var = 1;
func_a($var);
# $var 此處仍然是 1!!!因為參考已更改。

?>
benjamin dot delespierre at gmail dot com
13 年前
請記住,使用 __callStatic 時,透過參考回傳值的功能無效。

<?php
class Test {
private static
$_inst;
public static function &
__callStatic ($name, $args) {
if (!isset(static::
$_inst)){
echo
"create";
static::
$_inst = (object)"test";
}
return static::
$_inst;
}

var_dump($a = &Test::abc()); // 顯示 'create'
$a = null;
var_dump(Test::abc()); // 不會顯示 'create' 且實例仍然存在於 Test::$_inst 中
?>
hawcue at yahoo dot com
20 年前
使用三元運算子 condition?value1:value2 時要小心。

請參考以下程式碼:

$a=1;
function &foo()
{
global $a;
return isset($a)?$a:null;
}
$b=&foo();
echo $b; // 顯示 1
$b=2;
echo $a; // 顯示 1 (不是 2!因為 $b 取得的是 $a 的副本)

要讓 $b 成為 $a 的參考,請在函式中使用 "if..then.."。
anisgazig at gmail dot com
2 年前
<?php

$a
= 9;
function &
myF(){
global
$a;
return
$a;
}

//修改值之前
$func =& myF();
echo
"$a and $func";
echo
"\n";

//修改值之後
$func++;
echo
"$a and $func";
php at thunder-2000 dot com
17 年前
如果您想取得陣列的一部分來操作,可以使用這個函式:

function &getArrayField(&$array,$path) {
if (!empty($path)) {
if (empty($array[$path[0]])) return NULL;
else return getArrayField($array[$path[0]], array_slice($path, 1));
} else {
return $array;
}
}

使用方法如下:

$partArray =& getArrayField($GLOBALS,array("config","modul1"));

您可以操作 $partArray,並且這些變更也會套用至 $GLOBALS。
zayfod at yahoo dot com
21 年前
文件中關於此頁的說明有一個小例外。當您將透過參考傳遞的值指定給透過參考回傳的函式結果時,您不需要使用 & 來表示應該進行參考繫結。

請參考以下兩個範例:

<?php

函式 & func_b ()
{
$some_var = 2;
return
$some_var;
}

函式
func_a (& $param)
{
# $param 此處為 1
$param = & func_b();
# $param 此處為 2
}

$var = 1;
func_a($var);
# $var 此處仍然是 1!!!

?>

第二個例子按預期工作。

<?php

函式 & func_b ()
{
$some_var = 2;
return
$some_var;
}

函式
func_a (& $param)
{
# $param 此處為 1
$param = func_b();
# $param 此處為 2
}

$var = 1;
func_a($var);
# $var 此處為 2,符合預期

?>

(使用 PHP 4.3.0 的經驗)
spidgorny at gmail dot com
14 年前
當返回函式內部實例化物件成員的參考時,物件會在返回時被解構(這是一個問題)。 看程式碼比較容易理解

<?php

類別 MemcacheArray {
public
$data;

...

/**
* 超聰明的一行快取讀取和寫入!
* 用法 $data = &MemcacheArray::getData(__METHOD__);
* 希望 PHP 會知道 $this->data 仍在使用中
* 並在資料更改後呼叫解構函式。
* 糟糕,情況並非如此。
*
* @return unknown
*/
函式 &getData($file, $expire = 3600) {
$o = new MemcacheArray($file, $expire);
return
$o->data;
}
?>

在這裡,解構函式在 return() 時被呼叫,參考變成一個普通的變數。

我的解決方案是將物件儲存在一個池中,直到最後的 exit(),但我不喜歡這樣。 有其他想法嗎?

<?php
protected static $instances = array();

function &
getData($file, $expire = 3600) {
$o = new MemcacheArray($file, $expire);
self::$instances[$file] = $o; // 避免物件過早解構
return $o->data;
}
?>
匿名
10 年前
我在使用一個會傳遞參照的類別方法時學到了一個慘痛的教訓。

簡而言之,如果你的類別中有一個在宣告時使用「&」符號初始化的方法,在使用該方法時不要再使用「&」符號,例如 &$this->method();

例如:
<?php
class A {
public function &
hello(){
static
$a='';
return
$a;
}
public function
bello(){
$b=&$this->hello(); // 錯誤。不要使用「&」符號。
$b=$this->hello(); // $b 是靜態變數的參考。
}
?>
jpenna
4 年前
你可以設定透過參照傳回的變數值,無論它是靜態函式變數還是物件的私有屬性(這相當危險)。

靜態函式變數

<?php
function &func(){
static
$static = 0;
return
$static;
}

$var1 =& func();
echo
"var1:", $var1, "\n"; // 0
func();

$var1 = 90;
echo
"var1:", $var1, "\n"; // 90
echo "static:", func(), "\n"; // 90
?>

私有屬性

<?php
class foo {
private
$value = 1;

public function &
getValue() {
return
$this->value;
}

public function
setValue($val) {
$this->value = $val;
}
}

$obj = new foo;
$myValue = &$obj->getValue(); // $myValue 是 $obj->value 的參考,其值為 1。
echo $obj->getValue(); // 1
echo $myValue; // 1
$obj->setValue(5);
echo
$obj->getValue(); // 5
echo $myValue; // 5
$myValue = 1000;
echo
$obj->getValue(); // 1000
echo $myValue; // 1000
?>
contact at infopol dot fr
20 年前
關於在非參考陣列中嵌入傳回參考的注意事項

<?
$foo;

function bar () {
global $foo;
$return = array();
$return[] =& $foo;
return $return;
}

$foo = 1;
$foobar = bar();
$foobar[0] = 2;
echo $foo;
?>

結果為「2」,因為參考被複製了(相當巧妙)。
willem at designhulp dot nl
19 年前
PHP5 和 PHP4 在參考方面有一個重要的區別。

假設您有一個類別,其中有一個名為 'get_instance' 的方法,用於取得現有類別及其屬性的參考。

<?php
class mysql {
function
get_instance(){
// 檢查物件是否存在
if(empty($_ENV['instances']['mysql'])){
// 尚無物件,建立一個物件
$_ENV['instances']['mysql'] = new mysql;
}
// 傳回物件的參考
$ref = &$_ENV['instances']['mysql'];
return
$ref;
}
}
?>

現在要取得現有的物件,您可以使用
mysql::get_instance();

雖然這在 PHP4 和 PHP5 中都能運作,但在 PHP4 中,所有資料都會遺失,就像它是一個新的物件一樣,而在 PHP5 中,物件中的所有屬性都會保留。
To Top