Bug or feature? Числа в php

Опубліковано: 2009-05-31   00:30:57

PHPХочу поділитись двома своїми спостереженнями про роботу з числами в мові php, які змусили мене коли я вперше зіштовхнувся з таким проблемами витратити купу часу та сил на їх подолання. Купу в межах кількості коду та часу, які б я мав витратити у нормальній мові програмування на подолання таких труднощів. Це мені дало ще більше підстав недолюблювати цю мову програмування, та називати її нелогічною. Справа в тому, що тут мова піде про таку здавалось би звичну для всіх річ, як робота з числовими даними, робота з якими мала б бути дуже простою та не викликати жодних проблем. Мала б бути. Однак php і тут підкинув проблему

А що є числом?

Всі добре знають, як добре php може впоратись з приведенням будь-яких чисел до рядку - достатньо лише конкатенувати числову змінну до рядка і жодних проблем. Та й навпаки перетворити рядок на число здавалося б проблем не викликає.

В таких обставинах перевірка чи значення змінної є числом має бути справою п'яти хвилин, тому що є ж функції is_int() та is_float. Про це можна тільки мріяти, окільки ці функції працюють тільки з тими змінними, що були встановлені як числа кодом php без жодних виключень. Тобто, якщо:

1 + "10 Small Pigs";

поверне значення 11, то

is_int("10");

поверне false. Все б нічого, однак всі данні введені користувачем представлені у вигляді рядків, тобто для них is_int() та is_float() не працюють. Частково рятує is_numeric(), яка так враховує можливість того, що рядок може містити число, однак перевірити чи ціле число так неможливо. Тому доводиться писати:

preg_match("/^[\d]+$/", $param); // Лише цілі числа
preg_match("/^([\d]+)(\.([\d]*))?$/", $param) || preg_match("/^([\d]+)(,([\d]*))?$/", $param); // Дійсні числа

Особисто я витратив більше години колись на вирішення проблеми, чому код який виглядає цілком логічно не працює. А проблема була саме в is_int() та is_float(). Хоча з дійсними числами ще далеко не все.

А чи знали ви, що числа прив'язані до локалі?

Зверніть увагу на другий вираз для перевірки даних. Зрозуміло, що на практиці для країн східної Європи той формат чисел, що за замовчуванням використовується наприклад в MySQL не є звичним: ми звикли до такої форми запису десяткових дробів, коли ціла та дрібна частини розділені комою, а в програмах та мовах програмування використовується запис через крапку.

Розумник php має розуміти обидві форми запису з переданих даних. І він здавалось би чудово це робить. Однак вискочила неприємна фішка мови: коли дійсне число конвертується в рядок, то враховується локаль встановлена в php. Коли ми організовуємо виведення даних це просто чудова та корисна функція, бо всі числа будуть в звичному вигляді.

Однак, що буде коли спробувати передати дані в MySQL? Оскільки запит є рядком, то під час збирання цього рядка php конвертує числові дані в неприйнятний для MySQL формат. І не завжди є можливість змінити локаль для MySQL. Наприклад, для багатомовних ресурсів. Тоді знову ж доводиться вигадувати граблі:

$param = (float) preg_replace("/,/", '.', $param);
/* Деякі дії з даними */
preg_replace("/,/", '.', (string)$param);

Таким ось костилем число примусово конвертується в форму характерну для буржуйських локалей (тобто гарантовано буде розпізнане мовою php), потім перетворюється примусово на float, з яким можна працювати, чи в 0 якщо рядок мав не числовий формат. А вже перед додаванням до рядка запиту число необхідно знову конвертувати в рядок, знову ж таки перевівши його в звичний для MySQL формат.

9.10.2009 UPD: Уважніше прочитав документацію з функції sprintf, та знайшов формат %F який дозволяє перевести дійсне число в рядок без урахування локалі.

Чистий та прозорий код мовою php?

З такими перетвореннями про чистоту коду, його прозорість та швидкодію мова йти не може. Не вірю я в те, що в 6ій версії мови всі ці проблеми буде вирішено. Вирішити їх можна на рівні мови? Звісно й доволі просто - додати деякі функції, які б дозволяли конвертувати дані з додатковими налаштуваннями.

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

Коментарі: 0
 

Коментарі:

Додати коментар

user

email

url

text

Повідомляти про новікоментарі