Приоритет оператора

Приоритет оператора определяет, насколько "тесно" он связывает между собой два выражения. Например, выражение 1 + 5 * 3 вычисляется как 16, а не 18, поскольку оператор умножения ("*") имеет более высокий приоритет, чем оператор сложения ("+"). Круглые скобки могут использоваться для принудительного указания порядка выполнения операторов. Например, выражение (1 + 5) * 3 вычисляется как 18.

Если операторы имеют равный приоритет, то будут ли они выполняться справа налево или слева направо определяется их ассоциативностью. К примеру, "-" является лево-ассоциативным оператором. Следовательно 1 - 2 - 3 сгруппируется как (1 - 2) - 3 и пересчитается в -4. С другой стороны "=" - право-ассоциативный оператор, так что $a = $b = $c сгруппируется как $a = ($b = $c).

Неассоциативные операторы с одинаковым приоритетом не могут использоваться совместно. К примеру 1 < 2 > 1 не будет работать в PHP. Выражение 1 <= 1 == 1, с другой стороны, будет, поскольку == имеет более низкий приоритет чем <=.

Ассоциативность имеет смысл только для двоичных (и тернарных) операторов. Унарные операторы являются префиксными или постфиксными, поэтому это понятие не применимо. Например, !!$a можно сгруппировать только как !(!$a).

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

В следующей таблице приведён список операторов, отсортированный по убыванию их приоритетов. Операторы, размещённые в одной строке имеют одинаковый приоритет и порядок их выполнения определяется исходя из их ассоциативности.

Порядок выполнения операторов
Ассоциативность Оператор Дополнительная информация
(н/а) clone new clone и new
правая ** арифметические операторы
(н/а) + - ++ -- ~ (int) (float) (string) (array) (object) (bool) @ арифметические операторы (унарные + и -), инкремент/декремент, побитовые операторы, приведение типов и оператор управления ошибками
левая instanceof типы
(н/а) ! логические операторы
левая * / % арифметические операторы
левая + - . арифметические операторы (бинарные + и -), операторы, работающие с массивами и строковые операторы (. до PHP 8.0.0)
левая << >> побитовые операторы
левая . строковые операторы (начиная с PHP 8.0.0)
неассоциативна < <= > >= операторы сравнения
неассоциативна == != === !== <> <=> операторы сравнения
левая & побитовые операторы и ссылки
левая ^ побитовые операторы
левая | побитовые операторы
левая && логические операторы
левая || логические операторы
правая ?? операторы сравнения с null
неассоциативна ? : тернарный оператор (лево-ассоциативный до PHP 8.0.0)
правая = += -= *= **= /= .= %= &= |= ^= <<= >>= ??= операторы присваивания
(н/а) yield from yield from
(н/а) yield yield
(н/а) print print
левая and логические операторы
левая xor логические операторы
левая or логические операторы

Пример #1 Ассоциативность

<?php
$a 
5// (3 * 3) % 5 = 4
// ассоциативность тернарных операторов отличается от C/C++
$a true true 2// (true ? 0 : true) ? 1 : 2 = 2 (до PHP 8.0.0)

$a 1;
$b 2;
$a $b += 3// $a = ($b += 3) -> $a = 5, $b = 5
?>

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

Пример #2 Неопределённый порядок вычисления

<?php
$a 
1;
echo 
$a $a++; // может вывести как 2 так и 3

$i 1;
$array[$i] = $i++; // может установить индекс как 1, так 2
?>

Пример #3 +, - и . имеют одинаковый приоритет (до PHP 8.0.0)

<?php
$x 
4;
// следующий код может выдать неожиданный результат:
echo "x минус 1 равно " $x-", ну я надеюсь\n";
// поскольку он вычисляется таким образом (до PHP 8.0.0):
echo (("x минус один равно " $x) - 1) . ", ну я надеюсь\n";
// требуемый приоритет следует задать скобками:
echo "x минус 1 равно " . ($x-1) . ", ну я надеюсь\n";
?>

Результат выполнения данного примера:

-1, ну я надеюсь
-1, ну я надеюсь
x минус один равно 3, ну я надеюсь

Замечание:

Несмотря на то, что = имеет более низкий приоритет, чем большинство других операторов, PHP всё же позволяет делать так: if (!$a = foo()), в этом примере результат выполнения foo() будет присвоен $a.

Список изменений

