brick/phonenumber
Brick\PhoneNumber is a PHP library for parsing, formatting, and validating international phone numbers. A port of Google's libphonenumber, it offers robust utilities for formatting, validation, and type detection in PHP applications.
Architecture fit. brick/phonenumber is a self-contained, framework-agnostic port of Google's libphonenumber: a single facade (PhoneNumberUtil::getInstance()) plus immutable value objects (PhoneNumber) and a parse exception type. It has no Laravel coupling, no service provider, no config, no I/O. That makes it a clean fit for a Laravel codebase — it slots in as a domain utility behind a singleton binding rather than as infrastructure. The main architectural decision is not whether it fits, but whether we hide it: injecting the vendor facade directly into controllers and models would couple our validation and formatting rules to this specific port, and there is a credible alternative (giggsey/libphonenumber-for-php) with near-identical semantics. Recommend wrapping it behind a thin internal interface (PhoneNumberNormalizer / PhoneNumberValidator) so the swap cost stays low.
Integration feasibility. composer require brick/phonenumber, one singleton binding in a service provider, one custom validation rule, and custom casts/mutators for normalized persistence. That is roughly a one-to-two-day effort for a competent Laravel developer. Two real constraints to confirm before committing: the PHP version floor (recent releases require PHP 8.1+) and the hard dependency on ext-gmp or ext-bcmath. The latter is the most common surprise in containerized deployments — it must be added to the base image and CI, and it will fail loudly if missing.
Technical risk. Moderate and mostly bounded:
isPossibleNumber() and isValidNumber(), and the distinction is easy to get wrong. Using the weaker check silently lets malformed numbers through — a data-quality failure that shows up months later in SMS delivery rates.null produces plausible-but-wrong normalizations.Key questions.
ext-gmp or ext-bcmath, and who owns that change?Stack fit. Pure PHP, PSR-4 autoloaded, no global state beyond the singleton facade's internal metadata cache. It works unchanged under FPM, Octane, and queue workers. There is nothing to configure and nothing to boot.
Compatibility. Laravel version-agnostic; the binding constraint is the PHP minor version and the GMP/BCMath extension. Because the package ships no Laravel provider, there is no version-coupling to the framework — which also means no upgrade friction when Laravel majors roll.
Migration path. Two likely starting points:
giggsey/libphonenumber-for-php. Also low risk, since the two ports deliberately mirror each other's API surface. Differences to reconcile: namespaces, exception classes, and formatting-constant/enum representations. If there is any chance we start on one and move to the other, the abstraction layer pays for itself immediately.Sequencing.
PhoneNumberUtil as a singleton.Maintenance. Low ongoing code maintenance, moderate dependency hygiene. The recurring obligation is periodic upgrades to pick up metadata refreshes; skipping them degrades validation quality quietly rather than breaking anything. No config files to drift, no schema. Watch upstream releases and pin to a known-good version between upgrades.
Support. Community-only: GitHub issues, no SLA, effectively a single maintainer. Acceptable for a utility of this scope; the fallback (forking, or switching to the sibling port) is realistic because the API is narrow and the behavior is specified upstream.
Scaling. Effectively free. Parsing is pure in-process CPU with metadata loaded once per worker and cached for the process lifetime. No network calls, no locks, no shared state. The only scaling note is per-worker memory for the metadata blob — a few megabytes, which matters at high worker counts and is otherwise negligible. Keep opcache enabled and avoid re-parsing the same values in hot loops; parse once at the boundary and pass the value object or the normalized string.
Failure modes to instrument.
NumberParseException on user input — must be caught and converted to a validation message, never a 500.ext-gmp/ext-bcmath — fails at install or first use; catch it in CI, not production.isPossibleNumber() is used where isValidNumber() is required.Ramp-up. Half a day to a day for a mid-level Laravel developer to be productive. The concepts that actually need teaching are not the API but the semantics: E.164 as the storage canonical form, valid versus possible, default-region behavior for national-format input, and why formatting belongs at the presentation boundary rather than in the database.
How can I help you explore Laravel packages today?