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

Приоритет оператора определяет, насколько "тесно" он связывает между собой два выражения. Например, выражение 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
= 3 * 3 % 5; // (3 * 3) % 5 = 4
// ассоциативность тернарных операторов отличается от C/C++
$a = true ? 0 : true ? 1 : 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-1 . ", ну я надеюсь\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

User Contributed Notes 10 notes

up
204
fabmlk
7 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
5
sangala at seznam dot cz
4 months ago
Using cast and ternary operator can be unclear,
(Useful to know with: declare(strict_types = 1) ).
<?php
$num_str
="5";

$i1 = (int)  isset($num_str) ? $num_str : 0;
$i2 = (int) (isset($num_str) ? $num_str : 0);
var_dump($i1);
var_dump($i2);
?>
Output:
string(1) "5"
int(5)
up
7
tlili dot mokhtar at gmail dot com
1 year ago
An easy trick to get the result of the left shift operation (<<), e.g.

15 << 2 = 15 * (2*2) = 60

15 << 3 = 15 * (2*2*2) = 120

15 << 5 = 15 * (2*2*2*2*2) = 480

and so on...

So it's:

(number on left) multiplied by (number on right) times 2.

The same goes for the right shift operator (>>), where:

(number on left) divided by (number on right) times 2 e.g.

15 >> 2 = (15/2)/2 = 7/2 = 3 (use floor values if result is in decimals).

35 >> 3 = (((35/2)/2)/2 = (17/2)/2 = 8/2 = 4
up
33
aaronw at catalyst dot net dot nz
5 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
50
Carsten Milkau
10 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
10
ivan at dilber dot info
5 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
0
rvwoens at gmail dot com
2 months ago
Note that ?? has a low priority, so this can lead to unexpected results:

$a=[];
$a['aa']??'not set'
--> not set (as expected)

but
"lets see if it is set".$a['aa']??'not set'
--> notice; undefined index aa
--> lets see if it is set

so you need to use parenthesis
"lets see if it is set".($a['aa']??'not set')
up
0
instatiendaweb at gmail dot com
2 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.
up
-4
karlisd at gmail dot com
7 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
-3
anisgazig at gmail dot com
2 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
To Top