Apakah Variabel PHP diteruskan oleh nilai atau dengan referensi?

Jawaban:

312

Ini berdasarkan nilai menurut Dokumentasi PHP .

Secara default, argumen fungsi dilewatkan oleh nilai (sehingga jika nilai argumen di dalam fungsi diubah, itu tidak bisa diubah di luar fungsi). Untuk memungkinkan suatu fungsi memodifikasi argumennya, mereka harus dilewatkan dengan referensi.

Agar argumen ke suatu fungsi selalu dilewatkan oleh referensi, tambahkan sebuah ampersand ( & ) ke nama argumen dalam definisi fungsi.

<?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.'
?>
Michael Stum
sumber
4
Saya juga memiliki keraguan ini (pemula) - jadi hanya untuk memperjelas, ini akan sama seperti $str = add_some_extra($str);jika saya tidak menggunakan referensi, kan? lalu apa nilai tambah nyata dari itu?
Obmerk Kronen
7
@ Omb Jika Anda tidak menggunakan ampersand untuk menandakan dengan referensi, itu tidak akan setara. Perhatikan bagaimana fungsi tidak memiliki pernyataan pengembalian, sehingga $strakan ditugaskan nol, dalam kasus Anda.
The Unknown Dev
jika Anda melakukannya dengan cara ini @ObmerkKronen maka Anda harus mengembalikan nilainya dan menangkapnya juga melalui kode Anda. Variabel awal akan tetap sama jika tidak.
Nabeel Khan
Saya ingin tahu apakah pass by reference memiliki beberapa manfaat kinerja atau tidak? Saya melewati array besar & secara default itu lulus dengan nilai. Jadi, jika saya menggunakan panggilan dengan referensi, apakah akan ada manfaat kinerja bijaksana ??? (menjaga nilai array tidak berubah selama seluruh proses)
Choxx
4
manfaat sebenarnya adalah Anda dapat memanipulasi / mengembalikan nilai muliple. Anda juga dapat melewati variabel dengan referensi dan masih membiarkan fungsi mengembalikan sesuatu.
Martin Schneider
65

Dalam PHP, secara default objek dilewatkan sebagai salinan referensi ke objek baru.

Lihat contoh ini .............

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

Sekarang lihat ini ..............

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.

Sekarang lihat ini ..............

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.

saya harap kamu bisa mengerti ini.

hardik
sumber
1
Ini menggambarkan dengan sangat baik bagaimana PHP menangani objek bekerja.
Frederik Krautwald
2
1st ex, nilai referensi dari objek diteruskan ke fungsi, perubahan pada objek menggunakan referensi baru akan mencerminkan semua referensi lain yang menunjuk ke objek yang sama. 2nd ex, lagi NILAI dari referensi objek diteruskan ke fungsi, fungsi mengubah nilai referensi untuk menunjuk ke objek baru, objek lama tetap sama. 3 ex, referensi nilai referensi obj diteruskan ke fungsi, sehingga perubahan fungsi beroperasi pada objek yang sama.
s-hunter
Contoh sempurna dan persis apa yang saya pikir akan terjadi. Saya pendatang baru di PHP (dari latar belakang Javascript / node.js) dan kadang-kadang sulit untuk memahami apa yang terjadi, tetapi ini sangat jelas!
TKol
Contoh ini tidak perlu rumit. $ytidak diperlukan - tidak ada di function changeValuedalamnya yang mengharuskannya berada di dalam class Y, sehingga menyatukan dua konsep yang tidak terkait. Saya akan pindah function changeValueke lingkup luar, tepat di atas $x = new X();. Hapus semua referensi $y. Sekarang lebih mudah untuk melihat bahwa dua contoh pertama meninggalkan $ x sendirian, dan yang ketiga mengubah isinya new Y(). Yang akan lebih mudah untuk melihat apakah Anda membuang typedari $x- fakta bahwa kedua Xdan Yterjadi untuk menyertakan $abclapangan juga tidak relevan dengan apa yang ditunjukkan
ToolmakerSteve
60

Tampaknya banyak orang menjadi bingung dengan cara benda dilewatkan ke fungsi dan apa artinya lewat referensi. Variabel objek masih dilewati oleh nilai, hanya saja nilai yang diteruskan dalam PHP5 adalah pegangan referensi. Sebagai bukti:

<?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";

Keluaran:

a, b

Untuk lulus dengan referensi berarti kita dapat memodifikasi variabel yang dilihat oleh pemanggil. Yang jelas kode di atas tidak bisa. Kita perlu mengubah fungsi swap ke:

<?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";

Keluaran:

b, a

untuk melewati referensi.

grom
sumber
18
Saya pikir bukti ini adalah salah tafsir. Sepertinya Anda mencoba bertukar referensi. Anda memiliki masalah dengan bagaimana objek ditugaskan. Anda sedang menetapkan kembali referensi yang tidak dapat diubah. Nilai yang ditunjukkannya dapat diubah dari dalam. Redefinisi swap sekarang melewati ** x, yang memungkinkan Anda untuk mengubah * x. Masalahnya adalah dalam berpikir bahwa $ x = $ y akan mengubah apa $ poin awalnya.
Grantwparks
9
Ini bukan bukti . Output dari contoh pertama adalah persis apa yang Anda harapkan jika nilai saat ini dari seluruh objek diteruskan ke swapfungsi; dengan kata lain, jika objek "dilewati oleh nilai". Di sisi lain, itu juga persis seperti yang Anda harapkan jika sebuah pegangan objek dilewatkan ke fungsi, yang sebenarnya yang terjadi. Kode Anda tidak membedakan antara dua kasus ini.
EML
31

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

Di PHP 5 ada Model Objek baru. Penanganan objek PHP telah sepenuhnya ditulis ulang, memungkinkan kinerja yang lebih baik dan lebih banyak fitur. Dalam versi PHP sebelumnya, objek ditangani seperti tipe primitif (misalnya integer dan string). Kelemahan dari metode ini adalah bahwa secara semantik seluruh objek disalin ketika variabel ditugaskan, atau diteruskan sebagai parameter ke metode. Dalam pendekatan baru, objek direferensikan oleh pegangan, dan bukan oleh nilai (orang dapat menganggap pegangan sebagai pengidentifikasi objek).

Karl Seguin
sumber
25

Variabel PHP ditugaskan oleh nilai, diteruskan ke fungsi dengan nilai, dan ketika berisi / mewakili objek dilewatkan oleh referensi. Anda dapat memaksa variabel untuk lulus dengan referensi menggunakan &

Ditugaskan oleh nilai / contoh referensi:

$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";

print ("var1: $var1, var2: $var2, var3: $var3);

akan menghasilkan

var1: tes, var2: tes akhir, var3: tes akhir

Lulus oleh nilai / referensi contoh:

$var1 = "foo";
$var2 = "bar";

changeThem($var1, $var2);

print "var1: $var1, var2: $var2";

function changeThem($var1, &$var2){
    $var1 = "FOO";
    $var2 = "BAR";
}

akan menghasilkan:

v1: foo, var2 BAR

Variabel objek yang dilewatkan oleh contoh referensi:

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";
}

Akan menghasilkan:

FOO

(contoh terakhir itu mungkin lebih baik ...)

cmcculloh
sumber
2
"Objek" bukan nilai dalam PHP5 dan tidak dapat "diteruskan". Nilai $fooadalah pointer ke objek . $fooadalah lewat nilai ke fungsi changeFoo(), seperti changeFoo()tidak menyatakan parameter yang dengan &.
newacct
9

Anda bisa meneruskan variabel ke fungsi dengan referensi. Fungsi ini akan dapat memodifikasi variabel asli.

Anda dapat mendefinisikan bagian dengan referensi dalam definisi fungsi:

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

