2010-04-26 87 views
62

我似乎無法得到任何一致的信息。不同的消息來源似乎說不同的事情和老的php.net本身(似乎)不明確說明這一點 - 雖然,我必須承認,我只是看了一眼。PHP5對象是否通過引用傳遞?

在我身邊掠過「重」的對象的情況下,我需要通過引用傳遞,但我不想讓打字:

function foo(TypeName& $obj) 

,如果我能逃脫簡直

function foo(TypeName $obj) 

那麼標準說什麼呢?

回答

87

通過引用傳遞(並分配)對象。不需要使用操作員的地址。

授予我鍵入的內容過於簡單但適合您的目的。該documentation狀態:

一個PHP5 OOP的關鍵點的那 經常提到的是「物 被引用在默認情況下通過」。 這並非完全正確。這 部分使用一些例子糾正了一般思想 。

一個PHP引用是一個別名,它允許兩個不同的變量 寫入相同的值。從PHP5, 開始,一個對象變量不再包含對象本身作爲值的 。它只有 包含一個對象標識符 它允許對象訪問器找到 實際的對象。當一個對象是由參數發送的 ,返回或將 分配給另一個變量時,不同的 變量不是別名:它們包含標識符的 副本,它將 指向同一對象。

有關更詳細的解釋(解釋過簡化以及標識符)檢查出this answer

+1

因此,您可以傳遞一個對象標識符的引用? – 2013-10-24 10:21:05

+8

當你傳遞一個對象時,你仍然「通過價值」傳遞。但是,「價值」不是對象本身。值是對象標識符,哪些訪問器( - >)用於查找對象。所以無論何時你傳遞一個對象或者將一個對象分配給別的東西,它都「感覺」像傳遞引用。當使用 - >時,它「感覺」像一個別名。但從技術上講,它不是別名,而是價值是對象標識符的值的副本。如果它是一個別名,重新分配一個完全不同的值會將所有的別名改變爲新的值,但是你會看到它不會使它們成爲別名。 – OCDev 2015-01-08 13:41:33

+0

@OCDev所以每次該對象被克隆?有點資源浪費。 – 2017-06-17 15:38:23

3

從PHP 5開始,所有對象都被傳遞並通過引用來分配。

在PHP 4中,您仍然需要通過明確使用&運算符來指定希望引用傳遞對象的位置。

8

PHP manual

可以通過參考 一個變量傳遞到功能所以該函數可以 修改變量。語法是 如下:

<?php 
function foo(&$var) 
{ 
    $var++; 
} 

$a=5; 
foo($a); 
// $a is 6 here 
?> 

注:有一個 函數調用無符號 - 只有函數定義 。單獨的函數定義 足以正確傳遞參考的參數 。截至PHP 5.3。0,當您在 foo(& $ a);中使用&時,您將收到一條警告,指出「通話時間通過引用」爲 。

而且從What's New in PHP5

在PHP 5中, 對象模型的基礎設施被改寫對象句柄運行 。除非你通過使用 明確克隆一個對象,否則你將永遠不會使用 創建你的對象的場景重複對象 。在PHP 5中,有 既不需要通過 參考由 參考

因此,因此,你需要使用function foo(&$var)語法的唯一一次傳遞對象,也沒有給他們分配的,如果是$ var可能不是的一個實例一類。

+0

我對你的陳述採取了迂腐的例外「因此,只有當你需要使用<< pass by reference >>語法時,如果$ var可能不是一個類的實例」。 還有另外一個重要的情況,你確實希望使用一個類的實例的引用... 如果 - 作爲調用函數的結果,你希望你傳遞的參數指向(指向)一個*不同的實例,那麼你將需要函數來接受通過引用傳遞的參數,並且在函數中你可以將該參數分配給不同的實例。 – 2013-05-15 13:50:40

1

是從PHP5開始,對象通過引用傳遞。沒有必要明確地做到這一點。

http://www.php.net/manual/en/migration5.oop.php

在PHP 5中有個新對象模型。 PHP的對象處理已經完全重寫,可以獲得更好的性能和更多的功能。在以前的PHP版本中,對象被處理爲基本類型(例如整數和字符串)。這種方法的缺點是,在分配變量或作爲參數傳遞給方法時,會在語義上覆制整個對象。在新方法中,對象由句柄引用,而不是由值引用(可以將句柄看作對象的標識符)。

2

簡短回答是。從Objects and references

一個PHP5 OOP的關鍵點的那 經常提到的是「物 被引用在默認情況下通過」。 這並非完全正確。這 部分使用一些例子糾正了一般思想 。

一個PHP引用是一個別名,它允許兩個不同的變量 寫入相同的值。從PHP5, 開始,一個對象變量不再包含對象本身作爲值的 。它只有 包含一個對象標識符 它允許對象訪問器找到 實際的對象。當一個對象是由參數發送的 ,返回或將 分配給另一個變量時,不同的 變量不是別名:它們包含標識符的 副本,它將 指向同一對象。

要緊的是,在讓你擔心的話,你永遠都不會是一個對象的副本,除非你明確地使用克隆關鍵字在函數調用。無論是別名還是標識符都不會改變這一事實。

+0

爲了進一步說明,我有一個作爲'functionName(\ Response $ response)'傳遞的PSR-7響應對象的例子,就像我在PHP 5+中編寫這個'functionName(\ Response&$ response)'一樣?當這是真的,那麼我必須重新思考我的小項目中的一切。 – 2017-01-28 09:46:01

+1

@ZsoltOroszlány在[PSR-7](http://www.php-fig.org/psr/psr-7/)中,根據定義,響應必須是不可變的。這意味着實現必須明確地調用'clone',如在例如[Slim框架](https://github.com/slimphp/Slim/blob/3.7.0/Slim/Http/Response.php#L182)。 – 2017-01-28 14:41:00

4

它似乎更精確一點,對象的值是通過值傳遞的,但對象本身的值是一個指針。這不同於傳遞參考。

http://www.php.net/manual/en/language.oop5.references.php列出的例子很好。在第一組中,$ a = NULL;不會影響$ b,因爲$ a只是一個指針。在第二組中,$ c = NULL;導致$ d也爲NULL,因爲$ d是對$ c的引用。

<?php 
class A { 
    public $foo = 1; 
} 

$a = new A; 
$b = $a; 
$a->foo = 2; 
$a = NULL; 
echo $b->foo."\n"; // 2 

$c = new A; 
$d = &$c; 
$c->foo = 2; 
$c = NULL; 
echo $d->foo."\n"; // Notice: Trying to get property of non-object... 
?> 
1

只是一個例子,其中通過「對象」,由參考是有用的:

class RefTest1 
{ 
    public $foo; 

    public function __construct(RefTest2 &$ref = null) 
    { 
     $this->foo =& $ref; 
    } 
} 

class RefTest2 
{ 
    public $foo; 

    public function __construct(RefTest1 &$ref = null) 
    { 
     $this->foo =& $ref; 
    } 
} 

class RefTest3 
{ 
    public $foo; 

    public function __construct(RefTest2 &$ref = null) 
    { 
     $this->foo =& $ref; 
    } 
} 

class DoCrossRef 
{ 
    public $refTest1; 
    public $refTest2; 

    public function __construct() 
    { 
     $this->refTest1 = new RefTest1($this->refTest2); 
     $this->refTest2 = new RefTest2($this->refTest1); 
    } 

    public function changeReference() 
    { 
     $this->refTest1 = new RefTest3($this->refTest2); 
    } 
} 

在結束RefTest1保持到RefTest2基準和周圍的其他方法,也如果RefTest2對象不存在當時RefTest1已創建。

在致電DoCrossRef->changeReference()之後,RefTest2對象也持有對新的RefTest3對象的引用。

0

下面是確認對象按引用傳遞的另一個示例。

<?php 

// discussion: https://stackoverflow.com/questions/2715026/are-php5-objects-passed-by-reference#_=_ 
class A { 
    public $foo = 1; 
} 

class B { 
    function inc($obj) { 
     $obj->foo++; 
    } 
} 

$objA = new A(); 
$objB = new B(); 
$objB->inc($objA); 

echo "[" . $objA->foo . "]"; // Outputs [2]