Детские ошибки, которые в последнее время отъели у меня немало времени и нервов. Разрабатывая сложные вещи не забывайте и о подобной чепухе. (Все примеры сведены к бессмысленному минимально иллюстрирующему коду).
OR
В PHP, как самом умном, результатом операторов && и || является TRUE/FALSE. Казалось бы, логично, что результатом логического оператора является логическое значение. Однако, другие языки развратили меня тем, что возвращают в этом случае значение одного из аргументом.
В итоге строка $x || $y || $z
вместо целочисленного значения одной из переменных, вернула предательский TRUE. После нелёгких поисков пришлось одну строку заменять на кучу ветвлений.
MBString
MBString работает с UTF-8? Хуй там! То есть в наиболее распространённом случае с UTF-8, а в общем случае зависит от того откуда руки у админа растут. Может и с какой-нибудь японской кодировкой.
Поэтому совсем уж по-правильному (чтобы не надеяться на настройки) кодировку нужно указывать одним из аргументов: mb_strlen($str, "UTF-8")
.
Какой я молодец, что с самого начала вынес строковые функции в отдельный классег : )
Контексты, будь они неладны
function func() { global $global_var; echo $global_var.'<br />'; } $global_var = 0; for ($i = 0; $i < 5; $i++) { $global_var = $i; func(); } |
Глобальные переменные в общем случае зло, но здесь так надо, поверьте :). Всё работает как надо.
Немного усложняем: вышеприведённый код, это одна из «страничек», которые подключаются по различным условиям внутри какой-то функции, после чего всё магическим образом перестаёт работать.
function includePage() { // Вычисляем $filename // ... require($filename); } |
Подключаемый внутри функции includePage() сценарий, выполняется в контексте этой функции, а $global_var становится локальной переменной этого контекста. И хрен до неё теперь достучишься из func().
// Нужно объявлять переменную так: global $global_var; $global_var = 0; // Или так: $GLOBALS['global_var'] = 0; |
Преобразования типов
/* Рисуем пагинатор */ $pageSize = 5; // Количество элементов на страницу $elementsCount = 12; // Общее количество элементов $pageCount = (($elementsCount - 1) / $pageSize) + 1; // Общее количество страниц /* Текущую страницу достаём из GET */ $currentPage = isset($_GET['page']) ? intval($_GET['page']) : 1; /* Проверяем диапазон */ if ($currentPage < 1) { $currentPage = 1; } elseif ($currentPage > $pageCount) { $currentPage = $pageCount; } /* Расчитывем значения для разделя LIMIT SQL-запроса */ $limitStart = ($currentPage - 1) * $pageSize; $limitSize = $pageSize; |
12 элементов по 5 на страницу. Всего 3 страницы. На последней странице отображаются последние два элемента выбираемые запросом с LIMIT 10, 5. Если запросить 4-ю страницу, то должна отобразиться 3-я. Запрашиваем 4-ю: отображается только 1 элемент.
Почему? Потому что $currentPage у нас не 3, а 3.2. Потому что нужно приводить типы: $pageCount = intval(($elementsCount - 1) / $pageSize) + 1;
.
На поиск ошибок дошкольного уровня всегда уходит до черта времени.
Ух, собака
Решил как самый умный писать ваще-ваще правильно. До того, что все WARNING’и должны бросать исключение.
Решается это достаточно просто с помощью set_error_hanlder.
В один прекрасный момент все ложиться нах и хуй проссышь почему.
Оказывается у меня есть библиотека для работы с БД, где встречаются подобные вещи:
@parent::__construct($host, $username, $passwd, $dbname, $port, $socket); if (mysqli_connect_errno()) { throw new goDBExceptionConnect(mysqli_connect_error(), mysqli_connect_errno()); } |
Я глушу собакой WARINING и корректно обрабатываю ошибку. А вот пыху на собаку оказывается наплевать, он всё равно вываливается в error_handler с генерацией исключения.
var
Немного из JS.
function f() { for (i = 0; i < 10; i++) { // ... } } for (var i = 0; i < 3; i++) { // Выполняется один раз f(); } |
Локальные переменные нужно объявлять через var, иначе они будут ссылаться на локальные переменные из объемлющих контекстов.
Сам всех этому учу, но в первый раз попался, когда не просто нету var, но ещё и функция вызывается в цикле.
Задачка для JS-гурманов :)
function f1(b) { if (b) { function f2(a) { alert(a); return true; } } f2(b); return true; } f1(true); f1(false); |
Почему IE и Opera показывают 1-2, а в FF ошибка?
Ух, накатал… Про первое помню, недавно было ;)
adw0rd, 25.04.2009, 5:46
Ты откуда взялся? :)
vasa_c, 25.04.2009, 11:33
Я бот )
adw0rd, 25.04.2009, 20:53
я аццкий ЖС гурман!
function f1(b)
{
if (b) {
f2 = function (a)
{
alert(a);
return true;
}
}
f2(b);
return true;
}
f1(true);
f1(false);
так надо, ибо в ифе она объявляется как временная функция по ходу. поэтмоу ндо сделатьэту функцию глобальной :)
mbstring. а в чем проблема поменять дефолт? mb_internal_encoding(«UTF-8»);
зрзвгву, 4.06.2009, 13:27
Нет, скорее всего, потому что по высоким стандартам ECMA статическое определение функции недопустимо в ветвлении. Поэтому (function f2(a) {…}) рассматривается FF просто как анонимная функция, которая ничему не присваивается и сразу же уходит в dev/null. «f2» же доступно только в теле функции.
А IE с Оперой кладут на высокие стандарты.
А хотя кто их всех знает. Может и не поэтому :)
vasa_c, 4.06.2009, 16:10
>mbstring. а в чем проблема поменять дефолт? mb_internal_encoding(«UTF-8»);
Либу писал, которую можно использовать в других местах. Нельзя глобальные настройки менять.
vasa_c, 4.06.2009, 16:12
1) Про контексты — полезно, спасибо. Тольк вот include_once может проинклюдиться несколько раз, если мы его из разных ф-ций вызываем? Можно проверить, но лень =). Описал бы результат этого в статье.
2) По поводу «@parent::__construct($host, $username, $passwd, $dbname, $port, $socket);
«:
я тоже так делаю. Так как быть-то?
3) расскажи плизз поподробнее про класс для строк, че умеет делать, сильно ли снижает производительность?
Koc, 6.06.2009, 16:24
>Тольк вот include_once может проинклюдиться несколько раз, если мы его из разных ф-ций вызываем?
Нет, не может.
Говорят может, если прописывать пути к файлу по разному, но я не проверял и это не относится к тому, что она вызывается внутри функции.
vasa_c, 6.06.2009, 20:09
>я тоже так делаю. Так как быть-то?
Пока что пишу с WARNING’ами. Поиск решения отложил до лучших времён.
vasa_c, 6.06.2009, 20:10
>расскажи плизз поподробнее про класс для строк, че умеет делать, сильно ли снижает производительность?
Да ничего особенного, в большинстве своём просто обёртки, дабы избежать случаев подобных вышеописанному:
vasa_c, 6.06.2009, 20:12
Спасибо за статью! Со многим сталкивался, но есть и неизведанное :)
По поводу страниц — можно считать так:
>>> $pageCount = ceil($elementsCount / $pageSize); // Общее количество страниц
и не париться с типами данных :)
kirik, 20.07.2009, 9:36
по поводу set_error_hanlder
в функцию добавить
if (!error_reporting()) return;
Как бы хм :)
>>mbstring. а в чем проблема поменять дефолт? mb_internal_encoding(«UTF-8″);
>Либу писал, которую можно использовать в других местах. Нельзя глобальные настройки менять.
Вообще можно восстанавливать, если уж либу, хотя смысла сейчас особо нету — utf8 уже везде…
Ivan1986, 12.06.2011, 1:49
>if (!error_reporting()) return;
Да, спасибо. Уже догадался с тех пор :)
>utf8 уже везде…
Да везде-то, везде. А потом хренась где-то и внезапно оказывается, что не везде.
vasa_c, 12.06.2011, 9:22