Pull to refresh

Comments 162

Пару месяцев назад решил поближе познакомится с Си и был в смятениях от битовых операций, так как всегда старался их избегать из-за кажущейся сложности и лишней трушности и олдшкульности. :) В итоге несколько часов убил на ознакомление по средствам чтения интернетов и метода тыка.

Теперь будет куда поглядывать за справкой. Большое спасибо за статью.
А когда-то давным давно изучения языков программирования начиналось именно с этого :)
Так раньше и компьютеры были только в крупных НИИ. А сейчас, начинают делать сайты чуть ли не в начальных классах школы.
Ну почему давным давно?
Мне немного за 30, я учился именно так. И кодили мы на всем от контроллеров, где написанную на асме прогу надо переводить в коды по таблице и вводить кнопками 0-9,A-F.

Не так давно это было. С нас еще песок не сыпется :)

PS: Но школоты полно. :(
Ага, было дело… И после тех лабораторных (у нас их так называли) забавно было слушать тех, кто рассказывал как сложно кодить на асме в текстовом редакторе, потом компилировать и т.д. :) (с учётом того, что вичисления не сильно отличались у нас и у них)…
какое еще давным давно? в прошлом году на чемоданчике в машинных кодах лабораторную работу делали) вначале пишешь программку на asm'е, затем переводишь руками в машинный код и вбиваешь в чемоданчик побайтово значения
Мне немного за 20 и я тоже кодил винрарный чёрный ящик :)
Почему же давным давно, я вот буквально год назад, на первом курсе первым делом изучал двоичный код, все его состояния, все операции над ним.
А хорошие мальчики и девочки помнят и знают это из курса алгебры, а точнее булева алгебра. Программа между прочит 9 или 10 класса (в Молдавии). И в институте это тоже должны давать
Все мы учили химию в школе, но большинство сейчас не напишет элементарного химического уравнения. Так уж устроен мозг, что информация которая регулярно не используется — забывается.
С тех пор ничего не изменилось. Просто многие, как сказано в первом комментарии, «избегают из-за кажущейся сложности и лишней трушности и олдшкульности».
Они лишают себя возможности осознать гениальность изобретения булевых операций :)
Они прогуливают уроки, СПАСИБО ФУРСЕНКО ЗА ЭТО!
Когда-то давным давно изучение языков программирования начиналось с изучения родного языка. Как видите, теперь это необязательно.
Если по поводу моей опечатки, то, к сожалению, на Хабре нельзя редактировать сообщения :) Я её заметил тогда, когда отправил сообщение. Но если хотите посоревноваться в знании языка, я готов :)
Если вам битовые операции кажутся излишне трушными, то зачем вы вообще программировать пошли? Я боюсь, что операции с указателями у вас бы вообще мозг взорвали.
И кстати в php ведь нет перечислений, без них вся эта шляпа с дефайнами — потенциально грабли!
> зачем вы вообще программировать пошли?

Гвозди тоже умею забивать, но в столяры же меня никто не записывает.

P.S. Операции с указателями мозг не взрывают.
Есть такая штука, как желание понимать код без лишних размышлений. Если написано substr($source, 0, strlen($prefix)) == $prefix, то, например, я сразу увижу, что у строки $source проверяется наличие префикса $prefix, пусть и несколько громоздко. Если я увижу strpos($source, $prefix) === 0 или !strncasecmp($source, $prefix, strlen($prefix)), то мне придется чутка поднапрячься, чтобы увидеть то же самое (хотя в первом я это и так вижу, потому что часто использую, а второе понимаю, потому что тоже когда-то писал на Си). А вот если там будут стоять какие-то монструозные конструкции, работающие за «полтора такта» процессора и занимающие пять символов кода (или, наоборот, тридцать строк), но при этом настолько для меня неестественно используемые, то на расшифровку строки кода уйдет много больше времени (по сравнению с примерами выше).

Нет, я не хочу сказать, что ТС сказал какую-то бесполезную глупость — наоборот, спасибо, возможно, я это применю как-нибудь в том же обработчике ошибок. Да, учиться полезно, и так мы узнаем новое. Да, в конце концов есть комментарии. Однако я не из поколения компьютеров размером со шкаф, и у меня нет болезненной идеи оптимизировать все без разбору — я приверженец мысли, что если код требует комментария с описанием работы, когда его (код) можно переписать так, чтобы он был очевиден (другие имена переменных/функций и, возможно, несколько более длинное и неизящное решение), то его нужно переписать, а вот если это — бутылочное горлышко программы, то можно сделать реализацию понепонятней и побыстрее, но отметить это место комментарием «так быстрее работает, чем обычная реализация».
А мне strpos($source, $prefix) === 0 кажется более понятным, нежели substr($source, 0, strlen($prefix)) == $prefix. Если Вам второй вариант понять и просчитать в уме проще, то Вам и с бинарными операциями будет на порядок легче ;)
Т.е. вам понять substr($source, 0, strlen($prefix)) == $prefix легче чем strpos($source, $prefix) === 0?
Мне одному кажется это странным?
Все относительно и сугубо индивидуально. Зависит от многих факторов, в том числе и от того, с чем раньше работал кодер (языки, технологии, стили кодирования etc). Впрочем, как я уже сказал, в основном я у себя использую strpos для таких целей, и поэтому мне это видеть точно так же просто, как и сравнение подстроки с переменной.
Удобочитаемость должна стоять на первом месте. Однажды пришлось написать такой код:
boolean option1, option2;
...
option1 = (option1 && option2) || (!option1 && !option2);
//option1 = ! (option1 ^ option2);

И закомментировал я отрицание исключающего ИЛИ от греха подальше, потому что сам через час бы не вспомнил, что имел ввиду.
А я вот вторую строчку использую и иногда более сложные условия, правда обычно они в методах типа testFlag, setFlag и т.д. инкапсулированы. Но блин, мозги тоже разминать надо!
мм…
boolean option1, option2;
...
option1 = (option1 == option2);

не? вроде гораздо читабельнее, чем оба варианта
ну не знаю, для меня последний вариант более читабелен, чем самый первый, может все дело в опыте? а второй вариант вообще совершает кучу ненужных операций и в strlen($source) раз медленнее, чем нужно
Самый первый пример (названный плохим), может читать вслух, с выражением, нараспев любой, читающий код. Его даже может понять человек не программирующий. Особенно если or поставить вместо ||.
А вот такое if($error['type'] & ( E_ERROR | E_PARSE | E_COMPILE_ERROR )) просто так вслух не прочитаешь.
Тот же самый минус у тернарных операций.
Но согласитесь, что здесь уже вопрос квалификации. Может, если человеку обязательно нужно or вместо ||, то ему и не следует лезть в этот код? А если ему действительно это нужно, то в случае с || Вы его подтолкнёте к новым знаниям, что может оказаться довольно полезным для молодого специалиста.
Но оговорюсь — всё должно быть в меру :) Я в perl'е использую разные конструкции, но предпочту оставить конструкцию if'ов/for'ов на несколько строк, одной строке на 500 символов из map'ов/grep'ов (для примера). Но опять же, когда конструкция получается читабельная и не слишком длинная, то я лучше оставлю одну строку, вместо десяти…
а что, програмировать уже нельзя без этого? тем более есть языки где вроде вообще нет никаких битовых операций и что?
if($user_perm & U_READ)

1001 & 0001 = 1001 — это true?
1000 & 0001 = 1000 — это false?

Простите, не знаком с php truth.
О, сорри, лоханулся. Забудьте мо. Вопрос :)
1001 & 0001 = 0001 — это true
1000 & 0001 = 0000 — это false

ЗЫ

Что-то я в шоке от комментов. Мне как С++ программисту ТАКОЕ видеть страшно!
Ну далеко не во всех книгах по PHP делают внятное объяснение по битовым операциям, все сразу начинают интернет-магазины писать или блоги. Плюс еще специфика языка с динамическими типами и низким порогом вхождения. Так, что отсутствие понимание по этой теме вполне объяснимо.
Обьяснимо то оно обьяснимо, но не нормально!
Зайдите на сайт govnokod.ru, там зачастую такое отмачивают, что незнание битовых операций, покажется цветочками :) Да и незнание не грех, хуже когда, при это не учатся.
Пускай новички лучше изучают ООП, паттерны, TDD и SQL, чем забивают мозги побитовыми операциями, которые будут совать в «спагетти»-код.

Вот сейчас сижу рефакторю и покрываю тестами «олдскульный» php-код, мне тут только побитовых операций для полного счастья не хватает.
Спорный вопрос. Сам об этом постоянно думаю. Еще к этом можно прибавить, что нафик пользоваться операциями выделения памяти.

Я думаю, но всегда оглядываюсь назад и спрашиваю себя: Был бы я теперь вменяемым программистом, если бы не начинал с паскаля с ассемблерными вставками (1-й курс универа)?

Все таки люди должны понимать зачем они уходят в абстракцию, забывая навыки использования азов: машинный код -> ассемблер -> язык программирования -> процедурный подход -> объектный подход.
Тоже часто об этом думаю. Правда вменяемым программистом себя не считаю, скорее быдлокодером. Но всё равно, с одной стороны, программирование на ассемблере, бэйсике, паскале, си и т. п. дало много несознательно применяемых «антипаттернов», с другой — если бы я осваивал пэхэпэ в начале 2000-х как первый язык, то, вероятно, мой код был бы ещё хуже, чем сейчас. Хотя напрямую не могу сказать, что какие-то практики из прошлого тысячелетия применяю, скорее сознательно избегаю их, на своей шкуре почувствовав, какие проблемы они могут принести, взять те же глобальные переменные или goto :)
Ассемблерских вставок у меня небыло, но начинал с Borland Pascal в техникуме, а через полтора года влился в WEB разработку на PHP, быстро попал в сильный коллектив местных зубров веб девелопмента что крайне положительно сказалось на квалификации и понимании вещей.
Я всё-же считаю PHP на профессиональном уровне достаточно сложным языком, т.к. слишком 95% поддаются соблазну сделать посбыстрее, нежели подумать и сделать правильно. Правильно в основном делают те, кто имеет хоть какой-то опыт программирования на компилируемых языках и вообще имеет представление о теории компъюторных наук, либо к ним пришол дзен после десятка лет работы и саморазвития :)
Нельзя новичков в ООП пускать. Это взорвет их мозг, и в результате код будет еще ужаснее, чем мог бы быть.
Уж лучше хоть какое-то ООП, чем спагетти с глобальными переменными и mysql_fetch_row();

