PHP Değişkenleri değere veya referansa göre mi aktarılıyor?


Yanıtlar:


312

PHP Belgelerine göre değerlidir .

Varsayılan olarak, işlev bağımsız değişkenleri değere göre iletilir (böylece işlev içindeki bağımsız değişkenin değeri değiştirilirse, işlevin dışında değiştirilmez). Bir işlevin bağımsız değişkenlerini değiştirmesine izin vermek için, bunların başvuru ile iletilmesi gerekir.

Her zaman başvuru ile iletilen bir işlevin bağımsız değişkenine sahip olmak için , işlev tanımındaki bağımsız değişken adına bir ve işareti ( & ) ekleyin .

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

4
Ayrıca bu şüphe vardı (acemi) - bu yüzden sadece açık olmak $str = add_some_extra($str);gerekirse, bu referansı kullanmıyormuşum gibi olurdu, değil mi? o zaman bunun gerçek katma değeri nedir?
Obmerk Kronen

7
Eğer olsaydı @Obmerk değil referans olarak göstermek için işareti kullanarak, bu eşdeğer olmaz. İşlevin dönüş ifadesinin nasıl olmadığına dikkat edin, bu $strdurumda sizin durumunuzda null atanır.
Unknown Dev

Eğer bu şekilde @ObmerkKronen yaparsanız, değeri döndürmeniz ve kodunuzdan yakalamanız gerekir. İlk değişken aksi halde aynı kalacaktır.
Nabeel Khan

Referansla geçişin bazı performans faydaları olup olmadığını merak ediyorum? Ben büyük bir dizi geçiyorum & varsayılan olarak bu değer by pass. Yani, referans ile çağrı kullanırsanız, bazı performans akıllıca fayda olacak ??? (tüm süreç boyunca dizi değerlerini değiştirmeden)
Choxx

4
asıl fayda, çoklu değerleri manipüle edebilmeniz / geri verebilmenizdir. Ayrıca değişkenleri referans olarak iletebilir ve yine de işlevin bir şey döndürmesine izin verebilirsiniz.
Martin Schneider

65

PHP'de, varsayılan olarak nesneler yeni bir Nesneye başvuru kopyası olarak iletilir.

Bu örneğe bakın .............

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

Şimdi şuna bakın ..............

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.

Şimdi şuna bakın ..............

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.

umarım bunu anlayabilirsin.


1
Bu, PHP nesnesinin nasıl çalıştığını çok iyi göstermektedir.
Frederik Krautwald

2
1. örnekte, obj referansının değeri fonksiyona aktarılır, yeni referans kullanılarak objde yapılan değişiklikler aynı objeyi işaret eden diğer tüm referanslara yansıyacaktır. 2. örnekte, yine obj referansının DEĞERİ fonksiyona geçirilir, fonksiyon referansın değerini yeni objeye işaret etmek için değiştirir, eski obj aynı kalır. 3. örnekte, obj referansının değerinin referansı fonksiyona aktarılır, böylece fonksiyondaki değişiklikler aynı obj üzerinde çalışır.
s-hunter

Mükemmel örnekler ve tam olarak ne olacağını düşündüm. PHP'ye yeni gelen biriyim (Javascript / node.js arka planından) ve bazen neler olup bittiğini görmek zor, ama bu çok açık!
TKoL

Bu örnek gereksiz yere karmaşıktır. $ygerekli değildir - içinde function changeValueolmasını gerektiren hiçbir şey yoktur class Y, böylece iki ilgisiz kavramı birbirine bağlar. function changeValueHemen hemen dış kapsama giderdim $x = new X();. İçin tüm referansları kaldırın $y. İlk iki örneğin $ x 'ı yalnız bıraktığını ve üçüncüsünün içeriğini değiştirdiğini görmek artık daha kolay new Y(). Terk olmadığını görmek için daha kolay olurdu hangisi typearasında $x- hem gerçeği Xve Ybir içerecek şekilde gerçekleşmesi $abcalanını da kanıtlanmıştır alakasız olduğunu
ToolmakerSteve

60

Pek çok insan, nesnelerin işlevlere aktarılma şekli ve referansla geçenlerin ne anlama geldiği ile karıştırılmaktadır. Nesne değişkenleri hala değere göre iletilir, sadece PHP5'te iletilen değer bir referans tanıtıcısıdır. Kanıt olarak:

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

Çıktılar:

a, b

İçin referans geçmek şekilde işin arayan tarafından görülen değişkenlerin değiştirebilir. Hangi açıkça yukarıdaki kodu yapmaz. Takas işlevini şu şekilde değiştirmemiz gerekir:

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

Çıktılar:

b, a

referans ile geçmek için.


18
Bu kanıtın yanlış bir yorum olduğunu düşünüyorum. Referansları değiştirmeye çalıştığınız anlaşılıyor. Nesnelerin nasıl atandığıyla ilgili bir sorununuz var. Değişmez referansı yeniden atarsınız. İçeriden değiştirilebildiğini gösteren değerdir. Takasın yeniden tanımlanması şimdi ** x geçiyor, bu da * x'i değiştirmenize izin veriyor. Sorun, $ x = $ y'nin $ x'in orijinal olarak işaret ettiği şeyi değiştireceğini düşünmektir.
grantwparks

