Các biến PHP được truyền theo giá trị hoặc bằng tham chiếu?
Các biến PHP được truyền theo giá trị hoặc bằng tham chiếu?
Câu trả lời:
Đó là theo giá trị theo Tài liệu PHP .
Theo mặc định, các đối số hàm được truyền theo giá trị (để nếu giá trị của đối số trong hàm bị thay đổi, nó không bị thay đổi bên ngoài hàm). Để cho phép một hàm sửa đổi các đối số của nó, chúng phải được truyền bằng tham chiếu.
Để có một đối số cho một hàm luôn được truyền bằng tham chiếu, hãy thêm một dấu và ( & ) vào tên đối số trong định nghĩa hàm.
<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // outputs 'This is a string, and something extra.'
?>
$str = add_some_extra($str);
khi tôi không sử dụng tài liệu tham khảo, phải không? Vậy giá trị gia tăng thực sự của nó là gì?
$str
sẽ được gán null, trong trường hợp của bạn.
Trong PHP, theo mặc định các đối tượng được chuyển dưới dạng bản sao tham chiếu đến một Đối tượng mới.
Xem ví dụ này .............
class X {
var $abc = 10;
}
class Y {
var $abc = 20;
function changeValue($obj)
{
$obj->abc = 30;
}
}
$x = new X();
$y = new Y();
echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 30
Bây giờ hãy xem điều này ..............
class X {
var $abc = 10;
}
class Y {
var $abc = 20;
function changeValue($obj)
{
$obj = new Y();
}
}
$x = new X();
$y = new Y();
echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 10 not 20 same as java does.
Bây giờ hãy xem điều này ..............
class X {
var $abc = 10;
}
class Y {
var $abc = 20;
function changeValue(&$obj)
{
$obj = new Y();
}
}
$x = new X();
$y = new Y();
echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 20 not possible in java.
tôi hy vọng bạn có thể hiểu điều này
$y
không cần thiết - không có gì trong function changeValue
đó yêu cầu nó phải ở bên trong class Y
, do đó, kết hợp hai khái niệm không liên quan với nhau. Tôi sẽ chuyển function changeValue
đến phạm vi bên ngoài, ngay phía trên $x = new X();
. Xóa tất cả các tham chiếu đến $y
. Bây giờ dễ dàng hơn để thấy rằng hai ví dụ đầu tiên để lại $ x một mình và ví dụ thứ ba thay đổi nội dung của nó thành new Y()
. Mà sẽ dễ dàng hơn để xem nếu bạn đổ sự type
của $x
- thực tế là cả hai X
và Y
xảy ra để bao gồm một $abc
lĩnh vực cũng là không thích hợp với những gì được thể hiện
Có vẻ như rất nhiều người bị nhầm lẫn bởi cách các đối tượng được truyền đến các hàm và những gì được truyền bởi tham chiếu có nghĩa là gì. Các biến đối tượng vẫn được truyền theo giá trị, nó chỉ là giá trị được truyền trong PHP5 là một điều khiển tham chiếu. Như là bằng chứng:
<?php
class Holder {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
function swap($x, $y) {
$tmp = $x;
$x = $y;
$y = $tmp;
}
$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);
echo $a->getValue() . ", " . $b->getValue() . "\n";
Đầu ra:
a, b
Để vượt qua tham chiếu có nghĩa là chúng ta có thể sửa đổi các biến mà người gọi nhìn thấy. Mà rõ ràng các mã trên không làm. Chúng ta cần thay đổi chức năng hoán đổi thành:
<?php
function swap(&$x, &$y) {
$tmp = $x;
$x = $y;
$y = $tmp;
}
$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);
echo $a->getValue() . ", " . $b->getValue() . "\n";
Đầu ra:
b, a
để vượt qua bằng cách tham khảo.
swap
hàm; nói cách khác, nếu các đối tượng được "truyền theo giá trị". Mặt khác, đó cũng chính xác là những gì bạn mong đợi nếu một đối tượng xử lý được chuyển đến chức năng, đó thực sự là những gì xảy ra. Mã của bạn không phân biệt giữa hai trường hợp này.
http://www.php.net/manual/en/migration5.oop.php
Trong PHP 5 có một Mô hình đối tượng mới. Việc xử lý các đối tượng của PHP đã được viết lại hoàn toàn, cho phép hiệu năng tốt hơn và nhiều tính năng hơn. Trong các phiên bản trước của PHP, các đối tượng được xử lý như các kiểu nguyên thủy (ví dụ: số nguyên và chuỗi). Hạn chế của phương thức này là về mặt ngữ nghĩa, toàn bộ đối tượng được sao chép khi một biến được gán hoặc được truyền dưới dạng tham số cho phương thức. Trong cách tiếp cận mới, các đối tượng được tham chiếu bằng tay cầm chứ không phải theo giá trị (người ta có thể nghĩ về tay cầm như một định danh của đối tượng).
Các biến PHP được gán theo giá trị, được truyền cho các hàm theo giá trị và khi chứa / đại diện cho các đối tượng được truyền bằng tham chiếu. Bạn có thể buộc các biến chuyển qua tham chiếu bằng cách sử dụng &
Được gán bởi giá trị / ví dụ tham chiếu:
$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";
print ("var1: $var1, var2: $var2, var3: $var3);
sẽ xuất
var1: test, var2: thử nghiệm cuối cùng, var3: thử nghiệm cuối cùng
Vượt qua bởi giá trị / tham chiếu exampe:
$var1 = "foo";
$var2 = "bar";
changeThem($var1, $var2);
print "var1: $var1, var2: $var2";
function changeThem($var1, &$var2){
$var1 = "FOO";
$var2 = "BAR";
}
sẽ xuất ra:
var1: foo, var2 BAR
Các biến đối tượng được truyền bởi exampe tham chiếu:
class Foo{
public $var1;
function __construct(){
$this->var1 = "foo";
}
public function printFoo(){
print $this->var1;
}
}
$foo = new Foo();
changeFoo($foo);
$foo->printFoo();
function changeFoo($foo){
$foo->var1 = "FOO";
}
Sẽ xuất:
Thức ăn
(ví dụ cuối cùng có thể tốt hơn có lẽ ...)
$foo
là một con trỏ tới một đối tượng . $foo
được truyền bởi giá trị cho hàm changeFoo()
, vì changeFoo()
không khai báo tham số của nó với a &
.
Bạn có thể truyền một biến cho một hàm bằng cách tham chiếu. Hàm này sẽ có thể sửa đổi biến ban đầu.
Bạn có thể định nghĩa đoạn văn bằng tham chiếu trong định nghĩa hàm:
<?php
function changeValue(&$var)
{
$var++;
}
$result=5;
changeValue($result);
echo $result; // $result is 6 here
?>
Bạn có thể làm một trong hai cách.
đặt biểu tượng '&' ở phía trước và biến bạn đang truyền trở thành một và giống với nguồn gốc của nó. tức là: bạn có thể vượt qua bằng cách tham khảo, thay vì tạo một bản sao của nó.
vì thế
$fred = 5;
$larry = & $fred;
$larry = 8;
echo $fred;//this will output 8, as larry and fred are now the same reference.
Các biến chứa các kiểu nguyên thủy được truyền theo giá trị trong PHP5. Các biến chứa các đối tượng được truyền bằng tham chiếu. Có một bài viết khá thú vị từ Tạp chí Linux từ năm 2006 trong đó đề cập đến sự khác biệt này và các khác biệt OO khác giữa 4 và 5.
&
.
Các đối tượng được truyền bằng tham chiếu trong PHP 5 và theo giá trị trong PHP 4. Các biến được truyền theo giá trị theo mặc định!
Đọc ở đây: http://www.webeks.net/programming/php/ampersand-operator-use-for-assigning-reference.html
&
.
&
trước các tham số trong định nghĩa - nếu chúng được truyền bằng giá trị thì đối tượng chứa trong phạm vi gọi hàm đó là tham số sẽ không bị ảnh hưởng
class Holder
{
private $value;
public function __construct( $value )
{
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
public function setValue( $value )
{
return $this->value = $value;
}
}
class Swap
{
public function SwapObjects( Holder $x, Holder $y )
{
$tmp = $x;
$x = $y;
$y = $tmp;
}
public function SwapValues( Holder $x, Holder $y )
{
$tmp = $x->getValue();
$x->setValue($y->getValue());
$y->setValue($tmp);
}
}
$a1 = new Holder('a');
$b1 = new Holder('b');
$a2 = new Holder('a');
$b2 = new Holder('b');
Swap::SwapValues($a1, $b1);
Swap::SwapObjects($a2, $b2);
echo 'SwapValues: ' . $a2->getValue() . ", " . $b2->getValue() . "<br>";
echo 'SwapObjects: ' . $a1->getValue() . ", " . $b1->getValue() . "<br>";
Các thuộc tính vẫn có thể sửa đổi khi không được chuyển qua tham chiếu vì vậy hãy cẩn thận.
Đầu ra:
SwapObjects: b, a SwapValues: a, b
Đối với bất kỳ ai gặp phải điều này trong tương lai, tôi muốn chia sẻ viên ngọc này từ các tài liệu PHP, được đăng bởi một người dùng ẩn danh :
Dường như có một số nhầm lẫn ở đây. Sự khác biệt giữa con trỏ và tài liệu tham khảo không đặc biệt hữu ích. Hành vi trong một số ví dụ "toàn diện" đã được đăng có thể được giải thích bằng các thuật ngữ thống nhất đơn giản hơn. Mã của Hayley, chẳng hạn, đang thực hiện CHÍNH XÁC những gì bạn nên mong đợi. (Sử dụng> = 5.3)
Nguyên tắc đầu tiên: Một con trỏ lưu địa chỉ bộ nhớ để truy cập một đối tượng. Bất cứ khi nào một đối tượng được chỉ định, một con trỏ được tạo ra. (Tôi chưa đào sâu quá nhiều vào công cụ Zend, nhưng theo như tôi thấy, điều này được áp dụng)
Nguyên tắc thứ 2 và nguồn gốc của sự nhầm lẫn nhất: Truyền một biến cho một hàm được thực hiện theo mặc định là một giá trị vượt qua, tức là bạn đang làm việc với một bản sao. "Nhưng các đối tượng được thông qua tham chiếu!" Một quan niệm sai lầm phổ biến cả ở đây và trong thế giới Java. Tôi chưa bao giờ nói một bản sao. Việc truyền mặc định được thực hiện theo giá trị. Luôn luôn. Những gì đang được sao chép và thông qua, tuy nhiên, là con trỏ. Khi sử dụng "->", tất nhiên bạn sẽ truy cập vào cùng một phần bên trong như biến ban đầu trong hàm người gọi. Chỉ cần sử dụng "=" sẽ chỉ chơi với các bản sao.
Nguyên tắc thứ 3: "&" tự động và đặt vĩnh viễn một tên / con trỏ biến khác vào cùng một địa chỉ bộ nhớ như một thứ khác cho đến khi bạn tách chúng ra. Đó là chính xác để sử dụng thuật ngữ "bí danh" ở đây. Hãy nghĩ về nó như tham gia hai con trỏ ở hông cho đến khi buộc tách ra bằng "unset ()". Chức năng này tồn tại cả trong cùng một phạm vi và khi một đối số được truyền cho một chức năng. Thông thường, đối số được truyền được gọi là "tham chiếu", do sự khác biệt nhất định giữa "truyền theo giá trị" và "chuyển qua tham chiếu" rõ ràng hơn trong C và C ++.
Chỉ cần nhớ: con trỏ tới các đối tượng, không phải chính các đối tượng, được truyền cho các hàm. Những con trỏ này là bản sao của bản gốc trừ khi bạn sử dụng "&" trong danh sách tham số của mình để thực sự vượt qua bản gốc. Chỉ khi bạn đào sâu vào bên trong của một đối tượng thì bản gốc sẽ thay đổi.
Và đây là ví dụ họ cung cấp:
<?php
//The two are meant to be the same
$a = "Clark Kent"; //a==Clark Kent
$b = &$a; //The two will now share the same fate.
$b="Superman"; // $a=="Superman" too.
echo $a;
echo $a="Clark Kent"; // $b=="Clark Kent" too.
unset($b); // $b divorced from $a
$b="Bizarro";
echo $a; // $a=="Clark Kent" still, since $b is a free agent pointer now.
//The two are NOT meant to be the same.
$c="King";
$d="Pretender to the Throne";
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByValue($c, $d);
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByRef($c, $d);
echo $c."\n"; // $c=="Pretender to the Throne"
echo $d."\n"; // $d=="King"
function swapByValue($x, $y){
$temp=$x;
$x=$y;
$y=$temp;
//All this beautiful work will disappear
//because it was done on COPIES of pointers.
//The originals pointers still point as they did.
}
function swapByRef(&$x, &$y){
$temp=$x;
$x=$y;
$y=$temp;
//Note the parameter list: now we switched 'em REAL good.
}
?>
Tôi đã viết một bài đăng trên blog chi tiết, rộng rãi về chủ đề này cho JavaScript , nhưng tôi tin rằng nó cũng áp dụng tốt cho PHP, C ++ và bất kỳ ngôn ngữ nào khác mà mọi người dường như bị nhầm lẫn về việc vượt qua giá trị so với chuyển qua tham chiếu.
Rõ ràng, PHP, giống như C ++, là một ngôn ngữ hỗ trợ chuyển qua tham chiếu. Theo mặc định, các đối tượng được truyền theo giá trị. Khi làm việc với các biến lưu trữ các đối tượng, sẽ giúp xem các biến đó là con trỏ (bởi vì về cơ bản chúng là gì, ở cấp độ lắp ráp). Nếu bạn chuyển một con trỏ theo giá trị, bạn vẫn có thể "theo dõi" con trỏ và sửa đổi các thuộc tính của đối tượng được trỏ tới. Những gì bạn không thể làm là để nó trỏ đến một đối tượng khác. Chỉ khi bạn tuyên bố rõ ràng một tham số được truyền bằng tham chiếu thì bạn mới có thể làm điều đó.
Trên thực tế cả hai phương thức đều hợp lệ nhưng nó phụ thuộc vào yêu cầu của bạn. Các giá trị theo tham chiếu thường làm cho tập lệnh của bạn chậm. Vì vậy, tốt hơn để vượt qua các biến theo giá trị bằng cách xem xét thời gian thực hiện. Ngoài ra, dòng mã phù hợp hơn khi bạn chuyển các biến theo giá trị.
Sử dụng hàm này cho các hàm khi bạn muốn thay đổi biến ban đầu và trả lại cho cùng một tên biến với giá trị mới được gán.
function add(&$var){ // The & is before the argument $var
$var++;
}
$a = 1;
$b = 10;
add($a);
echo "a is $a,";
add($b);
echo " a is $a, and b is $b"; // Note: $a and $b are NOT referenced
Phụ thuộc vào phiên bản, 4 là theo giá trị, 5 là theo tham chiếu.