cloud-castle / format-phone
Телефонные номера для PHP 8.1+: нормализация в E.164, маскирование для логов, определение страны/типа/региона и валидация по правилам страны. Быстрее и легче libphonenumber, неизменяем, без runtime-зависимостей.
Requires
- php: >=8.1
Requires (Dev)
- brick/phonenumber: ^0.6 || ^0.7
- deptrac/deptrac: ^3.0 || ^4.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- giggsey/libphonenumber-for-php-lite: ^8.13
- icanhazstring/composer-unused: ^0.9
- infection/infection: ^0.29 || ^0.33
- php-parallel-lint/php-parallel-lint: ^1.4
- 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
This package is auto-updated.
Last update: 2026-07-30 05:55:22 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Format Phone
Работа с телефонными номерами для PHP 8.1+: нормализация в E.164, форматирование, маскирование номера для логов (
+7999****567), а также определение страны, типа линии (мобильный/городской), региона и валидация по правилам страны (RU, US, GB, DE, FR, IT, ES). Неизменяемый value-объект, fail-loud, ноль runtime-зависимостей (справочник встроен).
Установка
composer require cloud-castle/format-phone
Требуется PHP 8.1+.
Быстрый старт
<?php
use CloudCastle\Format\Phone\PhoneNumber;
// Разбор и нормализация в E.164 (пробелы, скобки, дефисы отбрасываются).
$phone = PhoneNumber::parse('+7 (999) 123-45-67');
$phone->toE164(); // '+79991234567'
$phone->getDigits(); // '79991234567'
$phone->format(); // '+7 999 123 456 7' (обобщённая группировка)
// Маскирование для логов — не пишем полный номер в журнал.
$phone->mask(); // '+79*******67' (по 2 цифры с краёв)
$phone->mask(3, 2, '•'); // '+799••••••67'
// Национальный номер + код страны (ведущий 0 отбрасывается).
PhoneNumber::parse('0123456789', '44')->toE164(); // '+44123456789'
// Проверка без исключения.
PhoneNumber::isValid('+79991234567'); // true
PhoneNumber::isValid('12345'); // false
// Определение страны, типа линии и региона по справочнику.
$moscow = PhoneNumber::parse('+74951234567');
$moscow->country(); // 'RU'
$moscow->type(); // PhoneNumberType::FixedLine
$moscow->region(); // 'Москва'
$moscow->isValidNumber(); // true (валиден по правилам RU)
$mobile = PhoneNumber::parse('+79991234567');
$mobile->type(); // PhoneNumberType::Mobile
$mobile->region(); // null (мобильный — не геозависим)
// Разбор в национальном формате страны (снимается национальный префикс).
PhoneNumber::parseForRegion('8 (999) 123-45-67', 'RU')->toE164(); // '+79991234567'
PhoneNumber::parseForRegion('07911 123456', 'GB')->type(); // PhoneNumberType::Mobile
// Проверка принадлежности стране.
$mobile->isValidForCountry('RU'); // true
$mobile->isValidForCountry('US'); // false
Возможности
- Нормализация в E.164:
parse()отбрасывает форматирование, проверяет длину (8–15 цифр) и цифровой состав;toE164(),getDigits(),format(). - Маскирование для логов:
mask()скрывает середину номера, оставляя первые и последние цифры — защита персональных данных в журналах и трассировках. - Определение страны и национального номера:
country(),callingCode(),nationalNumber()по встроенному справочнику (RU, US, GB, DE, FR, IT, ES). - Определение типа линии:
type()→ {@see PhoneNumberType} (мобильный, городской, бесплатный, премиальный, VoIP и т.д.) по правилам страны. - Определение региона:
region()для геозависимых (стационарных) номеров (например,+74951234567→ «Москва»). - Валидация по стране:
isValidNumber()иisValidForCountry()проверяют номер не только по длине E.164, но и по правилам конкретной страны. - Разбор национального формата:
parseForRegion($input, 'RU')снимает национальный префикс и подставляет код страны. - Fail-loud: некорректный номер или код страны — сразу
InvalidPhoneNumberException, а не тихий мусор. - Неизменяемый value-объект: номер нельзя случайно изменить.
- Ноль runtime-зависимостей: справочник встроен как PHP-массив — лёгкий и быстрый;
подменяется через
PhoneNumber::useRegistry()для кастомных данных.
Сравнение с аналогами
Все таблицы ниже сгенерированы автоматически из честных сравнительных
тестов (benchmarks/compare.php) на ОДИНАКОВОЙ операции для всех аналогов,
PHP 8.1.34, без Xdebug.
1. Функциональность
| Возможность | 🏆 CloudCastle | libphonenumber | brick | preg¹ |
|---|---|---|---|---|
Нормализация в E.164 (+ и цифры) | ✅ | ✅ | ✅ | ✅ |
| Маскирование середины номера для логов (защита ПД) | ✅ | ❌ | ❌ | ❌ |
| Fail-loud на некорректной длине/коде страны | ✅ | ✅ | ✅ | ❌ |
| Неизменяемый value-объект | ✅ | ❌ | ✅ | ❌ |
| Ноль runtime-зависимостей (справочник встроен) | ✅ | ❌ | ❌ | ✅ |
| Валидация номера по данным конкретной страны² | ✅ | ✅ | ✅ | ❌ |
| Определение типа линии (мобильный/городской/…)² | ✅ | ✅ | ✅ | ❌ |
| Определение региона по номеру² | ✅ | ✅ | ✅ | ❌ |
| Всего | 🏆 8 | 5 | 6 | 2 |
2. Безопасность и корректность
| Свойство | 🏆 CloudCastle | libphonenumber | brick | preg¹ |
|---|---|---|---|---|
| Маскирование ПД (номера) в логах | ✅ | ❌ | ❌ | ❌ |
| Fail-loud: исключение вместо тихого мусора | ✅ | ✅ | ✅ | ❌ |
| Неизменяемость (нет случайной мутации номера) | ✅ | ❌ | ✅ | ❌ |
| Ноль зависимостей (малая поверхность атаки) | ✅ | ❌ | ❌ | ✅ |
| Валидация длины E.164 (8–15 цифр) | ✅ | ✅ | ✅ | ❌ |
| Всего | 🏆 5 | 2 | 3 | 1 |
3. Производительность
разбор номера с форматированием → E.164, 50 000 раз (минимум из 4).
| Решение | Время (мс) | Итог |
|---|---|---|
| preg¹ | 12,1 | базовый уровень (не библиотека) |
| 🏆 CloudCastle | 60,9 | быстрейшее среди библиотек |
| libphonenumber | 697,5 | аналог |
| brick | 733,6 | аналог |
4. Потребление памяти
Пик памяти на 50 000 операций (изолированный процесс, только целевая библиотека).
| Решение | Пиковая память (KB) | Итог |
|---|---|---|
| 🏆 CloudCastle | 6 966 | легчайшее среди библиотек |
| preg¹ | 6 966 | базовый уровень (не библиотека) |
| libphonenumber | 7 388 | аналог |
| brick | 7 588 | аналог |
¹ Базовый уровень (нативные вызовы/примитивы без полноты решения) показан для контекста и не претендует на победу среди библиотек-аналогов.
² Валидация по стране, определение типа и региона реализованы для выверенного
набора стран (RU, US, GB, DE, FR, IT, ES). libphonenumber покрывает 200+ стран
(это его сильная сторона по охвату), но тянет объёмные базы, мутабелен, не маскирует
ПД и на порядок медленнее. Справочник CloudCastle расширяем и спроектирован под
вынос в отдельную библиотеку.
Вывод и честная область применения. CloudCastle Format Phone сочетает лёгкую
нормализацию в E.164, безопасное маскирование ПД для логов (чего нет у
аналогов) и определение страны/типа линии/региона + валидацию по правилам страны
для выверенного набора стран — при этом он на порядок быстрее и легче
libphonenumber/brick, неизменяем и без runtime-зависимостей. Идеален для финтеха
и систем, работающих с номерами перечисленных стран, где важны скорость, безопасность
ПД и предсказуемость. Если нужен максимальный международный охват (200+ стран),
геокодирование и данные операторов — берите libphonenumber; во всех остальных
сценариях (особенно логи/хранение/финтех и перечисленные страны) этот пакет
предпочтительнее.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
Полный список команд с описаниями: composer run-script --list.
Документация
- Wiki (возможности, диаграммы, сравнения): wiki/docs/ru/Home.md
- Жизненный цикл номера (mermaid)
- Определение страны · Тип линии · Регион · Маскирование · Валидация
- Репозиторий: https://gitverse.ru/cloud-castle/format-phone
- История изменений: CHANGELOG.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano