Передача объектов по ссылкам и значениям в PHP

Дописывая свой проект столкнулся с проблемой передачи объектов в PHP, о чем и хотел бы тут все расписать, мало ли кому пригодится.

Общеизвестно, что с 5ой версии PHP все объекты передаются по ссылке. Но что же стоит за этой фразой?
Пример первый:

< ?php
session_start();
class My {
        public $i = 0;
}
 
if (isset($_SESSION['my_int'])) {
        $my_int = $_SESSION['my_int'];
} else {
        $my_int = 0;
        $_SESSION['my_int'] = $my_int;
}
if (isset($_SESSION['my_obj'])) {
        $my_obj = $_SESSION['my_obj'];
} else {
        $my_obj = new My();
        $_SESSION['my_obj'] = $my_obj;
}
echo('my_int=' . $my_int++);
echo(' my_obj.i=' . $my_obj->i++);
?>

Обновив страницу несколько раз, получаем:

my_int=0 my_obj.i=0
my_int=0 my_obj.i=1
my_int=0 my_obj.i=2

Т.е. объект сохраняется в сессии, даже при том что мы этого явно не делали. Тут все просто, $my_obj = $_SESSION[‘my_obj’]; создает в $my_obj копию идентификатора и обращение к $my_obj->i фактически равносильно $_SESSION[‘my_obj’]->i
Добиться того же эффекта с переменной можно явно присвоив значение по ссылке:

$my_int = &$_SESSION['my_int'];

Теперь при обновление страницы увеличиваться будут оба счетчика.

Возьмем менее тривиальный пример, чтобы показать, менее очевидные веши:

<?php
class A {
    public $foo = 'empty';
}
class B {
    public $foo = 'empty';
    public $bar = 'hello';
}
 
function normalAssignment($obj) {
    $obj->foo = 'changed';
    $obj = new B;
}
 
function referenceAssignment(&$obj) {
    $obj->foo = 'changed';
    $obj = new B;
}
 
$a = new A;
normalAssignment($a);
echo get_class($a), "\n";
echo "foo = {$a->foo}\n";
 
referenceAssignment($a);
echo get_class($a), "\n";
echo "foo = {$a->foo}\n";
echo "bar = {$a->bar}\n";
/*
prints:
A
foo = changed
B
foo = empty
bar = hello
*/
?>

Вывод менее очевиден, не так ли?
Под передачей по ссылке подразумевается передача копии указателя, следовательно при обращение через “->”, мы получаем доступ к внутренностям переданного объекта, тогда как “=” оперирует уже с локальной копией объекта.
Символ “&” автоматически устанавливает присваиваемой переменной идентификатор того же участка память, что и у оригинального объекта. Здесь более подходит термин “alias”. Этот алиас будет постоянным, до тех пор, пока его явно не удалить (unset($var_name)).
Вывод: в функции передаются указатели на объекты, не сами объекты. Эти указатели – копии оригиналов, до тех пор пока в параметрах функции не используется “&” – в этом случае передается оригинал.

Leave a Reply