А если новичков сначала на современные фреймворки сажать…
А что такого натворил mysql_fetch_row? Он легко читается. Даже в учебниках по Codeigniter есть такие примеры (остальные свой ActiveRecord везде активнее используют).
Не знаю, мне так сложно запоминать $row[7] это id отправителя или время отправления. А если выборка идет по SELECT * так еще надо в базу залазить и смотреть, что вообще там выбирается.
У-у-упс, перепутал с mysql_fetch_array, прошу прощения.
mysql_fetch_row() лучше сразу комбинировать с list():
while( list($id, $pid, $name) = mysql_fetch_row($result) ){...}
Мне как то не нравится наблюдать в классе тонны HTML кода.
Смотришь, вроде и MVC используют, но через 5 минут понимаешь, что рано радовался – логика находится везде так как и отображение.
Нужно понимать уметь применять и то, и другое правильно. Ни знания ООП, ни понимание побитовых операций еще никому не вредили.
Ну, имхо, битовые операции редко бывают нужны для «магазинчиков» и «бложиков», кроме, разве что, error_reporting(E_ALL | E_STRICT);. Человека, который с ИТ знаком на уровне «обычного пользователя», все эти битовые премудрости скорее отпугнут, а профит от них далеко не очевиден, если, конечно, не расписывать $user_perm &= ~ U_DELETE; как кучу if'ов. А для новичка (а может и не только) вообще читабельней будет что-то вроде $user_perm['can_delete'] = FALSE;, а то и $user->disableDelete();
Флаги — это вполне себе типичное использование битовых операций и очень часто нужное. Хотя в PHP же нету аналога enum'ов и поэтому там вся простота и наглядность теряется.
Хотя в js enum'ы прекрасно эмулируются. Если в php можно делать неизменяемые static поля у классов, то и там можно эмулировать нормальные перечисления.
Типичное — согласен. Насчёт нужного — нет, если мы не драйвера или hiload пртоколы пишем. А вот перечислений действительно не хватает, приходится вручную описывать константы с ручным инкрементом, что чревато.

Неизменяемые делать нельзя, модификаторы типа const отсутствуют (так же как, например, и final), разве что статические геттеры для приватных свойств, инициализируемых при «компиляции», но это несколько не то и семантически, и инициализация только самая примитивная допустима.
const есть, только для массивов такое не прокатит.
А, ну да, я «для классов» прочитал как «для объектов». А так, в принципе да, можно сделать что-то вроде:
class UserMermission {
const READ = 1;
const WRITE = 2;

}
но не получается что-то вроде
class UserMermission {
const READ = 1;
const WRITE = self::READ +1; // или придерживаясь темы self::READ << 1;

}
Что затратнее? Сравнивать строчки или сравнивать числа? Зачем преждевременной пессимизацией заниматься? Тем более, что использование флагов очень даже читабельно выглядит и не ест мозг.
Причём тут PHP? *facepalm* Это даже не программирование, это — обычная математика. Если программист не знает таких вещей — это просто говнокодер.
З.Ы. С замиранием сердца жду на хабре статей на темы «Циклы» и «Условные и безусловные переходы»
Полегчало? Ну да все кругом говнокодеры кроме, такого гениального программиста как Вы.
На хабре есть много статей которые я считаю элементарными, но в отличии от Вас я понимаю, что знания у людей разные, и то что не нужно мне, может пригодиться другим людям.
Так что если в статье для вас ничего нового, просто проходите мимо, ну или поставьте ей минус, но не стоит опускаться до оскорблений.
это не оскорбления, а адекватная оценка специализдов подобного уровня. Чтобы знать такие вещи гением быть не надо. И это не «я считаю элементарными», это есть практически в каждом мало-мальски нормальном учебнике по программированию.
До некоторого мнения я считал что хабр — это если не сборище мегамозгов, то по крайней мере достаточно грамотных людей, которые знают подобные вещи. Я ошибался.
Это именно оскорбления. А можно ссылку на этот сферический учебник по программированию? Как-то мне встречаются только учебники по определенному языку.
И могу привести десяток книг по PHP, в которых упоминается о битовых операциях, только то, что они есть или вообще не упоминается.
Я понимаю если бы у Вас было куча гениальных статей на хабре, или типа ваша статья о виджете на Dojo именно на мегамозги расчитана, которые видимо читать документацию не умеют? :)
Моя статья была написана по причинам:
1. желание получить инвайт, были планы о других статьях по Dojo, более серьёзные — но как-то уже не охота, формат ресурса не тот, который я ожидал
2. русскоязычной информации по Dojo — с гулькин хрен, в отличие от jQuery он не популяризован (что на мой взгляд совершенно неоправданно)

