Переменные PHP передаются по значению или по ссылке?

Переменные PHP передаются по значению или по ссылке?

Ответов (16)

Решение

Это по стоимости согласно документации PHP .

По умолчанию аргументы функции передаются по значению (так что, если значение аргумента внутри функции изменяется, оно не изменяется вне функции). Чтобы функция могла изменять свои аргументы, они должны передаваться по ссылке.

Чтобы аргумент функции всегда передавался по ссылке, добавьте амперсанд ( & ) к имени аргумента в определении функции.

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

Кажется, многих людей смущает то, как объекты передаются функциям и что означает передача по ссылке. Объект по-прежнему передается по значению, просто значение, которое передается в PHP5, является указателем ссылки. Как доказательство:

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

Выходы:

a, b

Для того, чтобы пройти по справочным средствам мы можем изменить переменные, которые видны вызывающей, что явно выше код не делает. Нам нужно изменить функцию подкачки на:

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

Выходы:

b, a

для того, чтобы пройти по ссылке.

В PHP по умолчанию объекты передаются как ссылка на новый объект.

См. Этот пример:

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

Теперь посмотри на это:

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.

Теперь посмотри на это:

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.

Надеюсь, вы понимаете это.

Вы можете передать переменную в функцию по ссылке. Эта функция сможет изменять исходную переменную.

Вы можете определить отрывок по ссылке в определении функции:

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

$result=5;
changeValue($result);

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

Используйте это для функций, когда вы хотите просто изменить исходную переменную и снова вернуть ее с тем же именем переменной с присвоенным ей новым значением.

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

На самом деле действительны оба метода, но это зависит от ваших требований. Передача значений по ссылке часто замедляет ваш скрипт. Так что лучше передавать переменные по значению, учитывая время выполнения. Кроме того, поток кода более согласован, когда вы передаете переменные по значению.

См. Этот пример:

<?php

$string = 'First String. ';
$string .= 'Second String. ';
$string .= 'Third String. ';

echo $string;

// output: First String. Second String. Third String. 

?>

Что касается того, как объекты передаются в функции, вам все равно нужно понимать, что без «&» вы передаете функции дескриптор объекта, дескриптор объекта, который все еще передается по значению, и он содержит значение указателя. Но вы не можете изменить этот указатель, пока не передадите его по ссылке с помощью символа «&».

<?php
        class Example 
        {
            public $value;
         
        }
        
        function test1($x) 
        {
             //let's say $x is 0x34313131
             $x->value = 1;  //will reflect outsite of this function
                             //php use pointer 0x34313131 and search for the 
                             //address of 'value' and change it to 1

        }
        
        function test2($x) 
        {
             //$x is 0x34313131
             $x = new Example;
             //now $x is 0x88888888
             //this will NOT reflect outside of this function 
             //you need to rewrite it as "test2(&$x)"
             $x->value = 1000; //this is 1000 JUST inside this function
                 
        
        }
         
     $example = new Example;
    
     $example->value = 0;
    
     test1($example); // $example->value changed to  1
    
     test2($example); // $example did NOT changed to a new object 
                      // $example->value is still 1
     
 ?>

TL; DR : PHP поддерживает как передачу по значению, так и передачу по ссылке. Ссылки объявляются с помощью символа амперсанда ( & ); это очень похоже на то, как это делает C++. Когда формальный параметр функции не объявлен с амперсандом (т. Е. Это не ссылка), все передается по значению, включая объекты. Нет различия между тем, как передаются объекты и примитивы. Ключ в том, чтобы понять, что передается, когда вы передаете объекты в функцию. Здесь бесценно понимание указателей.

Для всех, кто столкнется с этим в будущем, я хочу поделиться этой жемчужиной из документации PHP, опубликованной анонимным пользователем :

Кажется, здесь есть некоторая путаница. Различие между указателями и ссылками не особенно полезно. Поведение в некоторых из уже опубликованных «всеобъемлющих» примеров можно объяснить более простыми объединяющими терминами. Код Хейли, например, делает ТОЧНО то, что вы должны ожидать. (Используя> = 5.3)

Первый принцип: указатель хранит адрес памяти для доступа к объекту. Каждый раз, когда объект назначается, создается указатель. (Я еще не слишком глубоко разбирался в движке Zend, но, насколько я понимаю, это применимо)

