79

What do "=&" / "&=" operators in PHP mean? Where can I read information about them?

Searching Google doesn't help.

2

2 Answers 2

104

$a &= $b is short for $a = $a & $b which is the bitwise-and operator.

$a =& $b assigns $a as a reference to $b.

19
  • 12
    I don't think there's a =& operator. It's a combination of = (assignment) and unary & (referencing) operators. Commented Sep 2, 2009 at 12:46
  • 3
    @hacker: Using a common name for the special character usually works well, e.g. "ampersand php".
    – GZipp
    Commented Sep 2, 2009 at 13:00
  • 1
    php.net/manual/en/language.references.whatdo.php more explanations on references. Commented Aug 19, 2010 at 22:01
  • 5
    Nitpicking: "$a =& $b assigns $a as a reference to $b" is wrong, since $a doesn't point to $b (or vice versa), but both point to the same place. A subtle but important difference. Commented Jul 12, 2013 at 9:27
  • 2
    @MichaelKrelin-hacker There's no dereference operator in PHP, per se. & is context-sensitive. You are right in that =& is not a single operator; rather, & is an operator when preceded by =, with whitespace permitted. Or perhaps you could say that & modifies the = operator.
    – Zenexer
    Commented Aug 10, 2013 at 20:16
54

=&

$a =& $b turns $a into an alias for $b. If the value or reference of $a is changed, the value or reference of $b will change accordingly.

This differs from "both pointing to the same place" when it comes to objects: I could do $c = $d = new AnObject(), and both variables would point to the same place; however, changing where one points would not change where the other points. That is, $c = null would not make $d = null. In the case of $a =& $b, however, $a = null would make $b = null.

Note: Officially, aliases are actually called references. The official terminology is a bit of a misnomer and is certainly ambiguous, so I've opted to use the term "alias" instead. For documentation, see php.net.

Uses and effects

With scalar values, =& is sort of like wrapping the value in an object, so that you can change the value universally among several variables. With types that are normally passed by reference (objects), =& provides a reference to a reference.

I tend to use =& when I'm working with associative arrays. Rather than rewriting $foo['bar']['foobar'] several times over, I can create an alias: $foobar =& $foo['bar']['foobar']. These even works if the index doesn't exist yet. If $foo['bar']['foobar'] doesn't exist, then isset($foobar) will be false. It's better than using a plain old variable, because I can create the alias before testing for the existence of the key without triggering an error.

Just be sure to unset (unset($foobar)) the alias when you're done. Otherwise, if you reuse the variable name later, you'll end up overwriting whatever the alias was pointing to.

You can use aliases in other ways, too--they're not limited to assignments. They work with:

  • foreach loops: foreach ($a as &$b) Assigning to $b will overwrite the corresponding value in $a. Unset $b when you're done, or you'll run into weird problems!
  • function/method parameters: function foobar(&$a) Assigning to $a within foobar will change whatever variable the caller passed as $a.
  • function/method return values: function &foobar() Whatever is returned can be modified by the caller; this is useful for passing around aliases. It's also easy to abuse.
  • arrays: $a = array(&$b) Any changes to $a[0] will now affect $b, including assignments.
  • call_user_func_array: call_user_func('foobar', array(&$a)) Assuming foobar takes a single alias parameter, foobar can now modify $a. This allows you to call functions/methods with alias parameters using call_user_func_array.

Examples

Scalars

$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

Objects

#!/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
)
*/
?>

&=

&= is unrelated to =&. It comes from a set of assignment operations. Here's just a few:

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

See the trend here?

Binary arithmetic operators generally have assignment counterparts. Let's say @ were an arithmetic operator (it's not as of writing) such that $a @ $b generally yields a number when $a and $b are numbers. (Think: Addition, multiplication, division, etc.) How often do you need to do something like this?

$a = $a @ $b;

Pretty often. Doesn't it seem a bit unnecessary to repeat $a? Many languages, including PHP, solve this with an array of assignment operators:

$a @= $b;

Much simpler, and to a programmer accustomed to this notation, perhaps more concise and descriptive at a glance. (I certainly find it easier to read, since I'm so used to it.) So to double a variable:

$a *= 2;

Quick, easy, and relatively descriptive. Some languages, including PHP, extend this feature beyond arithmetic for an extra operation or two. Notably:

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

Very useful.

&= falls among these assignment operators, because & represents a bitwise arithmetic AND operation. There are a few others listed in the PHP documentation (see aforementioned link), all of which are common to many programming languages.

This means that $a &= $b is the same as $a = $a & $b.

3
  • One addtion @zenexer to your already awesome anser. $a @= $b is different from $a = $a @ $b in a signficant way and that is how ofent $a is evaluated. In the first case only one time in the second two times. This might have an impact if $a i not a normal variable but a property or even a functino with side effect.
    – theking2
    Commented May 9, 2022 at 17:25
  • Great answer! I finally got it! I remember reading docs about it and failing to grasp the complete view. Commented Jul 5, 2022 at 11:04
  • "Alias" is not really a great term, because it still implies the operation is directional, but it is not. Some descriptions talk about "adding to a reference set", which is closer to the truth: both names are equally valid, and neither can be considered a reference to, or alias of, the other.
    – IMSoP
    Commented Aug 14, 2022 at 9:39