И формат статьи такой, что на момент написания я сам изучал его, потому извините, шедевра не получилась. Но сравнивать основы программирования и платформы для front-end разработки некорректно.

Задрали уже эти веб-«программисты», сайтоделы… Уже два месяца не можем серверного PHP-кодера найти не можем (в СПб!) — приходят овощи, ни шаблонов проектирования, ни алгоритмов не знают. А некоторые вообще скатываются до «а что, это нужно PHP-программисту»? Для них программирование — говносайт на Цэ-Эм-Эс нахреначить.
… уф, выговорился… прям крик души )

Интересно, а возможны гуру программирования которые не в состоянии читать документацию на английском? ;)
Хм, а что такое серверный PHP-кодер?
Ну, а вообще после учебников, типа, «PHP за 24 часа», чего ж Вы хотите. Тем более, что имхо программирование выучить нельзя, для этого должен быть определенный склад ума.
На самом всё просто, компьютеры стали намного доступнее, потому порог вхождение стал значительно ниже, так что с этим можно только смириться.
Я не ориентируюсь на гуру программирования (и так же сам себя им не считаю) — гуру программирования знают всё и ещё чуть-чуть, потому учить их чему-то… А вот непопулярность Dojo (имхо в связи с отсутствием статей-уроков-туториалов) по сравнению с jQuery — вещь достаточно очевидная.

Серверный PHP-кодер… Ну я имел ввиду архитектуру приложения. Сейчас вот занимаюсь фронт-ендом, но морда делается не только на Dojo, но и на PHP/ZF, а нужен ещё и серверный — создание веб-сервисов, которые бы связывали морду и чисто серверные модули (+бд разумеется).

Специализдов «за 24 часа» гнать в шею надо, чтоб не «позорили честь мундира». Не так давно российские программисты считались одними из лучших, сейчас уже увы не так.
По-моему российские программисты и дальше выигрывают различные олимпиады. Но это же не значит, что это может сделать любой российский программист ;) А хабр как по мне скорее не сборище для мегамозгов, а хранилище полезной IT-информации, ну это имхо.
А мне вот страшно вспоминать как с WinAPI работать на ассемблере :)
Вы сами сказали, " как С++ программисту". Область применения у C++ и php разная.
На уровне вебморды к браузерным играм?
На любом уровне. Я начинал писать веб-приложения (тогда и слова-то такого не было, просто сайты) именно на C++, CGI приложения. Тогда (в конце 90-х) они на шаред-хостинге работали быстрее, чем нынешние на PHP на VDS от Хетцнера. Но когда открыл для себя PHP, то на C++ как-то перестал писать. Когда PHP3 сменился массово на PHP4, то о C++ вспоминал с ностальгией, когда на PHP5 и VDS стали по 100 рублей — о С++ вспоминаю с ужасом. Хотя вру, от статической типизации не отказался бы. Жду-не дождусь, когда type hinting будет работать в PHP на примитивных типах.
Значит я могу со спокойной душой называть php программистов быдлокодерами?
Есть некоторые базовые вещи, которые ОБЯЗАННЫ преподавать ещё в школе, если программист на любом языке, даже на 1С их не знает, то как он вообще смеет себя программистом называть?
Предлагаю пройти в мой опрос, где люди уверены, что в байте 8 бит, 6 бит, 2 бита.
я там выше еще написал. Ребята вы вообще о чём пишете? Это проходят в старших классах школы в курсе алгебры 9 — 10 класс.
Дело в том что многие «программисты» ещё и 6-й класс не окончили.

(Почитайте форумы, повсюду вопросы класса «как посчитать параметры для LIMIT в SQL зная номер страницы и количество постов на страницу»)

И обидно не то что они не обученные, а то что уверены что знают достаточно и не хотят учиться дальше.
define('U_READ', 1 << 0);   // 0001
define('U_CREATE', 1 << 1); // 0010
define('U_EDIT', 1 << 2);   // 0100
define('U_DELETE', 1 << 3); // 1000
define('U_ALL', U_READ | U_CREATE | U_EDIT | U_DELETE); // 1111

