cloud-castle / unit-convertor
Конвертер единиц измерения для PHP 8.1+: 99 категорий и 577 единиц (СИ, имперские, США, морские, астрономические, исторические русские), размерностный анализ величин, температурные шкалы и дельты, составные величины (5 ft 3 in), SI/IEC-префиксы, произвольная точность на cloud-castle/match, внешние с
Requires
- php: >=8.1
- cloud-castle/match: ^1.18
Requires (Dev)
- cartalyst/converter: ^8.0
- crisu83/php-conversion: ^0.5.2
- deptrac/deptrac: ^3.0 || ^4.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanhazstring/composer-unused: ^0.9
- infection/infection: ^0.29 || ^0.33
- jordanbrauer/unit-converter: ^0.9.0
- nmarfurt/measurements: ^1.4
- php-parallel-lint/php-parallel-lint: ^1.4
- php-units-of-measure/php-units-of-measure: ^2.2
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- vimeo/psalm: ^6.0
- webmozart/assert: ^1.11
Suggests
- ext-intl: Запись величин прописью: Formatter::spellout()
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-05 05:43:13 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle UnitConvertor
Конвертер единиц измерения для PHP 8.1+: 99 категорий и 577 единиц (СИ, имперские, США, морские, астрономические, исторические русские), размерностный анализ величин (10 м / 2 с = 5 м/с), физически корректные температуры (8 шкал + дельты Δ°C), составные величины («5 ft 3 in»), динамические SI/IEC-префиксы (кветто…кветта, KiB…YiB), произвольная точность на
cloud-castle/match, внешние справочники единиц, локализация на 6 языков с плюрализацией, парсинг и форматирование. Единственная runtime-зависимость —cloud-castle/match.
Установка
composer require cloud-castle/unit-convertor
Требуется PHP 8.1+ (проверено вплоть до 8.5).
Быстрый старт
<?php
use CloudCastle\UnitConvertor\Converter;
use CloudCastle\UnitConvertor\Quantity;
$converter = new Converter();
// Простая конверсия — 0.2 мкс на операцию после прогрева пары
$converter->convert(5, 'km', 'mi'); // 3.10685596…
$converter->convert(100, 'celsius', 'fahrenheit'); // 212.0
$converter->convert(8, 'L/100km', 'mpg_us'); // 29.4018… (нелинейная)
$converter->convert(1, 'GiB', 'MB'); // 1073.741824 (IEC ↔ СИ)
$converter->convert(1, 'кВтч', 'Дж'); // русские алиасы работают
// Величины-объекты: иммутабельные, с арифметикой и размерностным анализом
$speed = Quantity::of(100, 'km')->div(Quantity::of(2, 'h'));
$speed->code(); // 'm/s'
$speed->to('km/h')->value(); // 50.0
// Физически корректные температуры
Quantity::of(30, 'celsius')->sub(Quantity::of(20, 'celsius')); // 10 Δ°C
Quantity::of(20, 'celsius')->add(Quantity::of(18, 'delta_fahrenheit')); // 30 °C
// Quantity::of(30, 'celsius')->add(Quantity::of(20, 'celsius')); — исключение!
// Парсинг, разложение, форматирование
Quantity::parse('5 ft 3 in')->to('cm')->value(); // 160.02
Quantity::of(5025, 's')->toCompound(['h', 'min', 's']); // 1 ч 23 мин 45 с
Quantity::of(1500, 'm')->humanize(); // «1,5 км»
Quantity::of(5, 'km')->format(1, 'ru', long: true); // «5 километров»
// Произвольная точность (BCMath через cloud-castle/match)
$converter->convertPrecise('1', 'ly', 'km'); // '9460730472580.8' — точно
Возможности
- 99 категорий, 577 единиц из коробки — от длины и массы до дозиметрии (мкЗв/ч, пКи/л), молярных концентраций (°dH жёсткости воды), темпа бега (мин/км), газовых отметок духовки и русских исторических мер (пуд, аршин, верста). Полный список — в wiki.
- Размерностный анализ: умножение и деление величин выводит размерность результата; произведение силы на длину само становится джоулями, а неизвестные размерности синтезируются на лету.
- Физическая корректность температур: 8 шкал (включая Реомюра, Делиля, Рёмера), дельта-единицы, запрет бессмысленных операций.
- Динамические префиксы: любые СИ-приставки от кветто (10⁻³⁰) до кветта (10³⁰) и IEC-приставки KiB…YiB — без раздувания данных, с точными строковыми множителями.
- Внешние справочники: свой каталог данных,
attachSource()поверх встроенного, программные категорииregisterCategory()— с генератором индексовIndexBuilderи защитой от перехвата чужих кодов. - Локализация: символы и имена единиц на 6 языках с корректной плюрализацией («5,5 километра», «2 kilometres», «1,5 kilomètre»).
- Произвольная точность:
convertPrecise()наBigDecimalизcloud-castle/match— 100 знаков после запятой. - Скорость: pair-кэш сводит линейную конверсию к одному умножению и сложению — ~0.2 мкс на операцию.
Сравнение с аналогами
Все таблицы ниже сгенерированы автоматически стендом benchmarks/ (compare.php → analysis.php → generate.php): каждый пакет установлен изолированно в var/analogs/<пакет> — включая сам cloud-castle/unit-convertor в установке без dev-зависимостей — и измерен в отдельном процессе без Xdebug (замеры — PHP 8.3.35, анализ — PHP 8.3.35). Жирным выделено лучшее значение строки.
Сводка по этапам
Сколько строк каждого раздела выиграл пакет (ничьи не засчитываются).
| Этап | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Функциональность | 3 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| Правильность | 4 | 3 | 1 | 0 | 1 | 1 | unit-convertor |
| phplint | 1 | 1 | 0 | 0 | 0 | 0 | unit-convertor, jordanbrauer |
| Psalm | 4 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| PHPStan | 4 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| PHPMD | 2 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| PHPCS | 3 | 1 | 0 | 0 | 0 | 0 | unit-convertor |
| Rector | 3 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| Deptrac | 1 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| Мутационное тестирование | 2 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| Безопасность | 16 | 1 | 5 | 4 | 4 | 2 | unit-convertor |
| Потребление памяти | 2 | 0 | 11 | 10 | 0 | 12 | measurements |
| Утечки памяти | 12 | 0 | 10 | 9 | 2 | 10 | unit-convertor |
| Производительность | 13 | 0 | 0 | 1 | 0 | 0 | unit-convertor |
| Качество | 5 | 1 | 1 | 0 | 1 | 0 | unit-convertor |
| Всего | 75 | 7 | 28 | 24 | 8 | 25 | unit-convertor |
1. Функциональность
Возможности сняты исполняемыми пробами (benchmarks/capabilities.php): каждая проба вызывает API пакета и проверяет правильность ответа — «есть метод» не засчитывается, неверный результат тоже. Таблица перечисляет объединение возможностей всех пакетов; интеграции с фреймворками (Laravel у cartalyst) не сравниваются.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Возможностей всего | 69 | 23 | 27 | 18 | 10 | 28 | unit-convertor |
| Уникальных (нет ни у одного другого пакета) | 19 | 0 | 0 | 0 | 0 | 0 | unit-convertor |
| Покрыто возможностей остальных пакетов | 100,0 % | 33,3 % | 39,1 % | 26,1 % | 14,5 % | 40,6 % | unit-convertor |
Полная матрица: все возможности всех пакетов
| Возможность | **unit-convertor** | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель | |---|:---:|:---:|:---:|:---:|:---:|:---:|---| | Сложение и вычитание величин (`add_sub`) | **✅** | ❌ | **✅** | **✅** | ❌ | **✅** | unit-convertor, php-units-of-measure, crisu83, measurements | | Защита от бессмысленной арифметики абсолютных шкал (`affine_guard`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Агрегаты: сумма, среднее, минимум, максимум (`aggregates`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Произвольная точность (BCMath) (`arbitrary_precision`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Автовыбор удобной единицы (`auto_unit`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Пакетная и ленивая конверсия (`batch_conversion`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Проверка возможности конверсии (`can_convert`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Категория: ускорение (`cat_acceleration`) | **✅** | ❌ | **✅** | **✅** | ❌ | ❌ | unit-convertor, php-units-of-measure, crisu83 | | Категория: количество вещества (`cat_amount`) | **✅** | ❌ | **✅** | ❌ | ❌ | ❌ | unit-convertor, php-units-of-measure | | Категория: угол (`cat_angle`) | **✅** | **✅** | **✅** | **✅** | ❌ | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, crisu83, measurements | | Категория: полная мощность (В·А) (`cat_apparent_power`) | **✅** | ❌ | ❌ | **✅** | ❌ | ❌ | unit-convertor, crisu83 | | Категория: площадь (`cat_area`) | **✅** | **✅** | **✅** | ❌ | **✅** | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, cartalyst, measurements | | Категория: электрический заряд (`cat_charge`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Категория: валюты по курсам (`cat_currency`) | **✅** | ❌ | ❌ | ❌ | **✅** | ❌ | unit-convertor, cartalyst | | Категория: объём данных (`cat_data`) | **✅** | **✅** | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer | | Категория: сила тока (`cat_electric_current`) | **✅** | ❌ | **✅** | **✅** | ❌ | **✅** | unit-convertor, php-units-of-measure, crisu83, measurements | | Категория: энергия (`cat_energy`) | **✅** | **✅** | **✅** | **✅** | ❌ | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, crisu83, measurements | | Категория: частота (`cat_frequency`) | **✅** | **✅** | ❌ | **✅** | ❌ | **✅** | unit-convertor, jordanbrauer, crisu83, measurements | | Категория: расход топлива (обратная шкала) (`cat_fuel_economy`) | **✅** | **✅** | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer | | Категория: размеры головных уборов (`cat_hat_size`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Категория: освещённость (`cat_illuminance`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Категория: длина (`cat_length`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ничья | | Категория: сила света (`cat_luminous_intensity`) | **✅** | ❌ | **✅** | **✅** | ❌ | ❌ | unit-convertor, php-units-of-measure, crisu83 | | Категория: масса (`cat_mass`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ничья | | Категория: массовая концентрация (`cat_mass_concentration`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Категория: мощность (`cat_power`) | **✅** | ❌ | **✅** | **✅** | ❌ | **✅** | unit-convertor, php-units-of-measure, crisu83, measurements | | Категория: давление (`cat_pressure`) | **✅** | **✅** | **✅** | **✅** | ❌ | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, crisu83, measurements | | Категория: радиоактивность (`cat_radioactivity`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Категория: сопротивление (`cat_resistance`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Категория: размеры обуви (`cat_shoe_size`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Категория: телесный угол (`cat_solid_angle`) | **✅** | ❌ | **✅** | ❌ | ❌ | ❌ | unit-convertor, php-units-of-measure | | Категория: скорость (`cat_speed`) | **✅** | **✅** | **✅** | **✅** | ❌ | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, crisu83, measurements | | Категория: температура (аффинные шкалы) (`cat_temperature`) | **✅** | **✅** | **✅** | ❌ | **✅** | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, cartalyst, measurements | | Категория: время (`cat_time`) | **✅** | **✅** | **✅** | **✅** | ❌ | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, crisu83, measurements | | Категория: напряжение (`cat_voltage`) | **✅** | ❌ | ❌ | **✅** | ❌ | **✅** | unit-convertor, crisu83, measurements | | Категория: объём (`cat_volume`) | **✅** | **✅** | **✅** | **✅** | ❌ | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, crisu83, measurements | | Сравнение величин (`compare`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Журнал конверсий (`conversion_log`) | **✅** | **✅** | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer | | Конверсия во все единицы категории (`convert_to_all`) | **✅** | **✅** | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer | | Регистрация своей категории (`custom_category`) | **✅** | **✅** | ❌ | ❌ | **✅** | ❌ | unit-convertor, jordanbrauer, cartalyst | | Регистрация своей единицы (`custom_unit`) | **✅** | **✅** | **✅** | ❌ | **✅** | **✅** | unit-convertor, jordanbrauer, php-units-of-measure, cartalyst, measurements | | Температурные дельты (Δ°C) (`delta_temperature`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Размерностный анализ (м / с = м/с) (`dimensional_analysis`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Динамические СИ-префиксы (любая единица + префикс) (`dynamic_si_prefixes`) | **✅** | ❌ | **✅** | ❌ | ❌ | ❌ | unit-convertor, php-units-of-measure | | Равенство в разных единицах (`equality_across_units`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Внешние каталоги единиц (`external_catalogs`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Исторические единицы (`historical_units`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Двоичные IEC-префиксы (KiB, MiB…) (`iec_prefixes`) | **✅** | **✅** | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer | | Неизменяемые величины (`immutable`) | **✅** | ❌ | **✅** | ❌ | ❌ | **✅** | unit-convertor, php-units-of-measure, measurements | | Проверка, известна ли единица (`is_defined`) | **✅** | **✅** | **✅** | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer, php-units-of-measure | | JSON-сериализация и восстановление (`json_serialization`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Список категорий (`list_categories`) | **✅** | **✅** | ❌ | ❌ | **✅** | ❌ | unit-convertor, jordanbrauer, cartalyst | | Список единиц категории (`list_units`) | **✅** | **✅** | **✅** | ❌ | **✅** | ❌ | unit-convertor, jordanbrauer, php-units-of-measure, cartalyst | | Локализованные названия (6 языков) (`localized_names`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Разбор составной строки «5 ft 3 in» (`parse_compound`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Разбор строки «5.5 km» (`parse_string`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Форматирование по шаблону (`pattern_format`) | **✅** | ❌ | ❌ | **✅** | **✅** | ❌ | unit-convertor, crisu83, cartalyst | | Точные float-результаты без накопления ошибки (`precise_floats`) | **✅** | ❌ | **✅** | ❌ | ❌ | ❌ | unit-convertor, php-units-of-measure | | Округление результата (`rounding`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Проверка совпадения размерностей (`same_dimension`) | **✅** | ❌ | **✅** | ❌ | ❌ | ❌ | unit-convertor, php-units-of-measure | | Умножение и деление на число (`scale_by_number`) | **✅** | ❌ | ❌ | ❌ | ❌ | **✅** | unit-convertor, measurements | | Признак единицы СИ (`si_flag`) | **✅** | **✅** | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer | | Значение прописью (`spellout`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Перевод в базовую единицу (`to_base_unit`) | **✅** | ❌ | **✅** | ❌ | ❌ | **✅** | unit-convertor, php-units-of-measure, measurements | | Разложение в составную величину (`to_compound`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Строковое представление (`to_string`) | **✅** | ❌ | **✅** | **✅** | ❌ | **✅** | unit-convertor, php-units-of-measure, crisu83, measurements | | Подсказки при опечатке в единице (`typo_suggestions`) | **✅** | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor | | Алиасы единиц (`unit_aliases`) | **✅** | ❌ | **✅** | ❌ | ❌ | ❌ | unit-convertor, php-units-of-measure | | Удаление единицы из реестра (`unregister_unit`) | **✅** | **✅** | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer |2. Правильность
Ответ каждой операции на эталонном входе сверен с эталоном (benchmarks/operations.php, относительная погрешность 1e-5). ❌ — пакет ответил неверно или упал: такой пакет не участвует в замерах этой операции. Прочерк — операции нет.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
length_m_cm | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ничья |
mass_kg_lb | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
temp_c_f | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | unit-convertor, jordanbrauer, php-units-of-measure, cartalyst, measurements |
speed_kmh_ms | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
area_m2_ft2 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
volume_l_gal | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
data_gb_mb | ✅ | ✅ | — | ❌ | — | — | unit-convertor, jordanbrauer |
energy_kwh_j | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
pressure_bar_psi | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
time_h_s | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
angle_deg_rad | ✅ | ✅ | ✅ | ✅ | — | ✅ | ничья |
fuel_l100_mpg | ✅ | ✅ | — | ❌ | — | ❌ | unit-convertor, jordanbrauer |
add_km_m | ✅ | — | ✅ | ✅ | — | ✅ | ничья |
compare_km_m | ✅ | — | — | — | — | ✅ | ничья |
| Верных ответов | 14 | 12 | 11 | 10 | 2 | 12 | unit-convertor |
3. phplint
Синтаксис исходников (php-parallel-lint) и доля файлов со строгой типизацией.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Находок | 0 | 0 | 0 | 0 | 0 | 0 | ничья |
Файлов с declare(strict_types=1) | 100,0 % | 100,0 % | 0,0 % | 0,0 % | 0,0 % | 0,0 % | unit-convertor, jordanbrauer |
4. Psalm
Psalm с настройками гейта пакета (errorLevel 1, строгие бинарные операнды) по исходникам каждого пакета на его минимальной версии PHP; поиск неиспользуемого кода отключён для всех, так как тесты аналогов не входят в дистрибутив.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Находок | 0 | 1 188 | 214 | 55 | 83 | 673 | unit-convertor |
| Находок на 1000 строк кода | 0,00 | 125,71 | 120,90 | 34,68 | 105,20 | 174,76 | unit-convertor |
| errorLevel Psalm в репозитории (1 — строже всего) | 1 | — | — | — | — | — | unit-convertor |
| Подавленных ошибок в baseline | 0 | — | — | — | — | — | unit-convertor |
5. PHPStan
PHPStan уровня max с настройками гейта пакета по исходникам каждого пакета на его минимальной версии PHP.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Находок | 0 | 256 | 141 | 40 | 52 | 401 | unit-convertor |
| Находок на 1000 строк кода | 0,00 | 27,09 | 79,66 | 25,22 | 65,91 | 104,13 | unit-convertor |
| Уровень PHPStan в репозитории | max | — | — | — | — | — | unit-convertor |
| Подавленных ошибок в baseline | 0 | — | — | — | — | — | unit-convertor |
6. PHPMD
PHPMD с набором правил гейта пакета (phpmd.xml).
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Находок | 0 | 5 | 14 | 4 | 2 | 11 | unit-convertor |
| Находок на 1000 строк кода | 0,00 | 0,53 | 7,91 | 2,52 | 2,53 | 2,86 | unit-convertor |
7. PHPCS
PHPCS со стандартом гейта пакета (phpcs.xml.dist).
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Находок | 0 | 859 | 56 | 259 | 4 | 3 783 | unit-convertor |
| Находок на 1000 строк кода | 0,00 | 90,90 | 31,64 | 163,30 | 5,07 | 982,34 | unit-convertor |
| Конфигурация стиля кода в репозитории | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer |
8. Rector
Rector с наборами гейта пакета (PHP 8.1, dead code, code quality, type declarations): файлов, которые он изменил бы.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Находок | 0 | 23 | 11 | 49 | 7 | 37 | unit-convertor |
| Находок на 1000 строк кода | 0,00 | 2,43 | 6,21 | 30,90 | 8,87 | 9,61 | unit-convertor |
| Rector в репозитории | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
9. Deptrac
Правила архитектурных слоёв зависят от проекта, поэтому сравнивается наличие контроля слоёв.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Правила архитектурных слоёв (Deptrac) в репозитории | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
10. Мутационное тестирование
MSI измерен прогоном Infection у собственного пакета; у аналогов — наличие мутационного тестирования.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Infection в репозитории | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
| MSI | 100,00 % | — | — | — | — | — | unit-convertor |
11. Безопасность
Пробы безопасности исполняются вызовом API каждого пакета (benchmarks/capabilities.php); вызовы и @ подсчитаны по токенам PHP в исходниках (методы и комментарии не учитываются), уязвимости — composer audit по установке пакета. Прочерк — проба неприменима (у пакета нет разбора строк или файлов локалей).
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| NAN на входе отклоняется исключением | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
| INF на входе отклоняется исключением | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
| Неизвестная единица — типизированное исключение пакета | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | unit-convertor, php-units-of-measure, crisu83, cartalyst |
Код локали не выходит за каталог данных (../) | ✅ | — | — | — | — | — | unit-convertor |
| Длина разбираемой строки ограничена | ✅ | — | — | — | — | — | unit-convertor |
Опасных вызовов (eval, unserialize, exec, system…) | 0 | 1 | 0 | 0 | 0 | 0 | unit-convertor, php-units-of-measure, crisu83, cartalyst, measurements |
Подавлений ошибок оператором @ | 0 | 0 | 0 | 0 | 0 | 0 | ничья |
Известных уязвимостей в дереве зависимостей (composer audit) | 0 | 0 | 0 | 0 | 0 | 0 | ничья |
| Заброшенных пакетов в дереве зависимостей | 0 | 0 | 0 | 0 | 0 | 0 | ничья |
Соответствие стандартам безопасности
Каждая отметка выведена из проб и измерений выше и из клона репозитория, а не заполнена вручную. Прочерк — требование к пакету неприменимо (например, у пакета нет разбора строк или файлов локалей).
| Стандарт / требование | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| CWE-20: проверка входа — NAN и INF отклоняются | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
| CWE-755: ошибки ввода — типизированные исключения, а не PHP-ошибки | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | unit-convertor, php-units-of-measure, crisu83, cartalyst |
| CWE-22: нет обхода каталогов через код локали | ✅ | — | — | — | — | — | unit-convertor |
| CWE-400: ограничение ресурсов — лимит длины входной строки | ✅ | — | — | — | — | — | unit-convertor |
| CWE-95 / CWE-502 / CWE-78: нет eval, unserialize, запуска команд | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | unit-convertor, php-units-of-measure, crisu83, cartalyst, measurements |
CWE-391: ошибки не подавляются оператором @ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ничья |
| CWE-1339: доступна произвольная точность вещественных чисел | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
| OWASP Top 10 A06:2021: нет уязвимых и заброшенных компонентов | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ничья |
| OpenSSF Scorecard «Security-Policy»: есть SECURITY.md | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | unit-convertor, jordanbrauer |
| OpenSSF Scorecard «Maintained»: коммиты за последние 90 дней | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | unit-convertor, php-units-of-measure |
| OpenSSF Scorecard «CI-Tests»: тесты в CI | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ничья |
| OpenSSF Scorecard «SAST»: статический анализ в репозитории | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
| OpenSSF Scorecard «Dependency-Update-Tool»: Dependabot/Renovate | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | unit-convertor |
| OpenSSF Scorecard «License»: лицензия в репозитории | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ничья |
12. Потребление памяти
Память самой библиотеки, КБ: прирост пика от точки до подключения автозагрузчика до конца 20 000 вызовов операции. Прочерк — у пакета нет такой возможности или ответ неверен.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
length_m_cm | 514,6 | 15 883,9 | 207,1 | 207,1 | 483,3 | 207,1 | php-units-of-measure, crisu83, measurements |
mass_kg_lb | 514,6 | 15 884,4 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
temp_c_f | 514,6 | 15 885,4 | 207,1 | — | 483,3 | 207,1 | php-units-of-measure, measurements |
speed_kmh_ms | 514,6 | 15 885,0 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
area_m2_ft2 | 514,6 | 15 885,1 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
volume_l_gal | 514,6 | 15 887,8 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
data_gb_mb | 514,6 | 15 884,5 | — | — | — | — | unit-convertor |
energy_kwh_j | 514,6 | 15 886,1 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
pressure_bar_psi | 514,6 | 15 884,9 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
time_h_s | 514,6 | 15 885,8 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
angle_deg_rad | 514,6 | 15 885,1 | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
fuel_l100_mpg | 514,6 | 15 885,0 | — | — | — | — | unit-convertor |
add_km_m | 514,6 | — | 207,1 | 207,1 | — | 207,1 | php-units-of-measure, crisu83, measurements |
compare_km_m | 514,6 | — | — | — | — | 207,1 | measurements |
13. Утечки памяти
Рост удерживаемой памяти после прогрева на 50 000 вызовов, байт (0 — утечек нет).
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
length_m_cm | 0 | 38 196 736 | 0 | 0 | 0 | 0 | unit-convertor, php-units-of-measure, crisu83, cartalyst, measurements |
mass_kg_lb | 0 | 38 194 864 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
temp_c_f | 0 | 38 196 744 | 0 | — | 0 | 0 | unit-convertor, php-units-of-measure, cartalyst, measurements |
speed_kmh_ms | 0 | 38 195 856 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
area_m2_ft2 | 0 | 38 197 904 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
volume_l_gal | 0 | 38 200 128 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
data_gb_mb | 0 | 38 197 080 | — | — | — | — | unit-convertor |
energy_kwh_j | 0 | 38 196 864 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
pressure_bar_psi | 0 | 38 198 552 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
time_h_s | 0 | 38 195 992 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
angle_deg_rad | 0 | 38 200 504 | 0 | 0 | — | 0 | unit-convertor, php-units-of-measure, crisu83, measurements |
fuel_l100_mpg | 0 | 38 197 952 | — | — | — | — | unit-convertor |
add_km_m | 0 | — | 0 | 0 | — | 0 | ничья |
compare_km_m | 0 | — | — | — | — | 0 | ничья |
14. Производительность
Время серии из 20 000 вызовов, мс (лучшее из 5 серий). Прочерк — у пакета нет такой возможности или ответ неверен. Разница меньше 3 % лежит в пределах разброса повторных замеров: такие пакеты делят победу.
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
length_m_cm | 4,42 | 95,26 | 16,62 | 8,17 | 71,59 | 18,04 | unit-convertor |
mass_kg_lb | 4,31 | 110,15 | 15,88 | 8,31 | — | 18,00 | unit-convertor |
temp_c_f | 4,36 | 121,04 | 16,12 | — | 69,37 | 17,77 | unit-convertor |
speed_kmh_ms | 4,42 | 117,01 | 15,80 | 7,89 | — | 16,69 | unit-convertor |
area_m2_ft2 | 4,43 | 102,00 | 16,07 | 7,93 | — | 18,30 | unit-convertor |
volume_l_gal | 4,49 | 106,70 | 16,11 | 7,92 | — | 18,20 | unit-convertor |
data_gb_mb | 4,40 | 150,33 | — | — | — | — | unit-convertor |
energy_kwh_j | 4,31 | 138,20 | 16,07 | 7,89 | — | 16,51 | unit-convertor |
pressure_bar_psi | 4,22 | 132,15 | 16,24 | 8,43 | — | 18,59 | unit-convertor |
time_h_s | 4,27 | 135,41 | 16,08 | 8,41 | — | 16,90 | unit-convertor |
angle_deg_rad | 4,38 | 121,96 | 16,44 | 8,22 | — | 18,89 | unit-convertor |
fuel_l100_mpg | 7,28 | 153,39 | — | — | — | — | unit-convertor |
add_km_m | 46,90 | — | 40,29 | 12,40 | — | 36,95 | crisu83 |
compare_km_m | 28,09 | — | — | — | — | 49,31 | unit-convertor |
15. Качество
Практики сняты с клона исходного репозитория каждого пакета; покрытие измерено только у собственного пакета (у аналогов прочерк — не измерялось).
| Метрика | unit-convertor | jordanbrauer | php-units-of-measure | crisu83 | cartalyst | measurements | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Файлов тестов | 28 | 0 | 18 | 5 | 1 | 0 | unit-convertor |
| Покрытие тестами (строки и методы) | 100,00 % | — | — | — | — | — | unit-convertor |
| Конвейеров CI | 3 | 1 | 1 | 1 | 1 | 2 | unit-convertor |
| Журнал изменений | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | unit-convertor, jordanbrauer, php-units-of-measure, cartalyst |
| Последний коммит | 2026-10-01 | 2023-08-23 | 2026-09-26 | 2016-05-18 | 2025-02-28 | 2022-02-11 | unit-convertor |
Воспроизвести: php benchmarks/install.php && php benchmarks/compare.php && php benchmarks/analysis.php && php benchmarks/generate.php.
Честно о плюсах и минусах
Плюсы:
- функциональный суперсет всех сравниваемых аналогов вместе взятых (см. таблицу выше: единственный со строковым парсингом, размерностным анализом, дельта-температурами, локализацией и внешними справочниками);
- самая быстрая конверсия среди аналогов — в 1.8–35 раз быстрее в каждой измеренной паре единиц, сравнение величин — в 1.7 раза быстрее;
- отклоняет
NAN/INFна входе и переполнение в арифметике величин; ни один из аналоговNAN/INFне отклоняет (см. таблицу безопасности); - 100 % покрытие строк и 100 % MSI мутационного тестирования; PHPStan max + strict, Psalm level 1, Deptrac-слои;
- физическая корректность там, где аналоги молча считают неверно (линейные «температуры» crisu83, отсутствие offset у cartalyst).
Минусы:
- пакет моложе и менее распространён, чем аналоги (меньше звёзд, установок и практики сообщества);
- рабочий footprint (~515 КБ против ~207 КБ у лёгких аналогов) — цена 99 категорий, полного индекса кодов и pair-кэша; если нужна пара конверсий длины в микросервисе с жёстким лимитом памяти, легковес может подойти лучше;
- сложение величин (
add_km_m) медленнее, чем у crisu83, measurements и php-units-of-measure:Quantityиммутабелен и на каждую операцию создаёт новый объект с проверкой совместимости и аффинных шкал, тогда как crisu83 мутирует один объект. Иммутабельность и запрет некорректной арифметики температур — сознательный выбор в пользу корректности; - режим произвольной точности тянет
cloud-castle/match(ext-bcmath).
Когда и где применять
- E-commerce, логистика, доставка — габариты и вес в разных системах, «5 ft 3 in» из американских карточек товара, локализованный вывод.
- IoT и телеметрия — датчики в смешанных единицах, температурные дельты без физических ошибок, mkЗв/ч и Бк/м³ для радиометрии.
- Финтех и биллинг ресурсов —
convertPrecise()для тарификации энергии (кВт·ч ↔ Дж) без накопления float-погрешности. - Медицина и лаборатории — мг/дл, ммоль/л, °dH, МЕ ферментов; строгие исключения вместо тихих ошибок.
- Автомобильные сервисы — расход л/100км ↔ mpg (US/UK), крутящий момент Н·м ↔ lbf·ft, давление шин.
- Контент и переводы — 6 локалей с плюрализацией, русские исторические меры для образовательных и музейных проектов.
- Когда не стоит: нужен неизменяемый набор из двух-трёх фиксированных коэффициентов в скрипте на 20 строк — хватит и умножения на константу.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
composer infection # мутационное тестирование (MSI 100%)
composer docs:build # пересборка сравнительных таблиц
php tools/build-index.php # пересборка индекса данных
Полный список команд с описаниями: composer run-script --list.
Документация
- Wiki (6 языков): wiki/docs/ru/Home.md
- Репозиторий: https://gitverse.ru/cloud-castle/unit-convertor
- История изменений: CHANGELOG.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano