Что означают операторы "= &" и "& =" в PHP?

Что делать "= &" / "& =" в PHP? Где я могу прочитать информацию о них?

Поиск Google не помогает.

Ответ 1

$a &= $b сокращен для $a = $a & $b, который является оператором побитовым и.

$a =& $b присваивает $a как reference до $b.

Ответ 2

= &

$a =& $b превращает $a в псевдоним для $b. Если значение или ссылка $a будет изменено, значение или ссылка $b соответственно изменится.

Это отличается от того, что "оба указывают на одно и то же место", когда дело доходит до объектов: я мог бы сделать $c = $d = new AnObject(), и обе переменные указывали бы на одно и то же место; однако, изменение, где одно очко не изменилось бы там, где другие точки. То есть $c = null не сделает $d = null. В случае $a =& $b, однако, $a = null сделает $b = null.

Примечание. Официально псевдонимы на самом деле называются ссылками. Официальная терминология немного ошибочна и, безусловно, неоднозначна, поэтому я решил использовать термин "псевдоним" вместо этого. Для документации см. php.net.

Использование и эффекты

Со скалярными значениями =& похож на перенос значения в объект, так что вы можете изменить значение универсально среди нескольких переменных. С типами, которые обычно передаются по ссылке (объекты), =& предоставляет ссылку на ссылку.

Я стараюсь использовать =&, когда я работаю с ассоциативными массивами. Вместо того, чтобы переписывать $foo['bar']['foobar'] несколько раз, я могу создать псевдоним: $foobar =& $foo['bar']['foobar']. Они даже работают, если индекс еще не существует. Если $foo['bar']['foobar'] не существует, то isset($foobar) будет ложным. Это лучше, чем использование простой старой переменной, потому что я могу создать псевдоним перед тестированием на наличие ключа без возникновения ошибки.

Не забудьте отменить (unset($foobar)) псевдоним, когда вы закончите. В противном случае, если вы повторно используете имя переменной позже, вы в конечном итоге перепишете все, на что указывает псевдоним.

Вы также можете использовать псевдонимы другими способами - они не ограничены назначениями. Они работают с:

  • петли foreach: foreach ($a as &$b) Назначение $b будет перезаписывать соответствующее значение в $a. Unset $b, когда вы закончите, или у вас возникнут странные проблемы!
  • Параметры функции/метода: function foobar(&$a) Присвоение $a внутри foobar изменит любую переменную, переданную вызывающим, как $a.
  • возвращаемые значения функции/метода: function &foobar() Все, что возвращается, может быть изменено вызывающим; это полезно для обхода псевдонимов. Это также легко злоупотреблять.
  • массивы: $a = array(&$b) Любые изменения в $a[0] теперь будут влиять на $b, включая присвоения.
  • call_user_func_array: call_user_func('foobar', array(&$a)) Предполагая, что foobar принимает один параметр псевдонима, foobar теперь может изменять $a. Это позволяет вам вызывать функции/методы с параметрами псевдонима с помощью call_user_func_array.

Примеры

Скаляры

$original = 1;
$copy = $original;
$reference =& $original;
// All three variables == 1.

$reference = 2;
// $original == 2, $reference == 2, $copy == 1

$original = 3;
// $original == 3, $reference == 3, $copy == 1

$copy = 4;
// $original == 3, $reference == 3, $copy == 4

Объекты

#!/usr/bin/env php
<?php
class Object
{
        private $properties;

        public function __construct(array $properties = array())
        {
                $this->properties = $properties;
        }

        public function __isset($key)
        {
                return isset($this->properties[$key]);
        }

        public function __unset($key)
        {
                unset($this->properties[$key]);
        }

        public function __get($key)
        {
                return isset($this->$key) ? $this->properties[$key] : null;
        }

        public function __set($key, $value)
        {
                $this->properties[$key] = $value;
        }

        public function __toString()
        {
                return print_r($this->properties, true);
        }
}

function print_vars()
{
        global $original, $ref, $refref;

        echo
                '$original: ', $original,
                '$ref: ', $ref,
                '$refref: ', $refref,
                PHP_EOL;
}

$original = new Object(array('a' => 1, 'b' => 2, 'c' => 3));
$ref = $original;
$refref =& $original;
print_vars();
/*
$original: Array
(
    [a] => 1
    [b] => 2
    [c] => 3
)
$ref: Array
(
    [a] => 1
    [b] => 2
    [c] => 3
)
$refref: Array
(
    [a] => 1
    [b] => 2
    [c] => 3
)
*/

$original->a = 'duck';
$ref->b = 'moose';
$refref->c = 'cow';
print_vars();
/*
$original: Array
(
    [a] => duck
    [b] => moose
    [c] => cow
)
$ref: Array
(
    [a] => duck
    [b] => moose
    [c] => cow
)
$refref: Array
(
    [a] => duck
    [b] => moose
    [c] => cow
)
*/

// This carries over to $refref, but not $ref.
$original = new Object(array('x' => 1, 'y' => 2, 'z' => 3));
print_vars();
/*
$original: Array
(
    [x] => 1
    [y] => 2
    [z] => 3
)
$ref: Array
(
    [a] => duck
    [b] => moose
    [c] => cow
)
$refref: Array
(
    [x] => 1
    [y] => 2
    [z] => 3
)
 */

// This does *not* carry over to $original or $ref.
$ref = new Object(array('o' => 42, 'm' => 123, 'n' => 1337));
print_vars();
/*
$original: Array
(
    [x] => 1
    [y] => 2
    [z] => 3
)
$ref: Array
(
    [o] => 42
    [m] => 123
    [n] => 1337
)
$refref: Array
(
    [x] => 1
    [y] => 2
    [z] => 3
)
*/

// This *does* carry over to $original, but not $ref.
$refref = new Object(array('alpha' => 10, 'beta' => 20, 'gamma' => 30));
print_vars();
/*
$original: Array
(
    [alpha] => 10
    [beta] => 20
    [gamma] => 30
)
$ref: Array
(
    [o] => 42
    [m] => 123
    [n] => 1337
)
$refref: Array
(
    [alpha] => 10
    [beta] => 20
    [gamma] => 30
)
*/
?>

& =

&= не имеет отношения к =&. Он исходит из набора операций присваивания. Вот только несколько:

  • +=
  • -=
  • *=
  • /=

См. здесь тренд?

Двоичные арифметические операторы обычно имеют сопоставления с назначением. Скажем, @ были арифметическим оператором (это не так, как написано), так что $a @ $b обычно дает число, когда $a и $b - числа. (Думайте: добавление, умножение, деление и т.д.). Как часто вам нужно делать что-то вроде этого?

$a = $a @ $b;

Довольно часто. Не кажется ли вам лишним повторять $a? Многие языки, включая PHP, решают это с помощью массива операторов присваивания:

$a @= $b;

Гораздо проще, и программисту, привыкшему к этим обозначениям, возможно, более кратким и описательным с первого взгляда. (Мне, конечно, легче читать, поскольку я так привык). Чтобы удвоить переменную:

$a *= 2;

Быстро, легко и относительно описательно. Некоторые языки, включая PHP, расширяют эту функцию за пределами арифметики для дополнительной операции или двух. В частности:

$a = $a . 'Appended text';
// Is the same as:
$a .= 'Appended text';

Очень полезно.

&= входит в число этих операторов присваивания, поскольку & представляет побитовую арифметическую операцию И. Есть несколько других, перечисленных в документации PHP (см. Вышеупомянутую ссылку), которые являются общими для многих языков программирования.

Это означает, что $a &= $b совпадает с $a = $a & $b.