ИМХО такое лучше записывать в 16 ричной СС
0x1, 0x2, 0x4, 0x8, 0x10, 0x20 
<source>
Выглядит аккуратнее!
Так не будет видно как работает оператор сдвига ;)
Ну разве что если разжевать совсем уж неумехам.
Так вроде это как раз статья для тех кто не разбирается или плохо разбирается в битовых операциях, тут как бы никаких открытий. Просто хотелось именно на примерах показать, а то зачастую люди могут прочитать про битовые операции, вроде как даже понять, что прочитали, но как их применять на практике может быть не совсем понятно.
А мне со сдвигом больше нравится — сразу понятно, что установлен именно один бит.
Тут есть один момент, сдвиг не будет работать при определении констант класса. Поэтому я везде пользуюсь шестнадцатиричным определением констант, которые могут применяться в битовых операциях.
в пхп есть какие-то отличая в битовых операциях от других языков программирования?
Нет, так же как везде, я написал об этом внизу. Просто непонимание этой темы заметил именно в статье по PHP, и примеры написаны на PHP.
Вы так говорите как будто без битовых операций, прям нельзя на PHP ничего написать. Просто редко используется и многие не заморачиваются с их изучением. Довольно много народу, к примеру, не разбираются в типах данных, и например в MySQL используют BIGINT, где достаточно TINYINT и т.п.
После того, как пару раз делал ALTER TABLE при близком переполнении INT, предпочитаю везде ставить BIGINT :)
Ну я имел ввиду поля не счетчики, которые в принципе не могут вылезти за TINYINT.
По-моему, такая экономия на спичках должна проводиться при профилировании, когда тесты покажут, что, например, SELECT с выборкой по TINYINT качественно меньше потребляет ресурсов чем по BIGINT.
Ставить BIGINT для поля, в котором будет 15-20 значений и неболее смысла нет. К тому же если вам нужен индекс по этому полю — размер имеет значение.
Минимум один раз сталкивался, когда изначально больше десятка значений не предполагалось, но очень быстро заполнилось 255.

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

Вообще применение BIGINT весьма специфическая задачка и уже зарание известно что будут большие числа. А для работы с деньгами вообще юзается DECIMAL :)
На хабре уже туториалы из школьного курса информатики? :)
Думаю поиск по хабру в случае чего, сработает быстрее поиска по учебнику информатики, которого нет в наличии ;) Так что полезно будет, если понадобится освежить память.
Круто, менять статью не буду, но сошлюсь как дополнительный материал, действительно элегантно вышло с ошибками. Как-то совершенно забыла моя голова о таких низкоуровневых операциях, когда думаешь обо всем не ниже объектного уровня и без контроля выделения памяти.
Я изначально хотел в комментах к вашей статье написать, но получилось как-то длинно для коммента, плюс там в нескольких местах встречались вариацию на тему, поэтому решил в качестве статьи оформить. Да и найти статью будет проще для освежения памяти.
$user_perm =  U_READ;
if($user_perm & U_READ) // есть ли право чтения?

Надо отметить, что для такого условия можно использовать в качестве второго аргумента только не составную константу (т.е. в битах такой константы должна быть только одна 1), иначе можно получить ряд проблем.

// 1 вариант
var_dump((bool)($user_perm & U_ALL)); //все права? - true - неправильная проверка
var_dump((bool)($user_perm & U_READ)); //чтение? - true
var_dump((bool)($user_perm & U_EDIT)); //редактирование? - false
// 2 вариант
var_dump(($user_perm & U_ALL) == U_ALL); //все права? - false - правильная проверка
var_dump(($user_perm & U_READ) == U_READ); //чтение? - true
var_dump(($user_perm & U_EDIT) == U_EDIT); //редактирование? - false


Конечно, теперь проверка выглядит не так красиво, зато правильно работает.
Статья очень повеселила :) Жду продолжения, например, почему в этих ваших компьютерах 5/2 = 2 или 2147483647+1 = -1 ;)))
volch@home:~$ php
<?php
echo 2147483647+1;
2147483648

ЧЯДНТ? :)
%) У вас мозг не 32-разрядный.
<?php
echo PHP_INT_MAX;

9223372036854775807
:)
Я, конечно, всегда старался избегать стереотипного мышления о PHP-программистах, но, простите, целая статья о битовых операциях… Вы серьезно?
Битовые операции — это даже не особенности стандарта IEEE 754, не принципы ООП, не указатели, не использование Windows API, не проблемы переполнения, даже не порядок выполнения операций… Это первые страницы любого, даже самого убитого учебника по любому языку программирования…

Для изучающих язык это, возможно, и полезно, но тогда половина PHP-программистов на хабре — изучающие PHP программисты… другого необидного объяснения я найти не могу.
Для многих сейчас PHP — это первый язык программирования. И далеко не все книги по нему начинаются с двоичного исчисления и битовых операций. Лично я не одной такой не видел, кажется. В лучшем случае вскользь упоминаются.

И да, я изучаю PHP уже лет 10, всё никак не изучу. Вот, вроде бы, только освоил фичи 5.3, а уже 5.4 на подходе с какими-то traits.
Опущу свое мнение по поводу того, что PHP для многих — это первый язык программирования…

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

А что там упоминать про битовые операции?
Это не какой-то высший пилотаж. Это вообще никакой не «пилотаж»…
И рассказывают о них во всех учебниках наряду со всеми другими «полупродвинутыми» операциями (унарные и тернарные, которые и то сложнее выглядят...).

И да, я изучаю PHP уже лет 10, всё никак не изучу. Вот, вроде бы, только освоил фичи 5.3, а уже 5.4 на подходе с какими-то traits.

Слово «изучающие» в моем комментарии стоит расшифровывать, как «изучающие основы языка».
То, что программист должен непрерывно увеличивать свой багаж знаний — это итак понятно.
Тем не менее, битовые операции и traits — между ними расстояние, как между арифметикой и матаном.
Битовые операции многие боятся как огня (наряду с временными зонами и кодировками).
Посмотрите сколько народу добавили эту заметку в избранное. Очевидно, считают ее полезной.
Именно и пугает тот факт, что многие добавляют эту статью в избранное.

наряду с временными зонами и кодировками

Серьезно… если человек ставит битовые операции по сложности на один уровень с временными зонами и кодировками, то «Вон из профессии».

Это простительно для начинающих или неспециалистов, когда даже целочисленное деление ставится под сомнение, но не для человека, который серьезно занимается программированием (и/или получает за это зарплату).
Серьезно… если человек ставит битовые операции по сложности на один уровень с временными зонами и кодировками, то «Вон из профессии».

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

Я лет 7 назад даже рекурсию не использовал, т.к. она у меня в голове не укладывалась, а сейчас не соображу, что же в ней такого было мне непонятно.
Процитирую самого себя:
Это простительно для начинающих или неспециалистов, когда даже целочисленное деление ставится под сомнение, но не для человека, который серьезно занимается программированием (и/или получает за это зарплату).

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

Но если человек занимается программированием профессионально и при этом не знает или не понимает битовые операции, которые являются базовыми, наряду с арифметическими, булевыми операциями, то я не понимаю, что человек вообще делает в этой профессии.
Это все равно, что считать интегралы, не понимая определения предела — посчитать по формулам можно, но как математик человек не состоялся точно.
Склонен считать базовыми те возможности, без которых нельзя решить существенную часть задач. А без битовых операций в PHP можно сделать что угодно. И лишь в некоторых случаях их использование предпочтительнее.

Налепить статических классов и говорить, что это ООП — непрофессионально.
Отказываться понимать битовые операции — непрофессионально.
До определенного момента не понимать битовые операции — нормально.
Если вы учились на копъюторных науках, то вы должны знать что из группы в 25-30 человек реально программистами, админами и прочими становится 2-4 человека, редко когда больше. У меня в группе было 28 человек, на 3-м курсе в программисты ушло 16 человек. Из них программистом работаю только я (WEB — PHP, MySQL и.т.д.) и ещё один человек (ушел в Java). И это несмотря на то, что в общем-то при желании могло бы быть человек 10. А вы про битовые операции, я чуть чаем от смеха не подавился.
>А что там упоминать про битовые операции?
Вот так же думают большинство авторов и не упоминают, только возникает вопрос — а как человек изнает об этом, купив и прочитав пару книг? Как можно знать что то о существовании чего ты даже не подозреваешь? :)
Возможен другой вариант.
Можно учиться программированию. А можно изучать конкретный язык. В общем случае это совершенно разные задачи.
Думаю, что большинство книг (да каких там книг — чаще просто статей tutorial) по PHP учат не основам программирования, а конкретным вещам в языке. Знание структур данных, указателей, основ машинной арифметики очевидно презюмируется.

Да и не настолько web-программирование обширная сфера, чтобы требовать от разработчиков этих знаний. В итоге имеем низкий порог вхождения в язык и как следствие — статья про битовые операции — в Лучшем :)
Вот именно, что при низком пороге вхождения и появляется куча школьников, которые в лучше случае одну книжку прочитают, а то и вовсе ничего не читают, а начинают ломиться к гугл и сразу на форумы свои вопросы вывалить. Так что в это случае полезность данной статьи очевидна — на хабре и школоты развелось — почитают лишний раз — научатся чему то новому.
Выкидывать такие книги надо! Как можно вообще браться за написание чего-либо, не зная булевой алгебры и не понимая системы счисления?
Насчёт булевой алгебры согласен, но побитовые операции это не она в чистом виде. А вот системы счисления — знания, которые необязательно пригодятся при разработке веб-приложений.
Побитовые операции — это самая, что ни на есть чистая и незамутнённая булева алгебра!
Тут как бы прикол в том, что человек вполне может понимать, как работает булева алгебра, но как применить на практике не знает. Это примерно то же как было с AJAX, ведь эта фича была реализована в IE еще в 98 году, и вполне возможно что многие о ней прочитали и знали, но пока её не назвали AJAX и не показали на примерах, как с этим работать, она почти не использовалась.
Если вы про асинхронные запросы — основу ajax, то дело было ещё до IE, и делали его ява-апплеты, MS со своим ActiveX-компонентом сыграла позднее. Наличие примеров и название повлияло на популярность куда меньше, чем «свободная» реализация в js XMLHttpRequest-объекта.

