И и И (логические выражения в PHP)

В ПХП есть два набора команд булевой логики — многим более привычные «&&» и «||», но кроме них — напоминающие о Бейсике и Эскюэле «and» и «or». Даже программирующие на языке годами часто не знают чем они отличаются, между тем употребление второго набора может привести к трудноуловимым багам, потому что ведут они себя чуть иначе.

Вся разница заключается в приоритетах выполнения, большинство языков, разбирая выражение, опирается на приоритеты выполнения, например, умножение приоритетней сложения, этому нас учат в школе, в ПХП и многих других языках — так же: 2 + 2 × 2 = 6, а не 8.

Так вот. Набор «and» и «or» — чуть ли не самые низкоприоритетные из всего, что может встретиться, а «&&» и «||» находятся где-то посередине. Поясню примером. Команда присваивания выше «по табелю о рангах», чем «or», но ниже, чем «||»:

// какая-то переменная, значение которой в коде,
// к этому моменту, стало true
$check = true;

// а это другая контрольная переменная, где-то в коде
// она приобрела значение false
$criteria = false;

// и вот мы подходим к главному
$ret_bool = $criteria ||  $check;
$ret_logic = $criteria or $check;

var_dump($ret_bool, $ret_logic);

Будут ли отличаться значения переменных ret_bool и ret_logic после выполнения программы? Конечно будут, иначе я бы не писал этут статью, неправда ли? Значение первой будет true, второй — false.

Почему так? Приоритеты! ПХП, исполняя предпоследние две строчки кода видит их как-то так:

$ret_bool = ($criteria || $check);
($ret_logic = $criteria) or $check;

Исполнение идёт строго по приоритетам, так как во втором случае операция присваивания имеет больший приоритет, чем «or», первым выполняется именно она, а проверка переменной check осуществляется, но её результат отбрасывается.

Это отлично подходит для программировая в «хакерском» стиле:

$ret_logic = $criteria or CheckSomething();

Функция CheckSomething() вызовется только в том случае, если criteria будет равна false или эквиваленту, но зато результат функции никак не повлияет на значение ret_logic.

Впрочем, я такой способ программирования крайне не рекомендую — для современных программистов он сложен.

Комментарии 28

Горбунов Олег № 1
Я кстати, пользуюсь «набором из бейсика», поскольку по диагонали оно читается в коде на порядки легче. Приоритеты скобками задаю всегда — ИДЕ подсвечивают, позволяя разбирать довольно сложные условия.
Не знаю, хорошо это или плохо, просто так привык. :)
Евгений Степанищев (bolknote.ru) автор № 2
Я кстати, пользуюсь «набором из бейсика», поскольку по диагонали оно читается в коде на порядки легче.

Это вопрос привычки. Одни значки и другие значки.

Приоритеты скобками задаю всегда — ИДЕ подсвечивают, позволяя разбирать довольно сложные условия.
Не знаю, хорошо это или плохо, просто так привык. :)

Плохо. Не нужно лишнего, это как ударения в каждом слове расставлять — больше знаком без какого-либо смысла. А в случае конструкций это просто не работает: /all/4143

hshhhhh (hshhhhh.name) № 4
для современных программистов он сложен.

смешно конечно, но вообще зачем так усложнять код? по мне так проще написать в три строчки. через три года будет проще разбираться почему не работает :).

Евгений Степанищев (bolknote.ru) автор № 6
смешно конечно, но вообще зачем так усложнять код? по мне так проще написать в три строчки. через три года будет проще разбираться почему не работает :)

Самое смешное, что никакого переусложнения нет. Это очень простое выражение. Но современные программисты считают его сложным.

PastorGL № 5
для современных программистов он сложен.

Я ещё со времён Бейсика (то есть, чуть меньше последних 25 лет) всегда расставляю скобки в логических выражениях и вокруг тернарного оператора. Вне зависимости от того, на каком языке пишу. Это правило как раз снимает необходимость помнить, в каком языке какие приоритеты.

А вещи типа

$ret_logic = $criteria or CheckSomething();

вообще стараюсь не использовать. Мало ли, вдруг сам не пойму, что я тут имел в виду, через пару лет копаясь в старом коде.

Евгений Степанищев (bolknote.ru) автор № 7
Это правило как раз снимает необходимость помнить, в каком языке какие приоритеты.

Это вопрос владения языком. Современный подход подразумевает, что лучше иметь низкий уровень в куче языков, чем идеально знать 1—2.

hshhhhh (hshhhhh.name) № 8

Комментарий для Евгения Степанищева:

Самое смешное, что никакого переусложнения нет. Это очень простое выражение. Но современные программисты считают его сложным.

Я не считаю его сложным, но просто из-за того что я and/or не пользовался уже много лет я не сразу найду ошибку / пойму как оно работает.

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

Это вопрос владения языком. Современный подход подразумевает, что лучше иметь низкий уровень в куче языков, чем идеально знать 1—2.

Тут дело не в современном подходе, а в современных реалиах. Вот знаешь ты сейчас, например, идеально пхп, а интересную работу найти совсем не так просто как 5 лет назад.

А на C что 10 лет назад, что 20 -- можно было найти работу.

Вопрос в мимолётности языков.

Ну и самая большая проблема в том что сейчас люди не учат языки программирования -- люди изучают фреймворки к языкам программирования.
Типа в требованиях редко можно найти Ruby/Python, но почти всегда Ruby On Rails / Django.

