| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > PHP: Общие вопросы > Принципиальные отличия float и intval |
| Автор: capitan 3.11.2009, 12:40 | ||
| Собственно возник такой вопрос в одном из топиков. Дабы не засорять его, выношу обсуждение сюда. Я в своих проекта всегда использую (float) исхожу из того что:
Дает такие результаты: 2147483647 12345678910 В нагруженных проектах есть поле id, которое auto_increment. Есть вероятность, что когда-то мы поймаем такую багу с intval($num) Кто что скажет? |
| Автор: NNaarreekk 3.11.2009, 13:26 |
| capitan, ну ты и оптимист Пока на сайте дойдет до миллиарда записей, то уже наверно в место РНР еще что-нибудь придумают))) А вообще если есть конкретно ошибка при интвал значит его не нужно использовать в этом случае, ИМХО. |
| Автор: Kevin 3.11.2009, 13:27 |
| Вероятность есть, а в PHP единственный тип данных для больших чисел — float. |
| Автор: Ипатьев 3.11.2009, 14:10 |
| может быть, кто-нибудь здесь осилит раздел документации, посвященный типам данных? |
| Автор: sTa1kEr 3.11.2009, 14:20 | ||
Это не бага. http://php.net/int |
| Автор: Simpliest 3.11.2009, 14:28 |
А зачем? И типам данных чего? MySQL? PHP? В теории 2млрд записей хватит на 68 лет при скорости 1 запись в секунду Если мы увеличим скорость до 100к в секунду, то всего около 6 часов. Другой вопрос, что тогда автоинкрементный id скорее всего будет несколько неактуален С флоатом тоже не все так гладко Ну и на закуску.... В теории при переходе на полностью 64 битные системы ваше целое число вырастет Поправка |
| Автор: youri 3.11.2009, 14:53 |
| при использовании prepared statements (mysqli) intval/float не нужны, т.е. id всегда будет храниться в виде строки. Да и для mysql не обязательно, можно просто проверять, что id (пришедший от пользователя) содержит только цифры |
| Автор: sTa1kEr 3.11.2009, 14:56 |
Затем, что там расписано до мелочей все то, что написали вы, плюс еще очень много полезной информации. |
| Автор: youri 3.11.2009, 14:59 |
| кстати, кто-нибудь знает, до каких пор можно рассчитывать, что "целочисленная" строка преобразуется в float без потерь? Я так понимаю до 2**52-1? |
| Автор: Kevin 3.11.2009, 15:06 | ||
Не напомните, что совершенно случайно передается первым аргументом в bind_param()? -- Про БД конечно не совсем это актуально, но, как я понял, топикстартер просто привел неудачный пример, иллюстрируя несколько другую идею. |
| Автор: Simpliest 3.11.2009, 15:08 |
Я же ответил Плясать лучше отсюда http://www.psc.edu/general/software/packages/ieee/ieee.php 2 цифры уйдут на округление. Добавлено через 1 минуту и 7 секунд Kevin, для очень больших чисел всегда есть GMP и BCMath 100 знаков точности - не предел. |
| Автор: Kevin 3.11.2009, 15:21 | ||
К самому PHP они относятся слабо, и не отменяют того, что есть только int и float. А тот же BCMath, в конечном счете, отдает простую строку. P.S.: Вообще, о чем спор? Есть int, есть float, есть разные уловки и библиотеки как преодолеть ограничения, о чем топик? |
| Автор: capitan 3.11.2009, 15:41 | ||
Сразу скажу, я не теоретик, а практик. Просто зашел спор как приводить полученную переменную. Я привожу всегда (float), Ипатьев говорит что нужно использовать intval. Я привел пример, может и не удачный, но исходя из чего я исходил. Можно было конечно привести пример online калькулятора. Вот хочу понять, когда применять intval, а когда float. |
| Автор: bars80080 3.11.2009, 15:53 | ||
для случаев где проверяется число менее 11 знаков - intval, для случаев большего -
100%-вариант |
| Автор: Ипатьев 3.11.2009, 16:06 |
| Насколько я помню, с вещественными числами могут быть проблемы. Когда 1111111111 станет вдруг 1111111110.99999999 Сейчас, правда, воспроизвести их не удалось. Но, на мой взгляд, функцию надо применять по назначению. Если нам нужно целое - мы приводим к целому. Если нужно вещественное - приводим к вещественному. Не наоборот. |
| Автор: sTa1kEr 3.11.2009, 16:13 | ||
capitan, для целых чисел нужно использовать intval, для вещественных floatval, но никак не иначе. При работе с большими целыми числами на 32х существуют соответствующие экстеншены приведенные выше. Для проверки является ли строка числом есть функция http://php.net/is_numeric
|
| Автор: Simpliest 3.11.2009, 16:15 |
| capitan, можешь применять и регулярку. Тогда смело забьешь на число значащих цифр. Вопрос в том, что в твоих стандартных проектах ты не упрешься даже в лимит int. |
| Автор: Simpliest 3.11.2009, 18:04 |
А он у них не цифровой. Там что хоть 65000 знаков. |
| Автор: bars80080 3.11.2009, 18:05 |
да ладно. в моём случае чисто цифровой |
| Автор: Simpliest 3.11.2009, 18:18 |
| bars80080, Я некорректно выразился, но все равно верь мне Счета, номера карт - не являются числами. Да, они обычно состоят из одних цифр - но это строки. И исключительно строки. Добавлено через 1 минуту и 5 секунд GUID, ID транзакции - тоже не числа. |
| Автор: bars80080 3.11.2009, 19:08 | ||
а я не работал в банке, но данные о проведённых платежах приходят в виде чисел. особо говорено, что id платежа - уникальный идентификатор состоящий исключительно из цифр. какая мне разница, как и где оно у них там хранится? я ставлю себе bigint и в ус не дую Simpliest, вот серьёзно, насколько вы лучше меня можете знать приходящий мне формат данных, если я даже не указал о какой системе веду речь? |
| Автор: sTa1kEr 3.11.2009, 19:59 | ||
В каком, простите, месте это стандартно? Но в любом случае - это не корректный способ проверки числа.
В PHP любые данные из-вне поступают в виде строк. |
| Автор: solenko 3.11.2009, 20:15 | ||
Почему? Почему не (int) и (float) соответственно? |
| Автор: youri 3.11.2009, 20:21 |
так это не способ проверки числа вообще, это способ использования переданного id. Только запихнуть нужно куда-нибудь эти манипуляции, в функцию/класс думаю, "стандартно" нужно понимать как "обычно". В mysql primary key + auto_increment не может создать отрицательный id. А что бывает необходимость в отрицательных id? |
| Автор: sTa1kEr 3.11.2009, 20:23 | ||||
Само собой разумеется, что можно использовать (int) и (float). Я лишь имел ввиду то-же самое, что за минуту до меня сказал Ипатьев. Добавлено через 10 минут и 13 секунд
Да, прошу прощенья, изначально речь шла исключительно об ID. Но суть моего сообщения была в том, что таким способом можно получить заведомо не правильный ID, а это в свою очередь может привести к плачевным последствиям.
С таким же успехом можно сказать, что стандартно ID - это строка из 36 символов, т.к. обычно в MSSQL primaty key - это GUID. Да, бывает потребность в совершенно разных ID. |
| Автор: Simpliest 3.11.2009, 21:17 | ||||||
Я же сказал уже И поправился
И плохо. Потому что это 64-битное целое и таким образом ты можешь хранить только 18ти-значные вещи (19я цифра может быть единицей) состоящие исключительно из цифр. Например, у нас счет 14ти-символьный. А у вас в России он уже может быть 20ти-символьным (он дейтствительно 20тизначный, но некоторые банки сокращают внутренний счет на несколько цифр) Номера карт распространенных МПС - 16 символов. Но есть варианты и с 20тью и даже алфавитно-цифровые Чтобы понять что счет это не число - можешь прочитать хотя бы его определение у вас http://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D0%BA%D1%83%D1%89%D0%B8%D0%B9_%D1%81%D1%87%D1%91%D1%82
Речь идет о том, что UID,ID, GUID, счета, номера карточек, серийные номера и т.д. и т.п. - не являются числами хотя и могут состоять исключительно из цифр. Поэтому хранить ты можешь как угодно, но не забывать чем они являются на самом деле. В случае с MySQL вас всех вводит в заблуждение автоинкрементное целочисленное поле в качестве sequence. В более взрослых базах это может быть вообще не число (Oracle, Interbase/Firebird, DB2) |
| Автор: bars80080 4.11.2009, 00:39 | ||||||||||||
у вас id бывают отрицательные? ну, это уже зависит от задачи. я думал, что речь идёт от прошлой темы, где проверялся идентификатор. там цель была не в числе, а именно в корректном идентификаторе.
не понял. каким образом из этого:
может получиться не корректный id?
я сейчас посмотрел, они у меня 15-значные
читать не буду, повторюсь только третий раз: я говорю не о счетах, а об идентификаторах операций. это не сертифицированная каким-то ведомством величина, это всего лишь порядковый номер принятый внутри организации для сохранения единого реестра. да они могли сделать его буквенным, но они сами себе прописали формат, что он - число. и опубликовали формат для всех партнёров, чтобы мы могли с ними сотрудничать. всё
легко может быть. я отдаю этой же системе свои идентификаторы в виде БЦБЦЦЦЦ-ЦЦ, потому что мне так удобно, и это вписывается в их формат данных но это специфичный формат, и я его парсю соответствующим образом, вытаскивая из него систему оборота, идентификатор заказа и номер операции по ней но мы говорим о частной ситуации, вытащенной из другой темы. и я её в очередной раз решаю инженерным способом, т.е. частно. что, видимо, не приветствуется в программерской среде. почему-то вам всегда нужны универсальные алгоритмы. вот скажи, можно ли придумать универсальный метод проверки на корректность для входящего идентификатора - состоящего из одних цифр и для идентификатора - БЦБЦЦЦЦ-ЦЦ? |
| Автор: Nigel 4.11.2009, 01:25 |
| Собственно, зачем используется такая конструкция (int)$value? Посмотрите 1-й пост, ТС использует этот как фильтр в своих запросах. А нужно ли это? Все нормальные либы используют биндинг для добавления переменных в запрос. Многие утверждают, что данные должны поступать в бд в неизменном виде, сами при этом нарушая свой принцип подобными конструкциями. ТС аргументировал такое поведение нагруженными проектами. Интересно узнать, какие проекты он считает нагруженными?;) На нормальные сервера ставят 64бита, и не изза того, что вы можете выйти за диапазон значений, а просто тупо потому, чтобы обеспечить нормальную работу с большими объемами памяти. В этом случае никаких проблем начальная конструкция не вызовет. А вот используя float, проблемы как раз получить можно. Это и точка(запятая), связанная с локализацией, и представление числа в виде строки, и выполнение арифметических операций, в результате чего будете получать совсем не то, что ожидаете. К тому же есть люди, которые используют везде (float), а при этом тип столбца у них в БД какой-нить smallint. А еще забавно, когда пишут абстрактный слой для бд, при этом сами запросы в никакой другой бд работать не будут, кроме mysql. Ради чего усилия тогда, спрашивается? Кто-то говорит "Я везде использую bigint. Я от всего застрахован". Может тогда для строк заюзать везде longtext? Чем больше диапазон, тем больше требуется памяти для хранения. А нужно ли это? Может быть, не стоит создавать дополнительных проблем? Может быть, все на самом деле проще... |
| Автор: youri 4.11.2009, 03:16 | ||||||||
я считаю, что bars80080 выбрал неподходящее слово. Более подходящее слово - обычно
не забывая про диапазон значений в этих строках
holy war detected! |
| Автор: Simpliest 4.11.2009, 06:55 | ||||
Решай наздоровье. Это правильно и разумно. А когда для борьбы с сферическими багами intval начинают использовать float, не учитывая при этом с чем работают - это не правильно.
Придумать можно что угодно. Но это не нужно (int)$id - вполне разумное применение, когда у тебя ID - это INT в MySQL и в топку всякие float Когда у тебя ID это BIGINT и 32-битная система, то твоя регулярка вполне подходящее решение. Делать везде BIGINT вместо INT - это не совсем разумно. С чем ты пытаешься спорить? |
| Автор: bars80080 4.11.2009, 11:41 |
да вроде не я пытаюсь спорить я сказал, что для заявленного случая (когда id числовое, что верно в большинстве случаев) регуляркой снимаются все ограничения на intval и не допускаются подобные ляпсусы как -5 или 0х55 от is_numeric и иже с ним. мне тут заявили, что это не 100% вариант (если речь велась, что не 100%, потому что id бывает и буквенный, то согласен. как-то не втыкнулся сразу) |
| Автор: youri 4.11.2009, 11:55 | ||
а какая разница, что прокатит -5 или 0х55? Это ж в основном защита от SQL Injection, или я не прав? Или есть другие причины превращать id в число? |
| Автор: bars80080 4.11.2009, 12:03 | ||
ну, тут уж я особо не размышлял, предпочитаю иметь в руках что-то конкретное допустим такая ситуация: попадается мне 0х4, ищу в базе where id=0x4 , при наличии id=4, что он вернёт? |
| Автор: sTa1kEr 4.11.2009, 18:10 | ||
Да, бывают. Пример каким образом можно получить не корректный ID, а в последствии логическую ошибку, я указал выше. И если вам так нравятся пользоваться кривыми велосипедами, вместо проверенный штатных задокументированных способов, то пожалуйста, это ваше дело. Главное не подавать плохие примеры другим пользователям.
А вы сами как думаете? Затем, что в PHP нету типизации переменных, по этому, что бы быть уверенным, что в переменной находится int необходимы подобные конструкции. |
| Автор: bars80080 5.11.2009, 11:02 | ||
даже не знаю, что сказать. прошу прощения заранее, но неужели отрицательный id - это хороший пример? так, у меня сейчас появился пхп и я проверил. мда, в целом при сохранении формата в дальнейшем он работает как часы. то есть на where id=0x26, он выдаст строку с id=38, и если вставить строку с тем же 0x26, то она станет id=38 но это всё при условии, что нигде число не будет порубано на предмет вредных символов |
| Автор: Nigel 5.11.2009, 12:33 | ||
sTa1kEr, ты так ничего и не понял из того, что я выше написал. Для защиты от sql-inj это вовсе не обязательно. |
| Автор: sTa1kEr 5.11.2009, 12:33 | ||||||
С учетом того, что в PHP нету ни long'ов, ни unsigned integer, иногда приходится так поступать. А иногда приходится работать с данными из внешних источников, использующих такие ID.
Именно Добавлено через 4 минуты и 21 секунду
Я ни слова не сказал про sql инъекции. Я говорил про типы переменных, не смотря на то, что в PHP нету строгой типизации, он все же, разумеется, различает типы переменных. И единственный корректный способ привести строку к типу integer - это использовать intval (или аналоги в вроде (integer), (int) ). |
| Автор: youri 5.11.2009, 16:02 | ||
Nigel пришел к нам со знанием какие либы есть "нормальные" (: Кстати, то, что ты говорил, прозвучало в http://forum.vingrad.ru/index.php?showtopic=278776&view=findpost&p=2012534 |
| Автор: Nigel 5.11.2009, 16:52 | ||
Я вкурсе про типы данных в php. Перечитай первый пост топика. |