Это я не к тому, что примеры не нужны, а к тому, что пример не гарантирует популярности.
Если, конечно, это не дурной пример — вот он заразителен.
Ну для java-апплета все-таки больше нужно сделать (это примерно то же, что сейчас для AJAX Flash использовать), чем одну строку добавить. Ведь все AJAX приложение успешно работают и в IE 6. Аналогично можно вспомнить WYSIWYG редакторы, тоже относительно недавно появились, хотя этот функционал еще в IE 5.5 ввели.
Ну, положим, про одну строку это преувеличение, иначе зачем бы Дима Котеров стал писать JsHttpRequest %)

А вообще, есть мнение, что всему своё время: популяризация указанных выше техник и технологий — есть следствие эволюционного развития ИТ. И, пока я окончательно не ударился в философию, уйду спать.
Он насколько я помню начал её писать, потому что в альтернативных браузерах, не сразу прикрутили аналоги.
Да бросьте, его сплошь и рядом в те годы в чатах применяли, а делать обновляющиеся на лету странички было невозможно из за повсеместного диалапа.
Ну да обновить всю страницу диалап позволял, а скачать только изменившуюся часть проблема.
Позволю себе не согласиться. Побитовые операции это расширение булевой алгебры на двоичное представление чисел.
Булева алгебра — это абстрактная теория, двоичное представление чисел — это одна из реализаций, а не расширение. Точно такая же реализация, как например теория множеств
Двоичное представление вообще никакого отношения к булевой алгебре не имеет. Побитовые операции это гибрид двоичного представления и булевой алгебры.
Информатика для самых маленьких
Много кто в комментариях говорит о бесполезности сей вещи в php, но мне кажется, что бинарные операции могут существенно понизить трудности в некоторых вещах. Например: в каталогах товаров (интернет магазины, и прочее), где у товара может быть много разных свойств, использовать бинарные операции более удобно, и элегантно). С начала года изучаю WinAPI (почти все построено на бинарных операциях), и тоже назревали мысли по поводу использования бинарных операции в php. Теперь точно буду. Спасибо автору!)
Для большей наглядности рассмотрим в качестве примера, простую систему разграничения прав доступа к сайту.

Вот что следует понимать: пример удачен в плане наглядости разбора битовых операций, однако с хорошей долей вероятности привести к проблемам читаемости, а значит и поддерживаемости кода на практике. Так, по отношению к реляционным СУБД хранение прав пользователя в виде указанных 4-х битов в одном поле можно трактовать, как случай неоправданной денормализации со всеми вытекающими.
А что мешает хранить даное значение как TINYINY конвертировав его при помощи bindec()?
Не надо конвертировать.
Здравый смысл и любовь к ближним %)
Мой комментарий не о невозможности хранения, он несколько о другом.
MySQL тоже вполне успешно поддерживает битовые операции, так что тут всё зависит от того как их использовать. А что касается наглядности, то эти биты обернутся в методы, и всё, и никак это на читаемости не скажется (те кто их будут юзать могут даже не догадываться, что там битовые операции используются). Зато поиск в MySQL по такой битовой маске в одном поле, будет явно быстрее, поиска по десятку полей в которых хранятся значения 1 или 0.
Есть многое на свете… Обернуть можно практически всё, во что будет угодно, если, конечно, забыть на время, что кому-то захочется увидеть расклад прав без помощи нашего приложения %) Вопрос в сомнительной полезности такой затеи.

Верно, что битовые операции поддерживают многие СУБД, только делают они это на разном уровне, иногда даже разными средствами. Выходит, что приложение, заявлющее поддержку разных СУБД, должно будет учитывать возможные нюансы. Присовокупьте к этому, что каркасы для разработки не предлагают выделенных интерфейсов для битовых выборок (поправьте, если я ошибаюсь) и получите довольно живописную прозу, в которой разработчик в погоне за эфимерным быстродействием и в попытке сэкономить пару сотен байт пускается во все тяжкие. Подозреваю, что из zend engine прольётся куда больше, чем удасться сэкономить.