$result=5;
changeValue($result);

echo $result; // $result is 6 here
?>
Mahsin
sumber
6

Anda dapat melakukannya dengan cara apa pun.

letakkan simbol '&' di depan dan variabel yang Anda lewati menjadi satu dan sama dengan asalnya. yaitu: Anda dapat melewati referensi, daripada membuat salinannya.

begitu

    $fred = 5;
    $larry = & $fred;
    $larry = 8;
    echo $fred;//this will output 8, as larry and fred are now the same reference.
Bingy
sumber
2
Ini sudah usang dan menghasilkan peringatan
fijiaaron
5

Variabel yang mengandung tipe primitif diteruskan oleh nilai dalam PHP5. Variabel yang berisi objek dilewatkan dengan referensi. Ada artikel yang cukup menarik dari Linux Journal dari 2006 yang menyebutkan ini dan perbedaan OO lainnya antara 4 dan 5.

http://www.linuxjournal.com/article/9170

Polsonby
sumber
Semua variabel dilewatkan oleh nilai dalam PHP jika parameter fungsi tidak memiliki &.
newacct
1

Objek dilewatkan dengan referensi dalam PHP 5 dan dengan nilai dalam PHP 4. Variabel dilewatkan oleh nilai secara default!

Baca di sini: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html

Miha
sumber
"Objek" bukan nilai dalam PHP5 dan tidak dapat "diteruskan". Semua variabel diteruskan oleh nilai jika parameter fungsi yang diteruskan tidak memiliki &.
newacct
@newacct tidak cukup? Objek agak disahkan oleh referensi . Saya pikir saya telah mengamati bahwa objek php dapat dimodifikasi oleh fungsi bahkan ketika tidak didefinisikan dengan &di depan parameter dalam definisi - jika mereka diteruskan oleh nilai objek yang terdapat dalam lingkup yang disebut fungsi dengan itu sebagai parameter akan tidak terpengaruh.
Félix Gagnon-Grenier
3
@ FélixGagnon-Grenier: Sekali lagi, "objek" bukan nilai dan tidak bisa "diteruskan". Anda tidak dapat memiliki "variabel" di PHP5 yang nilainya adalah "objek", Anda hanya dapat memiliki nilai yang merupakan referensi objek (yaitu penunjuk ke objek). Tentu saja Anda dapat meneruskan atau menetapkan pointer ke objek dengan nilai dan memodifikasi objek yang ditunjuknya dengan memanggil metode yang melakukan modifikasi tersebut. Itu tidak ada hubungannya dengan referensi lewat. Apa jenis nilai dan apakah suatu parameter pass-by-value / pass-by-reference adalah hal-hal yang independen dan ortogonal.
Newacct
1
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>";

Atribut masih dapat dimodifikasi ketika tidak dilewati oleh referensi jadi waspadalah.

Keluaran:

SwapObjects: b, a SwapValues: a, b

Ricardo Saracino
sumber
1

Bagi siapa saja yang menemukan ini di masa mendatang, saya ingin membagikan permata ini dari dokumen PHP, yang diposting oleh pengguna anonim :

Tampaknya ada beberapa kebingungan di sini. Perbedaan antara petunjuk dan referensi tidak terlalu membantu. Perilaku dalam beberapa contoh "komprehensif" yang sudah diposting dapat dijelaskan dengan istilah pemersatu yang lebih sederhana. Kode Hayley, misalnya, melakukan PERSIS apa yang seharusnya Anda harapkan. (Menggunakan> = 5.3)

Prinsip pertama: Pointer menyimpan alamat memori untuk mengakses objek. Setiap kali suatu objek ditetapkan, sebuah pointer dihasilkan. (Saya belum menggali terlalu dalam ke mesin Zend, tapi sejauh yang saya bisa lihat, ini berlaku)

