League URI Toolkit 7.9: From URI Matching to Data Extraction

League URI Toolkit 7.9 introduces a new way to work with URIs: extracting data from them and converting that data into meaningful PHP values.

This release also updates the uri-polyfill to keep pace with the URI functionality available in PHP’s native ext/uri extension. But the most significant addition is the introduction of extraction APIs for UriTemplate and UrlPattern, opening up new possibilities for applications that need to retrieve structured data from URIs.

Let’s take a closer look at what’s new.

Extracting data from URIs

URI templates have traditionally been used to expand variables into a URI, following the rules defined by RFC 6570. With version 7.9, the league/uri package adds the ability to match existing URIs against a template and extract the values they contain.

The new API offers two complementary operations: match() to determine whether a URI conforms to a template, and extract() to retrieve the data captured by it.

For example, given the template:

$template = 'https://example.com/hotels/{hotel}/bookings/{booking}';

And the URI:

$uri = 'https://example.com/hotels/Rest%20%26%20Relax/bookings/42'

You can first check whether the URI matches the template:

use League\Uri\UriTemplate;

$uriTemplate = new UriTemplate($template);

$uriTemplate->match($uri); // true

When you need the values captured by the template, use extract():

use League\Uri\UriTemplate;

$uriTemplate = new UriTemplate($template);
$result = $uriTemplate->extract($uri);

$result->isSuccessful(); // true
$result['hotel'];   // 'Rest & Relax'
$result['booking']; // '42'

The new UriTemplate::extract() API returns an ExtractionResult, giving you access to the extracted values as well as information about the extraction process. You can inspect missing variables, identify extraction failures, and distinguish between complete and partial values.

When you need extraction to succeed completely or fail explicitly, extractOrFail() provides a strict alternative.

This feature extends the usefulness of URI templates beyond URI generation, making them a practical tool for interpreting existing URIs.

URL patterns can extract data, too

Version 7.9 brings the same matching and extraction capabilities via the UrlPattern class, based on the WHATWG URL Pattern specification.

Unlike URI templates, URL patterns support component-specific matching, wildcards, named groups, and regular-expression constraints. This makes them particularly useful for applications that need to recognize URL structures, including routers.

For example, you can define a pattern that matches book URLs with numeric identifiers:

use League\Uri\UrlPattern;

$pattern = UrlPattern::from(
    pattern: '/books/:id(\\d+)', 
    baseUrl: 'https://example.com'
);

As with URI templates, match() lets you check whether a URI conforms to the pattern:

$pattern->match('https://example.com/books/123'); // true
$pattern->match('https://example.com/books/abc'); // false

And when you need the captured values, extract() gives you access to them:

$result = $pattern->extract('https://example.com/books/123');

$result->path['id']; // '123'

Here, the regular-expression constraint ensures that the identifier contains only digits, while the extraction result exposes the captured value.

Although both APIs provide matching and extraction, they follow different models. UriTemplate implements RFC 6570 and extracts variables without being aware of the URI component they represent. UrlPattern, on the other hand, follows the WHATWG URL Pattern model and processes values according to their URI components.

This distinction also affects how extracted values can be converted. Consider the hostname label xn--fi8h, which represents the Unicode character 🍅. With UriTemplate, the extracted value remains in its original Punycode form until you explicitly interpret it as a hostname:

$uriTemplate = new UriTemplate('{host}.example.com');
$result = $uriTemplate->extract('xn--fi8h.example.com');

$result->string('host'); // 'xn--fi8h'
$result->host('host');   // '🍅'

With UrlPattern, hostname parsing and decoding are already handled by the URL Pattern algorithm:

$pattern = new UrlPatternBuilder(host: '{:foo}.example.com')->build();
$result = $pattern->extract('xn--fi8h.example.com');

$result->host->string('foo'); // '🍅'

The two APIs also differ in their extraction behavior. UriTemplate::extract() returns an inspectable result even when extraction is incomplete, whereas UrlPattern::extract() returns null when the URI does not match.

Together, these APIs let you match URIs, extract structured data, and convert values into the forms your application needs, while respecting the different semantics of URI templates and URL patterns.

From extracted strings to typed PHP values

Extracting values is only part of the problem. Once a value has been retrieved from a URI, it often needs to be converted before it can be used by an application.

Consider a pagination URI:

https://example.com/search?limit=10

The extracted value of limit is a string. An application may need it as an integer instead.

Version 7.9 introduces typed accessors that make these conversions part of the extraction API:

Query::fromUri($uri)->integer('limit'); // 10

Depending on the extraction API, you can retrieve values as strings, booleans, integers, floats, arrays, dates, or enums. Collection-oriented accessors also support converting lists of extracted values.

For example, a URI template can extract a date and a status:

$template = new UriTemplate('/articles/{date}{?status}');
$result = $template->extract('/articles/2026-10-17?status=published');

$result->date('date', '!Y-m-d');
$result->enum('status', ArticleStatus::class);

This allows the application to work with a DateTimeImmutable instance and an enum case rather than manually converting the extracted strings.

Conversions are deliberately safe: when a value is missing or cannot be converted, the typed accessor returns null. This gives applications an explicit way to handle invalid or unavailable values.

The result is a more direct path from a URI to application-level data, with less repetitive conversion code.

Keeping the URI polyfill up to date

Alongside these new APIs, the uri-polyfill has been updated to follow the functionality provided by PHP’s native ext/uri extension.

The polyfill remains important for projects that need the newer URI parsing capabilities while supporting PHP versions where the extension is unavailable. Keeping the implementation aligned helps maintain consistent behavior across supported environments.

Conclusion

League URI Toolkit 7.9 expands the role of URI handling in PHP applications.

With extraction support in both UriTemplate and UrlPattern, URIs can now serve not only as values to parse, construct, and manipulate, but also as structured sources of application data. Typed accessors take that one step further by making it easier to convert extracted values into the PHP types an application expects.

The uri-polyfill update complements these additions by keeping the toolkit aligned with PHP’s evolving native URI support.

Together, these changes make working with URIs more expressive and reduce the amount of custom code needed to turn them into useful application data.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.