И с последним утверждением на счёт явности быстроты поиска я бы поспорил — быстрота будет зависеть от многих факторов.
Ну так я вроде нигде и не говорил, что битовые операции «панацея от всех болезней» в некоторых ситуациях, их использовать удобно, в некоторых лучше обойтись без них. Но понимание того как их можно применить на практике, никому не навредит.
Не навредит — абсолютно точно ;)
Я бы предложил U_ALL определять как 2147483647 (PHP_INT_MAX) или -1 (я всегда -1 использую). В вашем примере это может не пригодиться (не знаю чем можно дополнить CRUD), но в других случаях может понадобиться расширить список констант, и тогда придется менять значение U_ALL и по коду операции типа U_ALL ^ U_DELETE и U_ALL & ~ U_DELETE
В 5.4 можно писать проще: define('U_EDIT', 0b0100);
Ну всё относительно, это на маленьких числах вроде нагляднее, а если там нужно будет хранить 16 значений, будете тщательно пересчитывать нули? По-моему со сдвигом проще и нагляднее, и потом легче читать:
define('U_EDIT', 0b0001000000000000);
define('U_EDIT', 1<<12);
Ну, на самом деле, ваше значение записывалось бы как 0b1000000000000, нули перед единицей совсем лишние, разве что для выравнивания коротких значений.
Разумеется, личное предпочтение каждого. Я пользуюсь тем что обозначено выше.
Кто-то пишет 1
парсер злой сегодня. Было:
— Кто-то пишет 1«12
бывает bindec('10101')
иногда и вручную проставить можно 1,2,4,8,16,…
Лидирующие нули тут особой погоды не делают. Вы сможете с легкостью сказать сколько нулей справа от единицы и какой именно бит тут выставляется?
мм, тут такое дело: не нужно знать сколько нулей там стоит. Суть объявления констант-флажков — чтобы избавиться от значений и использовать их имена. А проставлять значения, добавляя по нулю в конец — проще.
В статье, к примеру, сдвиги использовались только для задания значений, а остальные операции: установка, сброс и проверка битов не используют сдвиги.
Ну понятно, что если пользоваться константами, то абсолютно пофиг, как она выставляется, хоть какую нибудь формулу всунуть. Но, а если к примеру нужно будет как-то использовать это значение, где-нибудь где нельзя использовать константу PHP, то считать нули таки придется.
Так что по сути это дело вкуса.
Ни разу не приходилось сталкиваться с необходимостью использовать битовые операции в PHP.
В PHP можно обойтись и без них, но иногда удобно использовать именно их.
Когда объект может иметь 40 состояний, тут как-то с битами удобней
Хорошо, как без битовых операций сделать у обьекта флаги? Причем так, чтобы обьект мог иметь сразу несколько одновременно выставленных флагов. Массив со строками держать и бегать по нему?
Вы не делаете error_reporting (E_ALL | E_STRICT)? :)
Да вы правы, для error_reporting указываю значение 30711
Часто использую битовые операции — позволяют сильно упростить условия. Резюмируя написанное:

добавляет бит(ы) из FLAGS в _state:
$this->_state |= self::FLAGS;

Удаляет бит(ы) из _state которые содержатся в FLAGS:
$this->_state &= ~self::FLAGS;

Наличие хотя бы одного бита из FLAGS в _state (может быть и все биты из FLAGS):
if($this->_state & self::FLAGS){}

Наличие всех битов из FLAGS в _state (в _state может быть и больше битов):
if($this->_state & self::FLAGS == self::FLAGS){}

Наличие всех битов в _state кроме битов содержащихся в FLAGS:
if($this->_state & ~self::FLAGS){}

В _state должен быть только один бит из FLAGS (например есть 5 состояний, но в одно время может быть только одно) Не исключает наличие других битов, не входящих в FLAGS:
if((($this->_state & self::FLAGS) & (($this->_state & self::FLAGS) - 1))){}
Если я правильно понял, то в последнем примере должно быть отрицание всего условия, иначе:
if (((0b10001000 & 0b00001111) & ((0b10001000 & 0b00001111) - 1))) {}
if ((0b00001000 & (0b00001000 - 1))) {}
if ((0b00001000 & 0b00000111)) {}
if (0b00000000) {}
Сори, отрицание забыл дописать
if(!(($this->_state & self::FLAGS) & (($this->_state & self::FLAGS) - 1))){}


так как условие
(($a & FLAGS) & (($a & FLAGS) — 1)) ==0
если в $a только один бит из FLAGS

В противном случае условие не равно не равно:
if (((0b10001010 & 0b00001111) & ((0b10001010 & 0b00001111) - 1))) {}
if ((0b00001010 & (0b00001010 - 1))) {}
if ((0b00001000 & 0b00001001)) {}
if (0b00001000) {}
Не поверите — как раз на дня задумался на эту тему и решил на досуге найти «как это делают умные люди». А тут — ваш пост. Спасибо большое!
Для php программистов полезно.
Добавлю пример, когда битовые маски это очень хорошо.
а именно с константами:


const $var1 = 1;
const $var2 = 2;
const $var3 = 4;
const $var4 = 8;


Задача хранить в базе для каждой позиции какой либо набор констант.
некоторые создают отдельную таблицу :), а умные поле, где хранится сумма констант.

Вы высказали очень спорную позицию. Надо быть гибче… где-то таблицу необходимо использовать, а где-то и одним полем можно обойтись.
именно поэтому я и говорил про константы, которых может быть конечное число :)
в других ситуациях конечно да.
например те же самые привилегии
Имхо битовые операции понимать обязан каждый разработчик.

Но со скриптовыми языками (как наверное со всеми языками со слабой типизацией) есть одно но: битовые операции почти наверняка не будут давать выигрыша в скорости (как раз из-за этой самой типизации), поэтому использовать их следует разве что для краткости записи и удобочитаемости.

Ну или для математики, например, возведение в степень двойки, проверки четности, проверки, что число содержит только один бит etc…
Разграничения прав доступа к сайту на битах. Горите в аду со своими сайтами.
Sign up to leave a comment.

Articles

Change theme settings