В современом мире работодателю редко нужны люди которые зачем-то помнят приоритеты для and / or если ими не пользуются %)

Евгений Степанищев (bolknote.ru) автор № 9

Комментарий для hshhhhh.name:

В современом мире работодателю редко нужны люди которые зачем-то помнят приоритеты для and / or если ими не пользуются %)

Работодатель тут не причём. Это вопрос профессионализма. Именно поэтому я могу найти любую ошибку в чужом коде (при этом я не программистом работаю), а из кучи программистов вокруг — считанные единицы.

hshhhhh (hshhhhh.name) № 10

Комментарий для Евгения Степанищева:

Работодатель тут не причём. Это вопрос профессионализма. Именно поэтому я могу найти любую ошибку в чужом коде (при этом я не программистом работаю), а из кучи программистов вокруг — считанные единицы.

Найти ошибку это одно.
Я про то что в пхп достаточно большое колличество вещей не совсем очевидно и в них надо вникать и разбираться. Эти вот приоритеты или нюансы с кастованием.

Я считаю что знать про них надо, но при этом я не совсем понимаю зачем писать код в котором могут быть ошибки.

То есть привёденный пример в статье: $ret_logic = $criteria or CheckSomething();
На мой взгляд совсем не пример хакерского кода, а кода плохого.
в чем проблема записать это в две строки?
$ret_logic = $criteria;
$criteria || CheckSometing();

Я бы ещё и в иф обернул просто потому что в пхп так писать не принято. На мой взгляд это такое же хакерский код как и писать if () без фигурных скобок. Можно -- да. Зачем? Непонятно.

hshhhhh (hshhhhh.name) № 11
Комментарий для Евгения Степанищева:

Если писать этот «хакерский код» как прототип с целью склепать на коленке что-то быстрое и важна скорость -- да, конечно.

В реальной жизни в любом коде должны быть такое дикое колличество проверок, то экономия одной строчки (и усложнение логики) не влияет ни на что. Я не понимаю зачем :).
hshhhhh (hshhhhh.name) № 12
Комментарий для Евгения Степанищева:

Опять же если рассматривать их как радость от познания возможностей компилятора -- да сам бог велел.

Но вот, например, в пхп есть анонимные функции. Анонимные функции это очень круто. Только в пхп ими практически не пользуются, но ведь они есть. Почему ими не пользуются?
zg (zg.livejournal.com) № 13
ну да, раньше и трава была зеленее и программисты лучше.
Евгений Степанищев (bolknote.ru) автор № 15
ну да, раньше и трава была зеленее и программисты лучше.

Я уже более 15 лет нанимаю программистов. Вижу куда движется всё.

Евгений Степанищев (bolknote.ru) автор № 14

Комментарий для hshhhhh.name:

Если писать этот «хакерский код» как прототип с целью склепать на коленке что-то быстрое и важна скорость — да, конечно.

Нет, это не он. Просто внутри некоторых языков программирования тоже появляется «мейнстрим». В ПХП это можно назвать «пишем на детсадовском в Си» (без указателей и прочих прелестей Си).

Но вот, например, в пхп есть анонимные функции. Анонимные функции это очень круто. Только в пхп ими практически не пользуются, но ведь они есть. Почему ими не пользуются?

Пользуются. Только не те, кто клепает маленькие сайты — во-первых, там всё равно как писать, во-вторых, хостеры лениво обновляются. Те, кто делает код, который требует выделенный хостинг, используют все прелести новых версий — это просто очень удобно.

zg (zg.livejournal.com) № 16

Комментарий для Евгения Степанищева:

Я уже более 15 лет нанимаю программистов.

это очень маленький срез.

Вижу куда движется всё.

не очень понятно, как по такому маленькому срезу можно прямо таки видеть всё.

Efendy № 18
Во многих языках приоритет у && и and разный, но такой нюанс как у тебя в примере — это изобретение пхп и оно не логично
Евгений Степанищев (bolknote.ru) автор № 20
Во многих языках приоритет у && и and разный, но такой нюанс как у тебя в примере — это изобретение пхп и оно не логично

Если разный (а где, кстати, такое ещё есть?), то это не изобретение ПХП, а работает так же везде или схожим образом, так как пример и строится на разнице приоритетов.

Евгений Степанищев (bolknote.ru) автор № 21

Комментарий для zg.livejournal.com:

почему вы так решили?

А почему вы так решили? Я ответил одним голословным утверждением на другое.

DuMOHsmol (anothersite.ru) № 22
А еще есть редко упоминаемый оператор "", синоним «!=». Насколько помню, приоритеты у них одинаковые.
Илья № 24

Комментарий для Евгения Степанищева:

Если разный (а где, кстати, такое ещё есть?)

Такая же ботва в Руби: http://www.techotopia.com/index.php/Ruby_O … Precedence
Частенько использую их в стиле

redirect_to 'xxx' and return
check_something or raise some_exception

Илья № 26
Комментарий для Евгения Степанищева:

Да, и такая же проблема с присваиванием и вообще. Поэтому очень быстро отучаешься использовать в сложных случаях, так как почти всегда оно работает не так, как ожидаешь. Фактически, только как в примере выше и использую, удобно — емко, кратко, вместе с тем читабельно.