9
Bu bir kanıt değil . İlk örneğin çıktısı, nesnenin tamamının geçerli değerinin swapişleve geçirilmesi durumunda tam olarak beklediğiniz değerdir ; diğer bir deyişle, nesneler "değere göre aktarılmışsa". Öte yandan, bir nesne tutamacının işleve geçirilmesini beklediğiniz de tam olarak budur. Kodunuz bu iki durum arasında ayrım yapmaz.
EML

31

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

PHP 5'te yeni bir Nesne Modeli vardır. Daha iyi performans ve daha fazla özellik için PHP'nin nesneleri kullanması tamamen yeniden yazılmıştır. PHP'nin önceki sürümlerinde, nesneler ilkel türler (örneğin tamsayılar ve dizeler) gibi ele alındı. Bu yöntemin dezavantajı, bir değişken atandığında tüm nesnenin anlamsal olarak kopyalanması veya bir yönteme parametre olarak geçirilmesiydi. Yeni yaklaşımda, nesnelere değere göre değil, tanıtıcıya başvurulur (tanıtıcı bir nesnenin tanımlayıcısı olarak düşünülebilir).


25

PHP değişkenleri değere göre atanır, işlevlere değere göre iletilir ve nesneleri içeren / temsil ederken başvuru ile iletilir. Değişkenleri bir &

Değer / referans örneğiyle atanır:

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

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

çıktı

var1: test, var2: son test, var3: son test

Değer / referans sınavıyla geçti:

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

changeThem($var1, $var2);

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

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

çıktı:

var1: foo, var2 BAR

Referans muayene ile geçirilen nesne değişkenleri:

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

Çıktı:

FOO

(bu son örnek muhtemelen daha iyi olabilir ...)


2
"Nesneler" PHP5'teki değerler değildir ve "iletilemez". Değeri bir nesneye$foo bir göstericidir . $foobir değer geçirilecek işleve changeFoo()olarak, changeFoo()bir ile parametresini belirtmezdi &.
newacct

9

Bir değişkeni işleve başvuru ile iletebilirsiniz. Bu işlev orijinal değişkeni değiştirebilir.

Passage fonksiyon tanımında referans ile tanımlayabilirsiniz:

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

$result=5;
changeValue($result);

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

6

Her iki şekilde de yapabilirsiniz.

önüne bir '&' sembolü koyun ve geçtiğiniz değişken kökeniyle bir ve aynı olur. yani: bir kopyasını almak yerine referans ile geçebilirsiniz.

yani

    $fred = 5;
    $larry = & $fred;
    $larry = 8;
    echo $fred;//this will output 8, as larry and fred are now the same reference.

2
Bu kullanımdan kaldırıldı ve bir uyarı oluşturuyor
fijiaaron

5

İlkel türler içeren değişkenler PHP5 içindeki değere göre geçirilir. Nesneleri içeren değişkenler referans ile iletilir. 2006'dan itibaren Linux Journal'dan bu ve 4 ile 5 arasındaki diğer OO farklılıklarından bahseten ilginç bir makale var.

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


Tüm değişkenler fonksiyon parametresine sahip değilse PHP'de değere göre geçirilir &.
newacct

1

Nesneler, PHP 5'te başvuru ve PHP 4'te değere göre geçirilir. Değişkenler varsayılan olarak değere göre iletilir!

Burayı okuyun: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html


"Nesneler" PHP5'teki değerler değildir ve "iletilemez". İletilen işlevin parametresi yoksa tüm değişkenler değere göre geçirilir &.
newacct

@newacct tam olarak değil mi? Nesneler referans olarak bir şekilde aktarılır . Ben php nesneleri &tanımındaki parametrelerin önünde ile tanımlanmamış olsa bile işlevler tarafından değiştirilebileceğini gözlemledim - değer olarak geçerse, bir parametre olarak işlev olarak adlandırılan kapsamda yer alan nesne etkilenmez.
Félix Gagnon-Grenier

3
@ FélixGagnon-Grenier: Yine, "nesneler" değer değildir ve "geçilemez". PHP5'te değeri "nesne" olan bir "değişken" olamaz, yalnızca nesne başvurusu olan bir değere sahip olabilirsiniz (örneğin, bir nesneye işaretçi). Elbette bir nesneye değere göre bir işaretçi iletebilir veya atayabilir ve bu tür bir değişiklik yapan bir yöntemi çağırarak işaret ettiği nesneyi değiştirebilirsiniz. Bunun referansla geçişle ilgisi yok. Bir değerin türü nedir ve bir parametrenin by-pass / by-referans olup olmadığı bağımsız ve dikey şeylerdir.
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>";