Второй принцип и источник наибольшей путаницы: передача переменной в функцию по умолчанию выполняется как передача значения, т. Е. Вы работаете с копией. «Но ведь объекты передаются по ссылке!» Распространенное заблуждение как здесь, так и в мире Java. Я никогда не говорил копию ЧТО. По умолчанию передача осуществляется по значению. Всегда. Однако ЧТО копируется и передается, так это указатель. При использовании "->" вы, конечно, будете иметь доступ к тем же внутренним компонентам, что и исходная переменная в вызывающей функции. Простое использование "=" будет играть только с копиями.

3-й принцип: «&» автоматически и навсегда устанавливает другое имя / указатель переменной на тот же адрес памяти, что и что-то еще, пока вы не разъедините их. Здесь правильно использовать термин «псевдоним». Думайте об этом как о соединении двух указателей на бедре до тех пор, пока они не будут принудительно разделены с помощью "unset ()". Эта функция существует как в той же области, так и при передаче аргумента функции. Часто переданный аргумент называется «ссылкой» из-за определенных различий между «передачей по значению» и «передачей по ссылке», которые более понятны в C и C++.

Просто помните: в функции передаются указатели на объекты, а не сами объекты. Эти указатели являются КОПИЯМИ оригинала, если вы не используете "&" в своем списке параметров для фактической передачи оригиналов. Только когда вы покопаетесь во внутренней части объекта, оригиналы изменятся.

И вот пример, который они предоставляют:

<?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 , но я считаю, что он одинаково хорошо применим к PHP, C++ и любому другому языку, где люди, похоже, не понимают , что такое передача по значению или передача по ссылке.

Ясно, что PHP, как и C++, - это язык, который поддерживает передачу по ссылке. По умолчанию объекты передаются по значению. При работе с переменными, в которых хранятся объекты, полезно видеть эти переменные как указатели (потому что это, по сути, то, чем они являются на уровне сборки). Если вы передаете указатель по значению, вы все равно можете «отслеживать» указатель и изменять свойства объекта, на который он указывает. Чего вы не можете сделать, так это указать ему на другой объект. Только если вы явно объявите параметр как передаваемый по ссылке, вы сможете это сделать.

Переменные, содержащие примитивные типы, в PHP5 передаются по значению. Переменные, содержащие объекты, передаются по ссылке. В Linux Journal от 2006 года есть довольно интересная статья, в которой упоминается это и другие объектно-ориентированные различия между 4 и 5.

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

В зависимости от версии, 4 - по значению, 5 - по ссылке.

Переменные PHP назначаются по значению, передаются функциям по значению, а когда они содержат / представляют объекты, передаются по ссылке. Вы можете принудительно передать переменные по ссылке с помощью символа '&'.

Присваивается по значению / справочному примеру:

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

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

выход:

var1: test, var2: final test, var3: final test

Передано по значению / справочному примеру:

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

changeThem($var1, $var2);

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

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

выход:

var1: foo, var2 BAR

Переменные объекта, передаваемые по справочному примеру:

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

выход:

FOO

(Последний пример, наверное, мог бы быть лучше.)

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

В PHP 5 есть новая объектная модель. Обработка объектов в PHP была полностью переписана, что позволило повысить производительность и расширить возможности. В предыдущих версиях PHP объекты обрабатывались как примитивные типы (например, целые числа и строки). Недостатком этого метода было то, что семантически весь объект копировался при присвоении переменной или передаче в качестве параметра методу. В новом подходе на объекты ссылаются по дескриптору, а не по значению (дескриптор можно рассматривать как идентификатор объекта).

Вы можете сделать это в любом случае.

Поместите символ «&» впереди, и переменная, которую вы передаете, станет той же самой, что и ее источник, т.е. вы можете передать ее по ссылке, а не копировать ее.

так

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

Объекты передаются по ссылке в PHP 5 и по значению в PHP 4. По умолчанию переменные передаются по значению!

Читайте здесь: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html

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

Атрибуты можно изменять, если они не переданы по ссылке, так что будьте осторожны.

Выход:

SwapObjects: b, a SwapValues: a, b