Безумный PHP. Фьюри код
Сборник PHP ненормальностей или что надо знать чтобы не сойти с ума и не прострелить себе что-нибудьПрочитал статью mnv: «Приведение типов в PHP == табурет о двух ножках?» и захотелось в комментариях добавить немного дополнений, но… Но потом увидел комментарий и понял, что лучше дополню статью тем, про что мало кто пишет и мало где это имеется в централизованном виде. Вроде бы всем известная тема, а все же кому-то в новинку. Это не совсем про приведение типов, но они тоже есть. Это про особенности, зная которые можно делать меньше ошибок. Если интересно, го под кат, я создал!
PHP не плохой и не хороший. Он для своих задач и с ними он справляется. При этом этот язык программирования имеет много разных багофич. Можно на них жаловаться и негодовать. А можно просто про них знать и уметь их обходить или применять. Не не не, я не призываю так писать, я просто говорю, что если захочется, то…
Прежде чем судить, давайте договоримся! Давайте рассматривать этот пост — как развлекательный. Т.е. это задачки не для собеседований и не для продакшена. Это просто примеры задач на олимпиаду, где можно получить звание «Я — интепретатор PHP!».Думай как PHP… Чувствуй как PHP… Будь PHP! Задачки взяты из нашего квеста, который мы делали на «День девелопера», отмечаемый в нашей компании. Наша коллега даже писала подробную статью про то, как в Tutu.ru чествуют труд айтишников в статье «Как отметить день программиста на работе и сделать всех довольными?». Так что повторюсь, это не для продакшена и не для собеседования. Это ради фана!
Про числа Числа в PHP, штука вещь хорошая. Про них так много говорили уже, что вроде бы все понятно. Но если говорить про PHP, есть пара дополнений, так что не буду грузить, а просто дополню парой примеров.Каков результат конкатенирования следующих строк? (да, так не пишут, но у нас же олимпиада)
Поиск строки в массиве Это вполне себе боевая ситуация. Такое может встретиться в коде некоторых CMS или реальных проектов.
Как в PHP переопределить TRUE? Вопрос на засыпку и ради академического интереса. Если очень хочется, то:
$ = 1; $ = 2; $ = $ + $ ;
var_dump ($);
//EOF// Да Символ с десятичным индексом 160 входит в таблицу разрешенных символов для именования переменных в PHP. В Windows его набрать можно как Alt+0160.
Выполнить любой ценой Это просто задачка на подумать. Опять же про приведение типов. Просто головоломка.
if ($x == false && $y == true && $x == $y) { echo «Yuo crazy developer!»; } Один из вариантов $x = 0;$y = 'x';
Безумная логика А вот еще классный пример особенностей интепретатора. Давайте ответим на вопрос, что будет? $a = 1; var_dump ($a + $a++); А если усложним?
$a = 1; var_dump ($a + $a + $a++); Если ответили на первые 2 вопроса, то тогда вам не составит труда интерпретировать вот эту задачку:
$a = 1; $b = 1;
var_dump (($a + $a + $a++) === ($b + $b++));
Ответ в следующем абзаце.Что-то пошло не так, да? ;)И в 1-м и во 2-м случае ответ 3, а значит 3й пример выдаст true. У меня есть мнение по этому поводу: все дело в оптимизации (может быть), но как минимум все дело в том, как хранятся переменные.
Когда у нас код вида ($b + $b++), то выходит следющее:1. сначала вычисляем правый операнд: вернуть 1 и увеличить на 1 $b
$b + 1, $b += 1 2. взять левый операнд $b (2) b и прибавить к нему вычисленное значение правого $b = 2 2 + 1 = 3 А теперь 2й пример.
$a + $a + $a++ Так как это сложение, то берем по 2 операнда слева на право.Взяли $a + $a Если $a = 1, то берем их значения и вычисляем результат: 1 + 1 = 2 В ячейку кладем 2, и смотрим что дальше: 2 + $a++ Ок, берем значение правого операнда (1) и добавляем его к левому: 2 + 1 = 3 Вроде бы все логично… Но на деле не логично. Так что не ломайте голову, все работает правильно. Но не так, как вы ожидали. В других языках, к примеру, Javascript, ответ будет другой. Проверьте. 2й вариант ведет себя одинаково с тем же JS. Но вот 1й вызывет вопросы, если смотреть на результаты в разных языках программирования.
Слабо проитерировать строку? Есть задача проитерировать строку:
function getCount (&$a) { return count ($a); }
$cnt = getCount ($foo); var_dump ($cnt);
// и если сделать так
$cnt = getCount ($foo['bar']); var_dump ($cnt);
Но все будет ок. Ошибка будет только в случае, если убрать амперсанд, тогда получим: PHP Notice: Undefined variable: foo in /www/sites/majorov.su/***/a.php on line 8int (0)PHP Notice: Undefined variable: foo in /www/sites/majorov.su/***/a.php on line 14int (0)
Несуществующий валидный код Давайте пофантазируем. У вас мощный проект с 10 летней историей. И у вас появилась задача рефакторинга и реинжиниринга старого кода.И вот вы правите код и сходите с ума. Почему? Ну вот потому, что, допустим, вы не понимаете почему у вас работает то, что не должно.
ACL, MD5 и… Коллизия? Представим что у вас есть CMS. И вот там есть что-то вроде такого (поверьте, много где такого кода (не именно такого, но работающего по такому принципу, можно найти в рунете).
// Допустим брутфорсим пользователя admin
// Получили пользовательский пароль QNKCDZO $_POST = ['pass' => 'QNKCDZO']; $userPass = md5($_POST['pass']);
// Есть пароль в базе такого вида 240610708 $actualPassInDb = md5('240610708');
$autorizied = false;
// сделали проверку if ($userPass == $actualPassInDb) { // Авторизировали пользователя $autorizied = true; } else { /*header*/var_dump («location: /error/»); die; } А что не так? Вроде все ок. Пароли же разные. Разве нет? Давайте взглянем на md5() хеши паролей:
QNKCDZO, в MD5 = string (32) »0e830400451993494058024219903391» 240610708 = string (32) »0e462097431906509019562988736854» Поняли? PHP видит 0 и думает что это число. А ему пох на то, что там строка, если что. Так что код может быть годный, но пользуемся проверкой не только по значению, но и по типу. Иначе беда.Foreach и ссылки на ключи На последок напомню, что, с ссылками надо быть аккуратнее.Вот пример, как получить не то, что ожидали:
$array = ['foo', 'bar'];
foreach ($array as $k => &$foo){ $foo .= $k; }
var_dump ($array);
foreach ($array as $foo) { var_dump ($foo); }
Что ожидаем? А что получаем? А получаем вот что:
array (2) { [0]=> string (4) «foo0» [1]=> &string (4) «bar1» // важно, здесь указатель ! } string (4) «foo0» string (4) «foo0» Из-за спрятавшегося указателя при следующей итерации мы получаем доступ к другому значению.Собственно это весь мой комментарий к той статье, который я хотел добавить. Учите особенности языка. Учите их не ради того, чтобы валить на собеседованиях. Учите их, чтобы самому в такую яму не попасть. Не брезгуйте. Вы так не пишите, так другие так могут написать. А кто будет объяснять им почему не так и что не так? А как объяснить то, чего не знаешь?
Мир вам, девелоперы. Я писал на PHP 12 лет, и сейчас уже 3 года как во фронтенд разработке, схожу с ума с JavaScript, но это уже совсем другая история ;) Но иногда хочется потрогать это самый PHP.
Так же советую к прочтению статью от AlexLeonov Готовимся к собеседованию по PHP: ключевое слово «static», там есть интересные моменты, которые я не стал описывать.
P.S.: на картинке PHP MV 9. Пистолет PHP (Prvi Hrvatski Pistolj — первый хорватский пистолет) был в спешном порядке разработан в отделившейся от союзной Югославии Хорватии в начале девяностых годов 20 века, когда страна отчаянно нуждалась в оружии из-за возникшей на руинах СФРЮ войны. Пистолет, вобравший в себя черты таких известных и достаточно удачных образцов как Beretta 92 и Walther P38, вышел гораздо менее удачным и имел проблемы с надежностью. Выпуск его был довольно непродолжительным и позже он был заменен на вооружении Хорватской армии гораздо более удачным пистолетом HS 2000.
Пистолет PHP использует автоматику с коротким ходом ствола, запирание осуществляется при помощи расположенной ниже ствола качающейся личинки. Возвратная пружина расположена под стволом. Ударно-спусковой механизм курковый, двойного действия (самовзводный). Слева на рукоятке расположен рычаг безопасного спуска курка с боевого взвода. Магазин двухрядный, емкостью 15 патронов.
Будьте аккуратны, не прострелите себе чего-нибудь!
Кстати, у нас в компании весело! Приходите к нам, в Tutu.ru за новыми возможностями, их есть у нас ;)