Özellikler referans ile geçilmediğinde hala değiştirilebilir, bu yüzden dikkatli olun.

Çıktı:

SwapObjects: b, a TakasDeğerleri: a, b


1

Gelecekte bununla karşılaşan herkes için, bu gem anonim bir kullanıcı tarafından yayınlanan PHP belgelerinden paylaşmak istiyorum :

Burada bir karışıklık var gibi görünüyor. İşaretçiler ve referanslar arasındaki ayrım özellikle yararlı değildir. Daha önce yayınlanmış olan bazı "kapsamlı" örneklerin davranışı daha basit birleştirici terimlerle açıklanabilir. Örneğin Hayley'in kodu TAMAMEN yapması gerekeni TAMAMEN yapıyor. (> = 5.3 kullanılarak)

İlk ilke: Bir işaretçi bir nesneye erişmek için bir bellek adresi depolar. Bir nesne atandığında, bir işaretçi oluşturulur. (Zend motorunu henüz derinlemesine araştırmadım, ancak görebildiğim kadarıyla bu geçerli)

2. ilke ve en karışıklığın kaynağı: Bir değişkenin bir işleve geçirilmesi varsayılan olarak bir değer geçirme olarak yapılır, yani bir kopya ile çalışıyorsunuz. "Ama nesneler referansla geçti!" Hem burada hem de Java dünyasında yaygın bir yanlış anlama. Ben NE OLDUĞUN bir kopyasını söylemedim. Varsayılan geçiş, değere göre yapılır. Her zaman. Bununla birlikte, işaretçi ne kopyalanır ve iletilir. "->" kullanırken, elbette, arayan işlevindeki orijinal değişkenle aynı iç yapılara erişeceksiniz. Yalnızca "=" kullanıldığında yalnızca kopyalarla oynatılır.

3. ilke: "&", siz onu ayırana kadar başka bir değişken adını / işaretçisini başka bir şeyle aynı bellek adresine otomatik ve kalıcı olarak ayarlar. Burada "takma ad" terimini kullanmak doğrudur. Bunu "unset ()" ile zorla ayrılana kadar kalçada iki işaretçi olarak birleştirmeyi düşünün. Bu işlevsellik hem aynı kapsamda hem de bir işleve bir argüman iletildiğinde bulunur. Genellikle "bağımsız değişken", "değere göre geçme" ile "referans ile geçme" arasında C ve C ++ 'da daha açık olan belirli ayrımlar nedeniyle "başvuru" olarak adlandırılır.

Unutmayın: nesnelere değil nesnelerin işaretçileri işlevlere aktarılır. Orijinalleri gerçekten iletmek için parametre listenizde "&" kullanmadığınız sürece bu işaretçiler orijinalin KOPYA SAYISIDIR. Yalnızca bir nesnenin içinin içine girdiğinizde orijinaller değişir.

Ve işte verdikleri örnek:

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

?>

JavaScript için bu konuda kapsamlı, ayrıntılı bir blog yazısı yazdım , ancak PHP, C ++ ve insanların değere göre geçişe göre referansla karıştığı başka bir dil için de aynı derecede geçerli olduğuna inanıyorum.

Açıkçası, PHP, C ++ gibi, referans ile geçişi destekleyen bir dildir. Varsayılan olarak, nesneler değere göre iletilir. Nesneleri depolayan değişkenlerle çalışırken, bu değişkenleri işaretçi olarak görmeye yardımcı olur (çünkü montaj seviyesinde temelde oldukları şey budur). Bir işaretçiyi değere göre iletirseniz, işaretçiyi yine de "izleyebilir" ve işaretlenen nesnenin özelliklerini değiştirebilirsiniz. Yapamayacağınız şey, farklı bir nesneye işaret etmesidir. Yalnızca bir parametreyi referans olarak iletildiğini açıkça belirtirseniz, bunu yapabilirsiniz.


0

Aslında her iki yöntem de geçerlidir, ancak gereksiniminize bağlıdır. Referansa göre pas değerleri genellikle komut dosyanızı yavaşlatır. Bu nedenle, yürütme süresini dikkate alarak değişkenleri değere göre geçirmek daha iyidir. Ayrıca değişkenlere göre değer ilettiğinizde kod akışı daha tutarlıdır.


0

Orijinal değişkeni basitçe değiştirmek ve yeni değeri atanmış olarak tekrar aynı değişken adına döndürmek istediğinizde işlevler için bunu kullanın.

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

-7

Versiyona bağlı olarak, 4 değere, 5 referansa göre.


11
Bunun doğru olduğunu düşünmüyorum.
Nick Heiner

@Karl Seguin, kısmen doğru. PHP5 nesnesi varsayılan olarak değere göre geçilmeden önce, ancak 5'ten beri bunlar işleyici tarafından geçirilir, bu da uygulamada referans olarak ele alınabilir (bazı istisnalar hariç) çünkü php.net/manual/en/language aracılığıyla nesne özelliklerini değiştirebiliriz . oop5.references.php .
Adam Faryna
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.