Prinsip 2, dan sumber yang paling membingungkan: Melewati variabel ke fungsi dilakukan secara default sebagai pass nilai, yaitu, Anda bekerja dengan salinan. "Tapi benda-benda dilewatkan dengan referensi!" Kesalahpahaman umum di sini dan di dunia Jawa. Saya tidak pernah mengatakan salinan APA. Pengoperan default dilakukan berdasarkan nilai. Selalu. APA yang sedang disalin dan dilewati, adalah penunjuknya. Saat menggunakan "->", Anda tentu saja akan mengakses internal yang sama dengan variabel asli dalam fungsi pemanggil. Hanya menggunakan "=" hanya akan bermain dengan salinan.

Prinsip 3: "&" secara otomatis dan permanen menetapkan nama variabel lain / penunjuk ke alamat memori yang sama dengan yang lain sampai Anda memisahkannya. Benar menggunakan istilah "alias" di sini. Anggap saja bergabung dengan dua petunjuk di pinggul sampai dipisahkan secara paksa dengan "tidak disetel ()". Fungsionalitas ini ada dalam lingkup yang sama dan saat argumen dilewatkan ke suatu fungsi. Seringkali argumen yang diteruskan disebut "referensi," karena perbedaan tertentu antara "lewat nilai" dan "lewat referensi" yang lebih jelas dalam C dan C ++.

Ingat saja: pointer ke objek, bukan objek itu sendiri, diteruskan ke fungsi. Pointer ini adalah SALINAN dari yang asli kecuali Anda menggunakan "&" di daftar parameter Anda untuk benar-benar melewati aslinya. Hanya ketika Anda menggali bagian dalam suatu objek, dokumen aslinya akan berubah.

Dan inilah contoh yang mereka berikan:

<?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.
}

?>

Saya menulis posting blog yang luas dan terperinci tentang subjek ini untuk JavaScript , tetapi saya percaya itu berlaku juga untuk PHP, C ++, dan bahasa lain di mana orang-orang tampaknya bingung tentang nilai demi nilai vs per referensi.

Jelas, PHP, seperti C ++, adalah bahasa yang mendukung referensi per referensi. Secara default, objek dilewatkan oleh nilai. Ketika bekerja dengan variabel yang menyimpan objek, ada baiknya untuk melihat variabel-variabel itu sebagai pointer (karena pada dasarnya seperti apa mereka, di tingkat perakitan). Jika Anda melewatkan pointer berdasarkan nilai, Anda masih bisa "melacak" pointer dan memodifikasi properti objek yang ditunjuk. Yang tidak bisa Anda lakukan adalah mengarahkannya ke objek lain. Hanya jika Anda secara eksplisit mendeklarasikan parameter yang dilewatkan oleh referensi Anda akan dapat melakukannya.

AleksandrH
sumber
0

Sebenarnya kedua metode ini valid tetapi tergantung pada kebutuhan Anda. Nilai-nilai kecepatan dengan referensi sering membuat skrip Anda lambat. Jadi lebih baik untuk melewatkan variabel berdasarkan nilai dengan mempertimbangkan waktu eksekusi. Alur kode juga lebih konsisten ketika Anda melewatkan variabel berdasarkan nilai.

atif
sumber
0

Gunakan ini untuk fungsi ketika Anda hanya ingin mengubah variabel asli dan mengembalikannya ke nama variabel yang sama dengan nilai baru yang ditetapkan.

function add(&$var){ // The &amp; 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
PPL
sumber
-7

Bergantung pada versi, 4 berdasarkan nilai, 5 berdasarkan referensi.

Karl Seguin
sumber
11
Saya pikir ini tidak benar.
Nick Heiner
@ Karl Seguin, sebagian benar. Sebelum objek PHP5 secara default diteruskan oleh nilai tetapi sejak 5 mereka dilewatkan oleh handler, yang dalam praktiknya dapat diperlakukan sebagai referensi (dengan beberapa pengecualian) karena kita dapat memodifikasi properti objek melalui mereka php.net/manual/en/language. oop5.references.php .
Adam Faryna