Версия Описание
8.0.0 Объединение строк (.) теперь имеет более низкий приоритет, чем арифметическое сложение/вычитание (+ и -) и побитовый сдвиг влево/вправо (<< и >>); ранее он имел тот же приоритет, что и + и -, и более высокий приоритет, чем << и >>.
8.0.0 Тернарный оператор (? :) теперь неассоциативен; ранее он был лево-ассоциативным.
7.4.0 Опираясь на приоритет конкатенации строк (.) относительно арифметического сложения/вычитания (+ или -) или побитового сдвига влево/вправо (<< или >>), т.е. их совместное использование в выражении без скобок не рекомендуется.
7.4.0 Не рекомендуется полагаться на лево-ассоциативность тернарного оператора (? :), т.е. вложение нескольких тернарных операторов без скобок.
add a note add a note

User Contributed Notes 8 notes

up
167
fabmlk
8 years ago
Watch out for the difference of priority between 'and vs &&' or '|| vs or':
<?php
$bool
= true && false;
var_dump($bool); // false, that's expected

$bool = true and false;
var_dump($bool); // true, ouch!
?>
Because 'and/or' have lower priority than '=' but '||/&&' have higher.
up
27
aaronw at catalyst dot net dot nz
6 years ago
If you've come here looking for a full list of PHP operators, take note that the table here is *not* complete. There are some additional operators (or operator-ish punctuation tokens) that are not included here, such as "->", "::", and "...".

For a really comprehensive list, take a look at the "List of Parser Tokens" page: http://php.net/manual/en/tokens.php
up
46
Carsten Milkau
11 years ago
Beware the unusual order of bit-wise operators and comparison operators, this has often lead to bugs in my experience. For instance:

<?php if ( $flags & MASK  == 1) do_something(); ?>

will not do what you might expect from other languages. Use

<?php if (($flags & MASK) == 1) do_something(); ?>

in PHP instead.
up
7
ivan at dilber dot info
7 years ago
<?php
// Another tricky thing here is using && or || with ternary ?:
$x && $y ? $a : $b// ($x && $y) ? $a : $b;

// while:
$x and $y ? $a : $b// $x and ($y ? $a : $b);

?>
up
4
karlisd at gmail dot com
8 years ago
Sometimes it's easier to understand things in your own examples.
If you want to play around operator precedence and look which tests will be made, you can play around with this:

<?php
function F($v) {echo $v." "; return false;}
function
T($v) {echo $v." "; return true;}

IF (
F(0) || T(1) && F(2)  || F(3)  && ! F(4) ) {
  echo
"true";
} else echo
" false";
?>
Now put in IF arguments f for false and t for true, put in them some ID's. Play out by changing "F" to "T" and vice versa, by keeping your ID the same. See output and you will know which arguments  actualy were checked.
up
-1
anisgazig at gmail dot com
3 years ago
Three types of operator associativity in php.
1.left
2.rigt
3.non-associativity

Category of three operators are right associativity
1)**
2)=,+=,-=,*=,/=,%=,&=,^=,|=,<<=,>>=,??=,.=
3)??

Category of eight operators are non-associativity
1)clone new
2)++,--,~,@
3)!
4)<,<=,>,>=
5)<<,>>
6)yield from
7)yield
8)print

Rest of the operators are left associativity
up
0
noone
4 years ago
Something that threw me of guard and I hadn't found it mentioned anywhere is if you're looking to asign a value in an if statement condition and use the same value in the said condition and compare it to a different value note the precedence of operators.

if($a=5&&$a==5){
  echo '5';
} else {
  echo 'not 5';
}
//echos  not 5

You'll get a Notice:  Undefined variable: a;
This happens because the expression is treated as
($a=5&&($a==5))
In this case $a was undefined.

Use parentheses to enforce the desired outcome or and instead of &&.
if(($a=5)&&$a==5){ // or $a=5 and $a==5
  echo '5';
} else {
  echo 'not 5';
}

//echos  5

We get no notice!

A use case for this can be a three part condition that first checks if a value is valid, second assigns a new variable based on the first value and then checks if the result is valid.

$ID=100;

if ($ID&&($data=get_table_row_for_ID($ID))&&$data->is_valid()) { //NOTE: assigned $data
// do something with the data
}

If assigning variables in an if condition I recommend adding a comment at the end of the line that such an action took place.
up
-1
instatiendaweb at gmail dot com
3 years ago
//incorrect
$a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2
//Unparenthesized `a ? b : c ? d : e` is not supported. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`
//correct
$a = (true ? 0 : true) ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2

==> correction documentation.
To Top