Александр Некрасов · Автономное руководство

PHP: полный мануал с примерами, функциями и ООП

Разделы этой страницы
  1. URI и URL: полный справочник двух парсеров
  2. Получить полезную часть ссылки: первый запуск
  3. Scheme, host, path, query и fragment
  4. RFC 3986: общий URI и две формы компонентов
  5. WHATWG: веб-ссылки, IDNA и исправляемый ввод
  6. Почему результат with нужно сохранить
  7. Эквивалентность и UriComparisonMode
  8. Байты, Unicode и границы компонентов
  9. Исключение, Error и диагностическая запись
  10. Как читать soft и hard ошибки WHATWG
  11. Все29 типов UrlValidationErrorType
  12. От синтаксиса к правилам конкретного приложения
  13. Практика: функция ссылок пагинации
  14. Полный справочник методов URI
  15. Функции и методы этой темы
  16. Код и руководство с собой
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 100 · С нуля → полный справочник

URI и URL: полный справочник двух парсеров

От первого имени узла до всех методов RFC3986 и WHATWG, immutable-изменений, нормализации, сериализации и29 типов диагностики. PHP8.5+.

Получить полезную часть ссылки: первый запуск

Наглядная модель

Выбрать правила адреса до его разбора

Ссылка может быть относительной, содержать кодирование и по-разному пониматься браузерным и RFC-парсером.

  1. Исходная строка

    Адрес ещё не проверен и не означает сетевое соединение.

  2. Выбранный стандарт

    Rfc3986 Uri либо WhatWg Url разбирает строку по своим правилам.

  3. Компоненты и изменения

    Читаем схему, host и путь; сохраняем возвращённый новый объект после изменения.

  4. Политика приложения

    Отдельно проверяем разрешённую цель, схему и правила фактического HTTP-клиента.

Корректный адрес не подтверждает доступность и допустимость ресурса. Нормализация и raw-компоненты решают разные задачи.

На странице магазина есть ссылка https://shop.example/catalog/drill?color=blue#delivery. Нужно взять имя узла, изменить фильтр и сохранить якорь. Если разрезать строку вручную по /, ?, @ и :, легко спутать пароль с host или данные параметра с разделителем. Расширение URI хранит разобранный адрес в объекте и даёт отдельные операции над его частями. Результат первого примера — только имя shop.example; подключений не будет.

Адрес как подписанный бланк
  1. Строка https://shop.example/catalog/drill
  2. Парсер выделяет scheme=https и host=shop.example
  3. $address хранит разобранный бланк
  4. getAsciiHost() возвращает shop.example

Бланк — аналогия структуры, не буквальное устройство памяти и не справка о владельце сайта. Адрес идентифицирует ресурс, но сам по себе не подтверждает его существование. RFC 3986 описывает общую структуру URI; WHATWG URL Standard задаёт веб-алгоритмы, близкие браузерам. Мы сначала используем WHATWG Url для HTTPS, затем сравним правила.

Основа записи: переменная и присваивание, что такое объект и вызов метода. Здесь необходимые символы разобраны до запуска; углубление в классы не требуется для первой строки.

ЗаписьЧто делает именно здесь
<?phpНачинает PHP-файл. Сохраните его как hello-uri.php в UTF-8; запускайте своим PHP 8.5+ через php hello-uri.php.
declare(strict_types=1);Включает строгие скалярные типы вызовов из этого файла; неправильное число вместо ожидаемой строки не следует считать корректным адресом.
$address = …;$address — имя переменной, = сохраняет результат справа, ; завершает команду.
new Uri\WhatWg\Url('https://shop.example/catalog/drill')new создаёт объект; полное имя с \ выбирает класс. Круглые скобки передают строку входа конструктору. Кавычки обозначают текст, а не имя переменной.
$address->getAsciiHost()-> вызывает операцию объекта. Пустые () означают, что дополнительных аргументов нет; результат — строка имени узла или null.
echo …, "\n";Печатает результат и перевод строки. В терминале ожидается строка ниже примера.
Получить имя узла из ссылкиСамостоятельный пример
<?php
declare(strict_types=1);

$address = new Uri\WhatWg\Url('https://shop.example/catalog/drill');
echo $address->getAsciiHost(), "\n";
Ожидаемый результат
shop.example

Не загружены ни каталог, ни картинка; URL разобран в памяти. Для реального HTTP существуют отдельные клиенты. .example — учебное имя, никаких прав или доступности сервера пример не предполагает.

Классы добавлены в PHP 8.5.0. В PHP 8.2–8.4 запись такого new не работает. В PHP 8.5 URI встроено: не нужно придумывать extension=uri для отдельной DLL. Проверьте выбранный исполняемый файл командой php -v и наличие класса; CLI и веб-сервер могут использовать разные PHP. Код проверки ниже честно рассчитан на окружение этого учебника PHP 8.5.11.

Проверить наличие нужного классаСамостоятельный пример
<?php
declare(strict_types=1);

echo PHP_VERSION_ID >= 80500 ? "Версия подходит\n" : "Нужен PHP 8.5+\n";
echo class_exists(Uri\WhatWg\Url::class) ? "WHATWG Url доступен\n" : "Класс отсутствует\n";
Ожидаемый результат
Версия подходит
WHATWG Url доступен

::class даёт полное имя класса строкой, class_exists проверяет доступность. У старого PHP ожидаются ветки отказа, а не напечатанный здесь успешный результат. Это проверка окружения, не установка.

Scheme, host, path, query и fragment

Разберём конкретную ссылку по частям. Порядок разделителей задаёт смысл символов: query начинается после первого структурного ?, fragment — после #. Если эти символы являются данными, их кодируют внутри соответствующего компонента.

Части ссылки каталога
  1. https://shop.example:8443
  2. /catalog/drill
  3. ?color=blue&page=2
  4. #delivery
КомпонентЗначение и назначение
schemehttps — схема; без :// в getter.
hostshop.example — имя узла. Это не обязательно домен: возможны IPv4, IPv6 и другие URI-схемы.
port8443 — явно заданный порт. Host и port — разные поля.
path/catalog/drill — маршрут ресурса; не локальный файловый путь.
querycolor=blue&page=2 — строка запроса. Разделение на ключи и значения задаёт приложение, не общая грамматика URI.
fragmentdelivery — клиентский указатель на часть ресурса.
userinfo / credentialsНапример anna:demo@ перед host. В учебных стендах можно разобрать; в обычном интерфейсе такие секреты лучше не принимать в URL.

Authority — часть после // до пути: может включать userinfo@host:port. Нельзя доверять тексту до @ как домену. null означает, что компонента нет; пустая строка может означать, что разделитель был, но значение пустое. getPath возвращает строку, даже если она пустая. RFC и WHATWG не во всех случаях одинаково сохраняют эту разницу.

Увидеть отсутствующий и пустой queryСамостоятельный пример
<?php
declare(strict_types=1);

$missing = new Uri\Rfc3986\Uri('https://shop.example/p');
$empty = new Uri\Rfc3986\Uri('https://shop.example/p?');
echo $missing->getQuery() === null ? "Нет query\n" : "Есть query\n";
echo $empty->getQuery() === '' ? "Пустой query\n" : "Другое значение\n";
Ожидаемый результат
Нет query
Пустой query

=== требует совпадения значения и типа. Простое echo для null и пустой строки вывело бы одинаковую пустоту, поэтому используем условный выбор сообщения: условие ? при-истине : иначе.

RFC 3986: общий URI и две формы компонентов

Uri\Rfc3986\Uri нужен, когда договор системы опирается на RFC 3986: URI может быть абсолютным, относительным, HTTP-ссылкой или идентификатором другой схемы. Это общий синтаксический инструмент, не валидатор доступности веб-сайта. Сохраняются исходные компоненты, а обычные getters и toString показывают нормализованную форму.

Две формы одного RFC URI
  1. HTTPS://Shop.Example/a/../%7ecard
  2. Raw: сохранить запись компонентов
  3. Normalized: lowercase + ~ + устранить a/..
  4. https://shop.example/~card

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Класс final readonly: нельзя наследоваться и менять готовый объект присваиванием свойств. Публичных изменяемых полей scheme/host/path нет. Получите компонент getter-методом или новый объект через with-метод. clone создаёт отдельный объект с тем же адресом; equals сравнивает адреса по режиму, === проверяет тождество объектов. __toString не предоставлен — выводите toString()/toRawString().

Сравнить исходное представление и нормализованноеСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri;

$u = new Uri('HTTPS://Shop.Example/a/../%7ecard');
echo $u->toRawString(), "\n";
echo $u->toString(), "\n";
Ожидаемый результат
HTTPS://Shop.Example/a/../%7ecard
https://shop.example/~card

use вводит короткое имя Uri в текущем файле; он не загружает пакет Composer и не запускает запрос. Raw не является гарантией байтовой копии: IPv6 сериализуется заново, а разрешение базы уже создаёт новый адрес.

Хранить ссылку, у которой пока нет схемыСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri;

$relative = new Uri('../images/drill.png');
echo $relative->getScheme() === null ? "Относительная ссылка\n" : "Есть схема\n";
$base = new Uri('https://shop.example/catalog/page');
echo $base->resolve($relative->toRawString())->toString(), "\n";
Ожидаемый результат
Относительная ссылка
https://shop.example/images/drill.png

Сам относительный объект корректен. Разрешение требует абсолютной базы. Не используйте относительную базу даже с абсолютным первым аргументом: PHP 8.5.11 отвергает такую комбинацию.

Начать API: Uri\Rfc3986\Uri::__construct, Uri\Rfc3986\Uri::parse, Uri\Rfc3986\Uri::getRawPath, Uri\Rfc3986\Uri::withQuery.

WHATWG: веб-ссылки, IDNA и исправляемый ввод

Uri\WhatWg\Url подходит для ссылок, которые должны разбираться по веб-алгоритму. Он обрабатывает международные домены, специальные схемы и допускает некоторые исправляемые нарушения исходной записи. Относительной строке нужна база: без неё Url::parse возвращает null, а new бросает InvalidUrlException. Полученный объект всегда имеет схему.

Браузерная нормализация
  1. HTTPS://пример.рф:443/a/../p
  2. IDNA-домен + удалить стандартный порт
  3. Свернуть сегменты пути
  4. https://xn--e1afmkfd.xn--p1ai/p
ПравилоЧто проверить в приложении
Special schemesftp, file, http, https, ws, wss. Стандартные порты: ftp21, http/ws80, https/wss443; file без такого порта. У прочих схем другой разбор host/path.
Hierarchical и opaque pathhttps://host/a имеет иерархический путь. mailto:sales@host имеет opaque path: обычный resolve/withPath не превращает его в каталог.
НормализацияУбираются dot-segments, default port и некоторые лишние разделители; Unicode-домен преобразуется IDNA, IPv4 может иметь нестандартную исходную запись. Не считайте входные байты сохранёнными.
ДиагностикаМягкие ошибки могут сопровождать успешный объект; они доступны выходным массивом. При жёстком отказе есть exception->errors либо null+errors у parse.
with-операцииСледуют URL setter-алгоритмам: могут нормализовать, не применить изменение либо использовать только часть строки. Это не строгая проверка всей строки отдельного поля.
Получить машинную и читаемую формы URLСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url;

$u = new Url('HTTPS://пример.рф:443/a/../p');
echo $u->toAsciiString(), "\n";
echo $u->toUnicodeString(), "\n";
Ожидаемый результат
https://xn--e1afmkfd.xn--p1ai/p
https://пример.рф/p

Две формы отражают один объект; Unicode касается отображения домена, а не декодирования всех % в пути. DNS и HTTP не выполняются.

Не обращаться с mailto как с каталогомСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url;

$mail = new Url('mailto:sales@shop.example');
echo $mail->getPath(), "\n";
echo $mail->withPath('/help')->toAsciiString(), "\n";
try { $mail->resolve('help'); } catch (Uri\WhatWg\InvalidUrlException $e) { echo "Эта база не каталог\n"; }
Ожидаемый результат
sales@shop.example
mailto:sales@shop.example
Эта база не каталог

withPath у opaque URL не применяет новый hierarchical путь. Новая цель другой природы требует нового объекта. Это поведение парсера, не отправка почты.

Начать API: Uri\WhatWg\Url::parse, Uri\WhatWg\Url::getAsciiHost, Uri\WhatWg\Url::withHost, Uri\WhatWg\UrlValidationError.

Почему результат with нужно сохранить

Оба класса моделируют адрес и не меняют исходный объект в with-операции. Это удобно для независимых фильтров каталога: базовая ссылка одна, а ссылки «страница2» и «страница3» не перезаписывают друг друга. Переменная может получить новый объект; readonly относится к объекту, а не запрещает присваивать переменной.

Два независимых фильтра
  1. $base: /catalog
  2. withQuery(page=2) → новый $page2
  3. withQuery(page=3) → новый $page3
  4. $base по-прежнему без query
Сохранить базовую ссылку и отдельный вариантСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url;

$base = new Url('https://shop.example/catalog');
$page2 = $base->withQuery('page=2');
$page3 = $base->withQuery('page=3');
echo $base->toAsciiString(), "\n";
echo $page2->toAsciiString(), "\n";
echo $page3->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/catalog
https://shop.example/catalog?page=2
https://shop.example/catalog?page=3

Каждый результат явно сохранён. Если нужна только текущая версия, допустимо $base = $base->withQuery(...); это замена ссылки в переменной, а не изменение старого объекта.

Отличить копию объекта от того же экземпляраСамостоятельный пример
<?php
declare(strict_types=1);

$a = new Uri\Rfc3986\Uri('https://shop.example/p');
$b = clone $a;
echo $a === $b ? "Один объект\n" : "Два объекта\n";
echo $a->equals($b) ? "Эквивалентные URI\n" : "Разные URI\n";
Ожидаемый результат
Два объекта
Эквивалентные URI

clone копирует текущий адрес. Для изменения компонента обычно достаточно with: он сам создаёт новый объект. Нельзя считать === сравнением URI-значений.

Эквивалентность и UriComparisonMode

Для списка загружаемых ресурсов две ссылки, отличающиеся #delivery и #payment, часто нужно считать одним адресом. Для списка мест чтения это разные записи. UriComparisonMode заставляет явно назвать выбранное правило: IncludeFragment учитывает fragment; ExcludeFragment не учитывает и используется по умолчанию.

Правило сравнения
  1. help#delivery и help#payment
  2. equals по умолчанию → без fragment
  3. true для адреса ресурса
  4. IncludeFragment → false для места чтения
Pure enum PHP 8.5Договор
Uri\UriComparisonMode::IncludeFragmentУчитывать fragment; отличается от простого true в аргументе.
Uri\UriComparisonMode::ExcludeFragmentНе учитывать fragment; default у equals обоих классов.
cases(), namecases() возвращает оба case; ->name даёт имя. Нет backed value и автоматических from/tryFrom.
Выбрать режим для закладокСамостоятельный пример
<?php
declare(strict_types=1);

$mode = Uri\UriComparisonMode::IncludeFragment;
$a = new Uri\WhatWg\Url('https://shop.example/help#delivery');
$b = new Uri\WhatWg\Url('https://shop.example/help#payment');
echo $mode->name, "\n";
echo $a->equals($b, $mode) ? "Одна закладка\n" : "Разные закладки\n";
Ожидаемый результат
IncludeFragment
Разные закладки

Enum-case — отдельное значение, его не заменяет строка "IncludeFragment". :: обращается к case по имени класса.

Не считать перестановку query автоматически эквивалентнойСамостоятельный пример
<?php
declare(strict_types=1);

$a = new Uri\WhatWg\Url('https://shop.example/p?a=1&b=2');
$b = new Uri\WhatWg\Url('https://shop.example/p?b=2&a=1');
echo $a->equals($b) ? "эквивалентны\n" : "различаются\n";
Ожидаемый результат
различаются

Одинаковый набор пар не означает одинаковый протокол: порядок/повторы могут влиять на подпись или сервер. equals не знает правил вашего приложения и не сортирует query.

Байты, Unicode и границы компонентов

Процентная запись %20 означает кодированный байт пробела. Она не равна HTML-экранированию &amp; и не является универсальной «безопасной строкой». Сначала задаётся структура адреса, затем кодируются данные каждого компонента. Unicode-домен обрабатывается IDNA; Unicode в сегменте пути обычно представлен percent-encoded UTF-8-байтами.

Данные поиска в нужном контексте
  1. q = drill & bit
  2. http_build_query → q=drill%20%26%20bit
  3. withQuery → URL
  4. HTML display → htmlspecialchars отдельно
Не дать амперсанду создать лишний параметрСамостоятельный пример
<?php
declare(strict_types=1);

$input = 'drill & bit';
$query = http_build_query(['q' => $input], '', '&', PHP_QUERY_RFC3986);
$u = (new Uri\WhatWg\Url('https://shop.example/find'))->withQuery($query);
echo $u->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/find?q=drill%20%26%20bit

[] создаёт массив, => связывает ключ q со значением $input. http_build_query кодирует именно данные параметра. Полученное %26 не становится структурным разделителем query.

Сохранить различие данных и разделителяСамостоятельный пример
<?php
declare(strict_types=1);

$a = new Uri\Rfc3986\Uri('https://shop.example/items/a%2Fb');
$b = new Uri\Rfc3986\Uri('https://shop.example/items/a/b');
echo $a->getPath(), "\n";
echo $a->equals($b) ? "Одинаково\n" : "Разная структура\n";
Ожидаемый результат
/items/a%2Fb
Разная структура

RFC-нормализация не раскрывает reserved / из %2F. Rawurldecode всего URL разрушил бы границы; декодируйте только данные компонента согласно протоколу и ровно один нужный раз.

parse_str не является нейтральным преобразованием любого query: он следует PHP-формату, меняет некоторые имена ключей и может терять повторные скалярные ключи. URL encoding, IDNA, UTF-8 и HTML encoding решают разные задачи. Для строгой подписи храните исходный текст и применяйте только предусмотренную протоколом канонизацию.

Исключение, Error и диагностическая запись

Импортёр ссылок должен отличать неправильный адрес от ошибки программы. Исключения прерывают обычный ход до подходящего catch. Объект UrlValidationError лишь описывает событие; его наличие в массиве не означает, что выполнение было прервано.

Два канала результата
  1. parse → объект или null
  2. errors → список записей
  3. constructor/with → при отказе exception
  4. catch читает тип и принимает решение
ТипНаследование и назначение
Uri\UriExceptionextends Exception; базовая ветка исключений URI.
Uri\InvalidUriExceptionextends Uri\UriException; не удалось разобрать/создать допустимый RFC URI.
Uri\WhatWg\InvalidUrlExceptionextends Uri\InvalidUriException; отказ WHATWG и public readonly array $errors. catch(InvalidUriException) охватывает обе ветки.
Uri\UriErrorextends Error; внутренняя ошибка URI. catch(Exception) не охватывает Error; общий предок обеих веток — Throwable.
Uri\WhatWg\UrlValidationErrorfinal readonly, не Throwable; одна диагностическая запись context/type/failure. Не бросайте её через throw.

Первые три базовых типа UriException, InvalidUriException, UriError наследуют конструктор (string $message = "", int $code = 0, ?Throwable $previous = null). Не добавляйте им вымышленных полей. getMessage возвращает строку причины; getCode — код, выбранный источником, а не обязательный HTTP-статус. getPrevious даёт предыдущую причину или null. getFile/getLine указывают место возникновения, getTrace возвращает массив кадров, getTraceAsString — текст, __toString — текстовое представление с диагностикой. Их вывод может содержать пути и аргументы. Клонирование исключения запрещено; создавайте обёртку с previous.

Перехватить адресный отказ без подавления всего приложенияСамостоятельный пример
<?php
declare(strict_types=1);

try {
    new Uri\WhatWg\Url('https://shop.example:70000/');
} catch (Uri\InvalidUriException $e) {
    echo $e instanceof Uri\WhatWg\InvalidUrlException ? "Отказ WHATWG\n" : "Отказ RFC\n";
    echo "Проверьте адрес\n";
}
Ожидаемый результат
Отказ WHATWG
Проверьте адрес

Дочернее исключение подходит родительскому catch. Пользователю показана наша безопасная фраза; техническая трассировка и context не публикуются.

Сохранить причину на границе импортаСамостоятельный пример
<?php
declare(strict_types=1);

$cause = new Uri\InvalidUriException('Некорректная ссылка');
$jobError = new Uri\UriException('Не импортирована карточка 17', 17, $cause);
echo $jobError->getMessage(), "\n";
echo $jobError->getCode(), "\n";
echo $jobError->getPrevious() === $cause ? "Причина сохранена\n" : "Причина потеряна\n";
echo (new Uri\UriError('Тестовый внутренний отказ')) instanceof Error ? "Ветка Error\n" : "Другая ветка\n";
Ожидаемый результат
Не импортирована карточка 17
17
Причина сохранена
Ветка Error

Объекты здесь создаём сами; внутренний сбой парсера не имитируется сетевой аварией. Код17 — локальный номер карточки, не статус протокола.

В PHP 8.5.11 сериализационные hooks имеют отдельные Exception/previous Error границы; они описаны в карточках __unserialize. Не переносите обещания конструктора на любой magic method. Все типы этой ветки появились в PHP 8.5.0.

Как читать soft и hard ошибки WHATWG

Редактор ссылки может показать предупреждение и всё же получить исправленный URL. У каждой записи context — часть входа в месте обнаружения проблемы, type — один из29 enum-case, failure — true при отказе парсинга, false при диагностируемом исправлении. context не является номером позиции и не гарантирует безопасное содержимое для журнала.

Разбор опечатки
  1. https:shop.example
  2. WHATWG восстанавливает //
  3. объект https://shop.example/
  4. type + failure=false сохраняют факт исправления
Прочитать диагностическое имя без исходного секретаСамостоятельный пример
<?php
declare(strict_types=1);

$diagnostics = [];
$url = Uri\WhatWg\Url::parse('https:shop.example', null, $diagnostics);
echo $url?->toAsciiString(), "\n";
foreach ($diagnostics as $item) {
    echo $item->type->name, ':', $item->failure ? 'отказ' : 'исправление', "\n";
}
Ожидаемый результат
https://shop.example/
SpecialSchemeMissingFollowingSolidus:исправление

?-> вызывает метод лишь у ненулевого объекта. foreach проходит по списку; ->type возвращает enum, ->name — имя его case. Код не выводит context.

Не спутать диагностику двух последовательных проверокСамостоятельный пример
<?php
declare(strict_types=1);

$errors = [];
Uri\WhatWg\Url::parse('https:shop.example', null, $errors);
echo count($errors), "\n";
Uri\WhatWg\Url::parse('https://shop.example/', null, $errors);
echo count($errors), "\n";
Ожидаемый результат
1
0

Выходной массив относится только к последней попытке, не накапливает историю. Если нужна история импорта, сохраняйте собственную запись с номером строки до следующего parse.

Все29 типов UrlValidationErrorType

Enum задаёт закрытый набор причин. Это pure enum: есть name и cases(), нет backed value, from() или tryFrom(). Для внешнего формата выберите собственное стабильное отображение имён и версию схемы. Не присваивайте каждому case навсегда одну тяжесть: признак failure находится в конкретной записи парсера.

Диагностика укороченного IPv4
  1. http://0x7f.1/
  2. Канонический host 127.0.0.1
  3. Ipv4NonDecimalPart
  4. failure=false: принято с исправлением
Case UrlValidationErrorTypeУсловие и практический смысл
DomainToAsciiДомен не прошёл преобразование IDNA в ASCII; например, повреждённая xn-- метка. Это проверка имени, не DNS.
DomainToUnicodeОшибка IDNA-преобразования доменного имени в Unicode. Наличие enum-case не обещает, что всякий parser path выдаст его; учитывайте используемую операцию.
DomainInvalidCodePointПосле обработки домен special-URL содержит запрещённый символ, например пробел или %00. Нельзя исправлять простым удалением символа.
HostInvalidCodePointЗапрещённый символ в opaque host у non-special схемы. Это другой алгоритм, чем IDNA-домен HTTPS.
Ipv4EmptyPartIPv4 заканчивается точкой, например 192.0.2.1.; парсер может убрать её и сообщить мягкую диагностику.
Ipv4TooManyPartsБольше четырёх частей IPv4, например 1.2.3.4.5. Уточнение PHP 8.5.11/WHATWG: меньше четырёх частей не обязательно ошибка, 127.1 допустимо и разворачивается.
Ipv4NonNumericPartЧасть кандидата IPv4 не удалось разобрать как число; например, буквенная часть при окончании адреса числом.
Ipv4NonDecimalPartIPv4 использует hex или octal, например 0x7f.1. Это может быть мягкое исправление к 127.0.0.1; не проверяйте IP только по исходному тексту.
Ipv4OutOfRangePartЧисловая часть превышает обычный октет 255. Непоследние части должны помещаться в октет; последняя при укороченной записи может занимать оставшиеся октеты. Проверяйте failure конкретного сообщения, а не объявляйте любой случай одинаковым.
Ipv6UnclosedВ IPv6-host нет закрывающей ], например https://[::1/. Скобки относятся к синтаксису URL-host.
Ipv6InvalidCompressionНачало IPv6 некорректно обозначает сжатие нулей, например [:1]. Одиночный начальный : не заменяет ::.
Ipv6TooManyPiecesБолее восьми шестнадцатеричных групп в IPv6. Сжатие не разрешает превысить итоговую длину адреса.
Ipv6MultipleCompressionСжатие :: использовано дважды, например [1::2::3]; нельзя однозначно восстановить длины обеих последовательностей нулей.
Ipv6InvalidCodePointВ IPv6 встретился неожиданный символ/окончание вместо hex-цифры либо разделителя, например [::g].
Ipv6TooFewPiecesБез :: указано меньше восьми групп, например [1:2:3]; недостающие группы автоматически не дописываются.
Ipv4InIpv6TooManyPiecesВ IPv6 с IPv4-хвостом до хвоста уже слишком много групп: IPv4 занимает две из восьми групп, для префикса остаётся не более шести.
Ipv4InIpv6InvalidCodePointНекорректная часть IPv4-хвоста: пустота, нецифра, ведущий ноль или лишняя часть. У этого хвоста более строгая запись, чем у самостоятельного WHATWG IPv4.
Ipv4InIpv6OutOfRangePartВ IPv4-хвосте IPv6 один из четырёх десятичных октетов превышает255, например [::ffff:192.0.2.999].
Ipv4InIpv6TooFewPartsВ IPv4-хвосте IPv6 меньше четырёх частей, например [::ffff:192.0.2]. Здесь сокращение до127.1 не применяется.
InvalidUrlUnitСимвол или %-последовательность не соответствует URL unit; например пробел в пути. Возможны автоматическое кодирование и мягкая диагностика, это не всегда отказ.
SpecialSchemeMissingFollowingSolidusПосле special-схемы нет ожидаемой пары //, например https:shop.example. WHATWG может восстановить разделитель.
MissingSchemeNonRelativeUrlСхему не удалось определить, а подходящей базы для относительной ссылки нет. shop.example без https:// — не готовый абсолютный URL; opaque-база также ограничивает разрешение.
InvalidReverseSoldiusОбратная косая черта \ используется в special-URL как будто это /. Имя enum-case именно InvalidReverseSoldius; не исправляйте его написание в PHP-коде.
InvalidCredentialsИсходный URL содержит credentials. Это может быть мягкая диагностика принятого user:password@host; отдельная политика приложения вправе такое запрещать.
HostMissingSpecial-URL требует host, но его нет, например https://. file имеет собственные правила пустого host, не обобщайте правило HTTPS.
PortOutOfRangeЧисло порта превышает65535, например :70000. Это относится к WHATWG, а не общему RFC URI.
PortInvalidПорт записан не допустимыми десятичными цифрами, например :abc. Пустой порт — отдельная допустимая ситуация, а не abc.
FileInvalidWindowsDriveLetterОтносительная file-ссылка начинается с Windows drive letter при file-базе. Парсер применяет file-правила и может выдать мягкую диагностику.
FileInvalidWindowsDriveLetterHostВ file-URL буква диска оказалась в позиции host, например file://C:/docs. Она переносится согласно алгоритму file, но исходная запись диагностируется.
Распознать нестандартную запись IPv4Самостоятельный пример
<?php
declare(strict_types=1);

$errors = [];
$u = Uri\WhatWg\Url::parse('http://0x7f.1/', null, $errors);
echo $u?->getAsciiHost(), "\n";
echo $errors[0]->type === Uri\WhatWg\UrlValidationErrorType::Ipv4NonDecimalPart ? "Не десятичная запись\n" : "Другая запись\n";
echo $errors[0]->failure ? "Отказ\n" : "Мягкая диагностика\n";
Ожидаемый результат
127.0.0.1
Не десятичная запись
Мягкая диагностика

Никакого подключения к localhost нет: обрабатывается строка. При исходящих HTTP-запросах запрет частных/локальных IP должен учитывать конечный разрешённый адрес и перенаправления, а не только этот пример.

Выбрать понятное пользователю сообщение по типуСамостоятельный пример
<?php
declare(strict_types=1);

$errors = [];
Uri\WhatWg\Url::parse('https://shop.example:70000/', null, $errors);
$type = $errors[0]->type;
$message = match ($type) {
    Uri\WhatWg\UrlValidationErrorType::PortOutOfRange => 'Порт должен быть не больше 65535',
    Uri\WhatWg\UrlValidationErrorType::HostMissing => 'Укажите имя узла',
    default => 'Проверьте адрес',
};
echo $message, "\n";
echo count(Uri\WhatWg\UrlValidationErrorType::cases()), " типов в PHP 8.5\n";
Ожидаемый результат
Порт должен быть не больше 65535
29 типов в PHP 8.5

match сравнивает case по значению и типу. default оставляет общее сообщение для остальных причин. Не копируем низкоуровневую диагностику в HTML; экранирование и политика интерфейса остаются отдельным слоем.

Практика: добавьте ветку PortInvalid с фразой «Порт записывается десятичными цифрами» и проверьте строку https://shop.example:abc/. Ожидаемая политика — отказ, сообщение PortInvalid; остальные case продолжат работать через default.

От синтаксиса к правилам конкретного приложения

Предположим, кнопка может вести только на справку нашего магазина. Нужны не только синтаксически корректный URL, но и явные условия: https, ровно shop.example, обычный порт, без credentials. Ни один парсер сам не знает этих требований. Пример ниже только принимает или отклоняет строки и ничего не загружает.

Политика ссылки магазина
  1. Строка кандидата
  2. Url::parse → объект/null
  3. schema + ASCII host + port + credentials
  4. Вернуть bool; перехода ещё нет

Перед функцией разберём новые элементы: function объявляет именованную операцию; string $input — её строковый параметр; : bool обещает true/false. return возвращает ответ вызывающему выражению. && требует выполнения всех условий; null — отсутствие значения. Синтаксис функции подробнее: параметры и return.

Применить узкую политику адреса магазинаСамостоятельный пример
<?php
declare(strict_types=1);

function isStoreLink(string $input): bool {
    $errors = [];
    $url = Uri\WhatWg\Url::parse($input, null, $errors);
    return $url !== null
        && $errors === []
        && $url->getScheme() === 'https'
        && $url->getAsciiHost() === 'shop.example'
        && $url->getPort() === null
        && $url->getUsername() === null
        && $url->getPassword() === null;
}
echo isStoreLink('https://shop.example/help') ? "Принято\n" : "Отклонено\n";
echo isStoreLink('https://shop.example@other.example/help') ? "Принято\n" : "Отклонено\n";
echo isStoreLink('https:shop.example') ? "Принято\n" : "Отклонено\n";
Ожидаемый результат
Принято
Отклонено
Отклонено

Первый вызов передаёт строку в $input, parse создаёт $url, return отдаёт true исходному выражению echo. Второй host — other.example, третий имеет мягкую диагностику; наша строгая политика отклоняет оба. Это лишь правила входной ссылки, не полная SSRF-защита HTTP-клиента.

При исходящем HTTP дополнительно контролируют DNS-результат/конечный IP, перенаправления на каждом шаге, допустимые схемы/порты самого клиента, таймауты и размеры ответа. Между проверкой и использованием не должно быть другого парсера с иным прочтением. Нельзя передавать непроверенный исходный ввод после проверки нормализованной копии. Для HTML и журналов также нужны отдельные правила вывода и скрытия секретов.

Практика: функция ссылок пагинации

Соберите ссылки пагинации каталога, сохранив одну доверенную базу. Требования: страница положительная; query сформирован из значений, а не склеен с сырым вводом; базовый объект не изменяется. Сначала предскажите две итоговые строки, затем запустите предложенное решение.

Вызов функции и возврат
  1. catalogPage($base, 2)
  2. Параметры: $base, $page=2
  3. http_build_query(page=2) → withQuery
  4. return новый Url → toAsciiString в echo
Решение: две независимые страницы каталогаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url;

function catalogPage(Url $base, int $page): Url {
    if ($page < 1) {
        throw new InvalidArgumentException('Номер страницы должен быть положительным');
    }
    $query = http_build_query(['page' => $page], '', '&', PHP_QUERY_RFC3986);
    return $base->withQuery($query);
}
$base = new Url('https://shop.example/catalog');
echo catalogPage($base, 2)->toAsciiString(), "\n";
echo catalogPage($base, 3)->toAsciiString(), "\n";
echo $base->toAsciiString(), "\n";
try { catalogPage($base, 0); }
catch (InvalidArgumentException $e) { echo "Номер страницы отклонён\n"; }
Ожидаемый результат
https://shop.example/catalog?page=2
https://shop.example/catalog?page=3
https://shop.example/catalog
Номер страницы отклонён

Url $base требует готовый объект, int $page — целое число. if проверяет условие, throw создаёт отказ приложения до сборки URL, catch обрабатывает его. Функция заменяет всю query; для сохранения старых параметров нужен отдельный договор о слиянии, не скрытая потеря фильтров.

Развитие упражнения: передайте категорию отдельным параметром и добавьте её в массив http_build_query перед page. Для tools и2 ожидается https://shop.example/catalog?category=tools&page=2. Не разрешайте заменять host через этот параметр. Для перехода из относительной ссылки используйте resolve и проверьте конечный host; для нужного component — соответствующий with.

Полный справочник методов URI

Все методы этой главы доступны с PHP 8.5.0. Выбирайте RFC и WHATWG по договору источника и следующего потребителя адреса. Между ними нет универсального «лучший для любого URI»; parse_url — прежний разбор компонентов, но не drop-in реализация этих стандартов. Полный справочник ниже включает getter, raw getter, with-операции, сравнение, сериализацию и диагностические конструкторы.

ЗадачаНачальные карточки
Разобрать или отклонитьUri\Rfc3986\Uri::parse / Uri\WhatWg\Url::parse
Относительная ссылкаUri\Rfc3986\Uri::resolve / Uri\WhatWg\Url::resolve
Домен/кодировкаUri\Rfc3986\Uri::getHost / Uri\WhatWg\Url::getAsciiHost / Uri\WhatWg\Url::getUnicodeHost
Обновить параметрыUri\Rfc3986\Uri::withQuery / Uri\WhatWg\Url::withQuery
Сравнить адресаUri\Rfc3986\Uri::equals / Uri\WhatWg\Url::equals
Разобрать отказUri\WhatWg\InvalidUrlException::__construct / Uri\WhatWg\UrlValidationError::__construct

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

Uri\Rfc3986\Uri::getSchemeПроверить протокол ссылки каталога до дальнейшей обработки.

PHP 8.5.0+ · uri

getScheme(): ?string

Проверить протокол ссылки каталога до дальнейшей обработки.

Запись getScheme(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; имя схемы без двоеточия, нижний регистр; null у относительного URI.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Проверить протокол ссылки каталога до дальнейшей обработки.
  1. HTTPS://Shop.Example/p
  2. getScheme() выделяет компонент
  3. https
  4. $value → echo, без HTTP
Проверить протокол ссылки каталога до дальнейшей обработки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('HTTPS://Shop.Example/p');
$value = $address->getScheme();
echo $value, "\n";
Ожидаемый результат
https

new создаёт объект из буквальной строки. $address->getScheme() читает один компонент; $value получает 'https', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Проверить протокол ссылки каталога до дальнейшей обработки. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('//shop.example/p');
echo $u->getScheme() === null ? "Нужна базовая схема\n" : "Схема есть\n";
Ожидаемый результат
Нужна базовая схема

Адрес с // содержит host, но ещё не задаёт схему. Не подставляйте https без политики приложения.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawScheme.

Uri\Rfc3986\Uri::getRawSchemeПоказать, как автор исходной ссылки записал схему.

PHP 8.5.0+ · uri

getRawScheme(): ?string

Показать, как автор исходной ссылки записал схему.

Запись getRawScheme(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; исходный регистр схемы без :, либо null.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Показать, как автор исходной ссылки записал схему.
  1. HTTPS://shop.example/p
  2. getRawScheme() выделяет компонент
  3. HTTPS
  4. $value → echo, без HTTP
Показать, как автор исходной ссылки записал схему.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('HTTPS://shop.example/p');
$value = $address->getRawScheme();
echo $value, "\n";
Ожидаемый результат
HTTPS

new создаёт объект из буквальной строки. $address->getRawScheme() читает один компонент; $value получает 'HTTPS', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Показать, как автор исходной ссылки записал схему. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('HtTpS://shop.example/p');
echo $u->getRawScheme(), ' -> ', $u->getScheme(), "\n";
Ожидаемый результат
HtTpS -> https

Raw полезен для диагностики представления. Решение «разрешён HTTPS» принимайте по нормализованной схеме, не по её исходному регистру.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getScheme.

Uri\Rfc3986\Uri::getHostВыделить нормализованное имя узла ссылки, не спутать его с пользователем.

PHP 8.5.0+ · uri

getHost(): ?string

Выделить нормализованное имя узла ссылки, не спутать его с пользователем.

Запись getHost(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; reg-name, IPv4 либо IPv6/IPFuture в квадратных скобках; null без authority, пустая строка при пустом host.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Выделить нормализованное имя узла ссылки, не спутать его с пользователем.
  1. https://trusted.example@Shop.Example/p
  2. getHost() выделяет компонент
  3. shop.example
  4. $value → echo, без HTTP
Выделить нормализованное имя узла ссылки, не спутать его с пользователем.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://trusted.example@Shop.Example/p');
$value = $address->getHost();
echo $value, "\n";
Ожидаемый результат
shop.example

new создаёт объект из буквальной строки. $address->getHost() читает один компонент; $value получает 'shop.example', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Выделить нормализованное имя узла ссылки, не спутать его с пользователем. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('mailto:sales@shop.example');
echo $u->getHost() === null ? "Host отсутствует\n" : $u->getHost();
echo $u->getPath(), "\n";
Ожидаемый результат
Host отсутствует
sales@shop.example

Знак @ внутри mailto не создаёт host-компонент. RFC не превращает Unicode-домен в IDNA; браузерный вариант — getAsciiHost.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawHost.

Uri\Rfc3986\Uri::getRawHostСопоставить введённое написание домена с нормализованным.

PHP 8.5.0+ · uri

getRawHost(): ?string

Сопоставить введённое написание домена с нормализованным.

Запись getRawHost(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; исходное написание host, IPv6 со скобками; null/пустая строка сохраняют различие.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Сопоставить введённое написание домена с нормализованным.
  1. https://Sh%6fp.Example/p
  2. getRawHost() выделяет компонент
  3. Sh%6fp.Example
  4. $value → echo, без HTTP
Сопоставить введённое написание домена с нормализованным.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://Sh%6fp.Example/p');
$value = $address->getRawHost();
echo $value, "\n";
Ожидаемый результат
Sh%6fp.Example

new создаёт объект из буквальной строки. $address->getRawHost() читает один компонент; $value получает 'Sh%6fp.Example', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Сопоставить введённое написание домена с нормализованным. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://[2001:DB8::1]/');
echo $u->getRawHost(), "\n", $u->getHost(), "\n";
Ожидаемый результат
[2001:DB8::1]
[2001:db8::1]

Raw getter сохраняет эту запись IPv6; toRawString заново сериализует IPv6 развёрнуто. Поэтому raw не обещает побайтовый архив всей входной строки.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getHost.

Uri\Rfc3986\Uri::getPathПолучить маршрут карточки после устранения навигационных сегментов.

PHP 8.5.0+ · uri

getPath(): string

Получить маршрут карточки после устранения навигационных сегментов.

Запись getPath(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результатstring; путь без query/fragment, иногда пустой; нормализованный, без полного percent-decoding.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Получить маршрут карточки после устранения навигационных сегментов.
  1. https://shop.example/catalog/../%7ecard
  2. getPath() выделяет компонент
  3. /~card
  4. $value → echo, без HTTP
Получить маршрут карточки после устранения навигационных сегментов.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example/catalog/../%7ecard');
$value = $address->getPath();
echo $value, "\n";
Ожидаемый результат
/~card

new создаёт объект из буквальной строки. $address->getPath() читает один компонент; $value получает '/~card', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Получить маршрут карточки после устранения навигационных сегментов. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/items/a%2fb');
echo $u->getPath(), "\n";
echo $u->getPath() === '/items/a/b' ? "два сегмента\n" : "кодированный разделитель сохранён\n";
Ожидаемый результат
/items/a%2Fb
кодированный разделитель сохранён

После rawurldecode %2F стал бы настоящим /. Это меняет структуру; не декодируйте маршрут целиком перед проверкой правил доступа.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawPath.

Uri\Rfc3986\Uri::getRawPathРазобрать, почему две входные ссылки выглядят по-разному.

PHP 8.5.0+ · uri

getRawPath(): string

Разобрать, почему две входные ссылки выглядят по-разному.

Запись getRawPath(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результатstring; путь до нормализации, пустой при его отсутствии; без query и fragment.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Разобрать, почему две входные ссылки выглядят по-разному.
  1. https://shop.example/catalog/../%7ecard
  2. getRawPath() выделяет компонент
  3. /catalog/../%7ecard
  4. $value → echo, без HTTP
Разобрать, почему две входные ссылки выглядят по-разному.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example/catalog/../%7ecard');
$value = $address->getRawPath();
echo $value, "\n";
Ожидаемый результат
/catalog/../%7ecard

new создаёт объект из буквальной строки. $address->getRawPath() читает один компонент; $value получает '/catalog/../%7ecard', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Разобрать, почему две входные ссылки выглядят по-разному. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/a/../price%20list');
echo $u->getRawPath(), "\n", $u->getPath(), "\n";
Ожидаемый результат
/a/../price%20list
/price%20list

Сохраняем исходный маршрут для локального разбора ошибки. Он не является безопасным путём файловой системы; %20 остаётся кодированным даже в normalized getter.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getPath.

Uri\Rfc3986\Uri::getQueryОтделить параметры поиска от маршрута и якоря.

PHP 8.5.0+ · uri

getQuery(): ?string

Отделить параметры поиска от маршрута и якоря.

Запись getQuery(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; query без первого ?, null если ? отсутствует, "" если запрос явно пуст.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Отделить параметры поиска от маршрута и якоря.
  1. https://shop.example/find?q=%7etool&part=a%2fb#top
  2. getQuery() выделяет компонент
  3. q=~tool&part=a%2Fb
  4. $value → echo, без HTTP
Отделить параметры поиска от маршрута и якоря.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example/find?q=%7etool&part=a%2fb#top');
$value = $address->getQuery();
echo $value, "\n";
Ожидаемый результат
q=~tool&part=a%2Fb

new создаёт объект из буквальной строки. $address->getQuery() читает один компонент; $value получает 'q=~tool&part=a%2Fb', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Отделить параметры поиска от маршрута и якоря. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

foreach (['https://shop.example/p', 'https://shop.example/p?', 'https://shop.example/p?0'] as $s) {
    $q = (new Uri($s))->getQuery();
    echo $q === null ? 'отсутствует' : ($q === '' ? 'пустой' : $q), "\n";
}
Ожидаемый результат
отсутствует
пустой
0

Строгие сравнения === сохраняют "0". Getter не разбирает пары параметров: parse_str нужен только если договор query — форма PHP, с учётом его преобразования ключей.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawQuery.

Uri\Rfc3986\Uri::getRawQueryСохранить написание query для проверки подписанного адреса.

PHP 8.5.0+ · uri

getRawQuery(): ?string

Сохранить написание query для проверки подписанного адреса.

Запись getRawQuery(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; query без ?, до нормализации; null и "" различаются.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Сохранить написание query для проверки подписанного адреса.
  1. https://shop.example/find?q=%7etool&part=a%2fb
  2. getRawQuery() выделяет компонент
  3. q=%7etool&part=a%2fb
  4. $value → echo, без HTTP
Сохранить написание query для проверки подписанного адреса.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example/find?q=%7etool&part=a%2fb');
$value = $address->getRawQuery();
echo $value, "\n";
Ожидаемый результат
q=%7etool&part=a%2fb

new создаёт объект из буквальной строки. $address->getRawQuery() читает один компонент; $value получает 'q=%7etool&part=a%2fb', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Сохранить написание query для проверки подписанного адреса. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/find?q=a+b&q=a%20b');
echo $u->getRawQuery(), "\n";
echo $u->getQuery(), "\n";
Ожидаемый результат
q=a+b&q=a%20b
q=a+b&q=a%20b

Ни +, ни порядок, ни повторные q не исчезли. Криптографическая подпись следует точному протоколу: даже raw URI не гарантирует сохранение всего исходного адреса; исходную строку храните отдельно.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getQuery.

Uri\Rfc3986\Uri::getFragmentПолучить имя раздела для локальной навигации справочника.

PHP 8.5.0+ · uri

getFragment(): ?string

Получить имя раздела для локальной навигации справочника.

Запись getFragment(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; часть после # без самого #; нормализованная, null без #, "" при пустом #.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Получить имя раздела для локальной навигации справочника.
  1. https://shop.example/help#%64elivery
  2. getFragment() выделяет компонент
  3. delivery
  4. $value → echo, без HTTP
Получить имя раздела для локальной навигации справочника.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example/help#%64elivery');
$value = $address->getFragment();
echo $value, "\n";
Ожидаемый результат
delivery

new создаёт объект из буквальной строки. $address->getFragment() читает один компонент; $value получает 'delivery', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Получить имя раздела для локальной навигации справочника. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/help#part%2f2');
echo $u->getFragment(), "\n";
echo $u->withFragment(null)->toString(), "\n";
Ожидаемый результат
part%2F2
https://shop.example/help

Fragment отделён от адреса ресурса; HTTP-клиенты обычно не передают его серверу. Существование такого id в HTML парсер не проверяет.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawFragment.

Uri\Rfc3986\Uri::getRawFragmentПоказать исходное кодирование якоря из импортированной ссылки.

PHP 8.5.0+ · uri

getRawFragment(): ?string

Показать исходное кодирование якоря из импортированной ссылки.

Запись getRawFragment(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; fragment без # до нормализации, null либо пустая строка по входу.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Показать исходное кодирование якоря из импортированной ссылки.
  1. https://shop.example/help#%64elivery
  2. getRawFragment() выделяет компонент
  3. %64elivery
  4. $value → echo, без HTTP
Показать исходное кодирование якоря из импортированной ссылки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example/help#%64elivery');
$value = $address->getRawFragment();
echo $value, "\n";
Ожидаемый результат
%64elivery

new создаёт объект из буквальной строки. $address->getRawFragment() читает один компонент; $value получает '%64elivery', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Показать исходное кодирование якоря из импортированной ссылки. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/help#part%2f2');
echo $u->getRawFragment(), ' -> ', $u->getFragment(), "\n";
Ожидаемый результат
part%2f2 -> part%2F2

Изменился только регистр hex в %2f. Для сравнения представлений выводим обе версии; это не извлечение текста HTML-раздела.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getFragment.

Uri\Rfc3986\Uri::getUsernameРаспознать встроенные учётные данные перед показом ссылки.

PHP 8.5.0+ · uri

getUsername(): ?string

Распознать встроенные учётные данные перед показом ссылки.

Запись getUsername(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; часть userinfo до первого буквального :, нормализованная; "" если имя пусто, null если нет userinfo.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Распознать встроенные учётные данные перед показом ссылки.
  1. https://%61nna:demo@shop.example/p
  2. getUsername() выделяет компонент
  3. anna
  4. $value → echo, без HTTP
Распознать встроенные учётные данные перед показом ссылки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://%61nna:demo@shop.example/p');
$value = $address->getUsername();
echo $value, "\n";
Ожидаемый результат
anna

new создаёт объект из буквальной строки. $address->getUsername() читает один компонент; $value получает 'anna', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Распознать встроенные учётные данные перед показом ссылки. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

foreach (['https://shop.example/', 'https://:demo@shop.example/'] as $s) {
    $name = (new Uri($s))->getUsername();
    echo $name === null ? 'userinfo отсутствует' : ($name === '' ? 'имя пустое' : $name), "\n";
}
Ожидаемый результат
userinfo отсутствует
имя пустое

Пустое имя не значит отсутствие пароля. Не показывайте целый URI в публичном журнале; пример использует только вымышленные данные.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawUsername.

Uri\Rfc3986\Uri::getRawUsernameРазобрать исходную запись логина в диагностическом стенде.

PHP 8.5.0+ · uri

getRawUsername(): ?string

Разобрать исходную запись логина в диагностическом стенде.

Запись getRawUsername(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; имя до первого буквального :, без нормализации; null без userinfo.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Разобрать исходную запись логина в диагностическом стенде.
  1. https://%61nna:demo@shop.example/
  2. getRawUsername() выделяет компонент
  3. %61nna
  4. $value → echo, без HTTP
Разобрать исходную запись логина в диагностическом стенде.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://%61nna:demo@shop.example/');
$value = $address->getRawUsername();
echo $value, "\n";
Ожидаемый результат
%61nna

new создаёт объект из буквальной строки. $address->getRawUsername() читает один компонент; $value получает '%61nna', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Разобрать исходную запись логина в диагностическом стенде. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://team%3Awest:demo@shop.example/');
echo $u->getRawUsername(), "\n", $u->getUsername(), "\n";
Ожидаемый результат
team%3Awest
team%3Awest

%3A — часть имени, а не разделитель пароля. Нормализация не раскрывает зарезервированное двоеточие.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getUsername.

Uri\Rfc3986\Uri::getPasswordПроверить наличие пароля в импортированной ссылке без его публикации.

PHP 8.5.0+ · uri

getPassword(): ?string

Проверить наличие пароля в импортированной ссылке без его публикации.

Запись getPassword(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; часть userinfo после первого буквального :, нормализованная; "" у userinfo без пароля, null без userinfo.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Проверить наличие пароля в импортированной ссылке без его публикации.
  1. https://anna:d%65mo@shop.example/
  2. getPassword() выделяет компонент
  3. demo
  4. $value → echo, без HTTP
Проверить наличие пароля в импортированной ссылке без его публикации.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://anna:d%65mo@shop.example/');
$value = $address->getPassword();
echo $value, "\n";
Ожидаемый результат
demo

new создаёт объект из буквальной строки. $address->getPassword() читает один компонент; $value получает 'demo', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Проверить наличие пароля в импортированной ссылке без его публикации. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

foreach (['https://shop.example/', 'https://anna@shop.example/'] as $s) {
    $password = (new Uri($s))->getPassword();
    echo $password === null ? 'userinfo отсутствует' : ($password === '' ? 'пароль пустой' : 'пароль задан'), "\n";
}
Ожидаемый результат
userinfo отсутствует
пароль пустой

Значение выводится только в первом учебном вызове с фиктивным demo. В реальном журнале выводите признак, не секрет; SensitiveParameter не скрывает возвращённую строку.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawPassword.

Uri\Rfc3986\Uri::getRawPasswordПроверить кодирование тестового пароля, не меняя его структуру.

PHP 8.5.0+ · uri

getRawPassword(): ?string

Проверить кодирование тестового пароля, не меняя его структуру.

Запись getRawPassword(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; хвост userinfo после первого буквального :, до нормализации; null/"" как у getPassword.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Проверить кодирование тестового пароля, не меняя его структуру.
  1. https://anna:d%65mo@shop.example/
  2. getRawPassword() выделяет компонент
  3. d%65mo
  4. $value → echo, без HTTP
Проверить кодирование тестового пароля, не меняя его структуру.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://anna:d%65mo@shop.example/');
$value = $address->getRawPassword();
echo $value, "\n";
Ожидаемый результат
d%65mo

new создаёт объект из буквальной строки. $address->getRawPassword() читает один компонент; $value получает 'd%65mo', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Проверить кодирование тестового пароля, не меняя его структуру. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://anna:demo%3Awest@shop.example/');
echo $u->getRawPassword(), "\n", $u->getPassword(), "\n";
Ожидаемый результат
demo%3Awest
demo%3Awest

Кодированное двоеточие остаётся частью пароля. URI не подтверждает эти учётные данные и не выполняет вход.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getPassword.

Uri\Rfc3986\Uri::getUserInfoУдалить весь блок учётных данных, не перепутав его с host.

PHP 8.5.0+ · uri

getUserInfo(): ?string

Удалить весь блок учётных данных, не перепутав его с host.

Запись getUserInfo(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; весь userinfo без @, нормализованный; null без блока, "" при @ без содержимого.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Удалить весь блок учётных данных, не перепутав его с host.
  1. https://%61nna:d%65mo@shop.example/
  2. getUserInfo() выделяет компонент
  3. anna:demo
  4. $value → echo, без HTTP
Удалить весь блок учётных данных, не перепутав его с host.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://%61nna:d%65mo@shop.example/');
$value = $address->getUserInfo();
echo $value, "\n";
Ожидаемый результат
anna:demo

new создаёт объект из буквальной строки. $address->getUserInfo() читает один компонент; $value получает 'anna:demo', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Удалить весь блок учётных данных, не перепутав его с host. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://anna:demo@shop.example/p');
echo $u->getUserInfo() !== null ? "Нужна очистка\n" : "Без userinfo\n";
echo $u->withUserInfo(null)->toString(), "\n";
Ожидаемый результат
Нужна очистка
https://shop.example/p

Удаление userinfo не удаляет токены из query/path. Для журналов нужен собственный разрешённый набор полей.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getRawUserInfo.

Uri\Rfc3986\Uri::getRawUserInfoСопоставить исходный и нормализованный блок учётных данных на фиктивной строке.

PHP 8.5.0+ · uri

getRawUserInfo(): ?string

Сопоставить исходный и нормализованный блок учётных данных на фиктивной строке.

Запись getRawUserInfo(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; userinfo без @, до нормализации; не равен всему authority.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Сопоставить исходный и нормализованный блок учётных данных на фиктивной строке.
  1. https://%61nna:d%65mo@shop.example/
  2. getRawUserInfo() выделяет компонент
  3. %61nna:d%65mo
  4. $value → echo, без HTTP
Сопоставить исходный и нормализованный блок учётных данных на фиктивной строке.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://%61nna:d%65mo@shop.example/');
$value = $address->getRawUserInfo();
echo $value, "\n";
Ожидаемый результат
%61nna:d%65mo

new создаёт объект из буквальной строки. $address->getRawUserInfo() читает один компонент; $value получает '%61nna:d%65mo', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Сопоставить исходный и нормализованный блок учётных данных на фиктивной строке. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://team%3Awest:demo@shop.example/');
echo $u->getRawUserInfo(), "\n", $u->getUsername(), "\n";
Ожидаемый результат
team%3Awest:demo
team%3Awest

Authority включает также host и port. Разделение логина и пароля происходит по буквальному :, не по %3A.

Raw-компоненты не предназначены для обхода валидации. Для полного архива сохраняйте исходный текст отдельно; относительная база и последующие with-вызовы уже меняют адрес.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getUserInfo.

Uri\Rfc3986\Uri::getPortПоказать явно записанный порт учебного сервиса.

PHP 8.5.0+ · uri

getPort(): ?int

Показать явно записанный порт учебного сервиса.

Запись getPort(): ?int описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?int; десятичное число без :, null если порт отсутствует или его текст пуст. RFC не удаляет стандартный порт.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Показать явно записанный порт учебного сервиса.
  1. https://shop.example:08443/p
  2. getPort() выделяет компонент
  3. 8443
  4. $value → echo, без HTTP
Показать явно записанный порт учебного сервиса.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example:08443/p');
$value = $address->getPort();
echo $value, "\n";
Ожидаемый результат
8443

new создаёт объект из буквальной строки. $address->getPort() читает один компонент; $value получает '8443', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Показать явно записанный порт учебного сервиса. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example:70000/');
$port = $u->getPort();
echo $port, "\n";
echo $port !== null && $port > 65535 ? "Не сетевой порт TCP/UDP\n" : "В диапазоне\n";
Ожидаемый результат
70000
Не сетевой порт TCP/UDP

В PHP 8.5.11 RFC принимает неотрицательный порт, помещающийся в PHP int; это шире сетевого диапазона. Парсер WHATWG ограничивает порт 65535. Очень длинная цифровая запись тоже может быть отвергнута реализацией.

Нормализация RFC: схема/host в нижний регистр; hex в %-последовательностях в верхний; percent-encoded unreserved ASCII раскодируются; в пути убираются сегменты «.» и «..». Зарезервированный %2F не превращается в разделитель /. Это не полная URL-декодировка и не проверка доступности сервера.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::toString.

Uri\WhatWg\Url::getSchemeОпределить схему готовой браузерной ссылки.

PHP 8.5.0+ · uri

getScheme(): string

Определить схему готовой браузерной ссылки.

Запись getScheme(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результатstring; всегда схема без :, нижний регистр. У корректного WHATWG Url нет отсутствующей схемы.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Определить схему готовой браузерной ссылки.
  1. HTTPS://shop.example/p
  2. getScheme() выделяет компонент
  3. https
  4. $value → echo, без HTTP
Определить схему готовой браузерной ссылки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('HTTPS://shop.example/p');
$value = $address->getScheme();
echo $value, "\n";
Ожидаемый результат
https

new создаёт объект из буквальной строки. $address->getScheme() читает один компонент; $value получает 'https', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Определить схему готовой браузерной ссылки. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('mailto:sales@shop.example');
echo $u->getScheme() === 'https' ? "Веб-ссылка\n" : "Другая схема\n";
Ожидаемый результат
Другая схема

Валидный URL не обязательно HTTP(S). Проверяйте нужную схему отдельно; не открывайте произвольные схемы через внешние программы.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getAsciiHostПолучить форму международного домена для машинного сравнения.

PHP 8.5.0+ · uri

getAsciiHost(): ?string

Получить форму международного домена для машинного сравнения.

Запись getAsciiHost(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; сериализованный host: ASCII/IDNA для доменов, IPv4 либо IPv6 со скобками; null если host отсутствует, "" при пустом host.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Получить форму международного домена для машинного сравнения.
  1. https://пример.рф/catalog
  2. getAsciiHost() выделяет компонент
  3. xn--e1afmkfd.xn--p1ai
  4. $value → echo, без HTTP
Получить форму международного домена для машинного сравнения.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://пример.рф/catalog');
$value = $address->getAsciiHost();
echo $value, "\n";
Ожидаемый результат
xn--e1afmkfd.xn--p1ai

new создаёт объект из буквальной строки. $address->getAsciiHost() читает один компонент; $value получает 'xn--e1afmkfd.xn--p1ai', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Получить форму международного домена для машинного сравнения. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('http://0x7f.1/');
echo $u->getAsciiHost(), "\n";
echo (new Url('mailto:sales@shop.example'))->getAsciiHost() === null ? "Нет host\n" : "Есть host\n";
Ожидаемый результат
127.0.0.1
Нет host

WHATWG распознаёт альтернативную запись IPv4. Проверка безопасности по исходному тексту host ненадёжна. Getter не выполняет DNS.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getUnicodeHostПоказать человеку международный домен, сохранив машинную форму рядом.

PHP 8.5.0+ · uri

getUnicodeHost(): ?string

Показать человеку международный домен, сохранив машинную форму рядом.

Запись getUnicodeHost(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; домен в Unicode; IPv4/IPv6 остаются адресами, null без host.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Показать человеку международный домен, сохранив машинную форму рядом.
  1. https://xn--e1afmkfd.xn--p1ai/p
  2. getUnicodeHost() выделяет компонент
  3. пример.рф
  4. $value → echo, без HTTP
Показать человеку международный домен, сохранив машинную форму рядом.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://xn--e1afmkfd.xn--p1ai/p');
$value = $address->getUnicodeHost();
echo $value, "\n";
Ожидаемый результат
пример.рф

new создаёт объект из буквальной строки. $address->getUnicodeHost() читает один компонент; $value получает 'пример.рф', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Показать человеку международный домен, сохранив машинную форму рядом. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://пример.рф/p');
echo $u->getUnicodeHost(), "\n", $u->getAsciiHost(), "\n";
Ожидаемый результат
пример.рф
xn--e1afmkfd.xn--p1ai

Визуально похожие буквы разных алфавитов не доказывают доверие. Для HTML экранируйте отображаемую строку; машинный allowlist сравнивает каноническое ASCII-имя.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getPathВыделить маршрут карточки после браузерного разбора.

PHP 8.5.0+ · uri

getPath(): string

Выделить маршрут карточки после браузерного разбора.

Запись getPath(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результатstring; pathname, у HTTP(S) пустой путь обычно сериализуется как /. Percent-encoding не декодируется полностью.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Выделить маршрут карточки после браузерного разбора.
  1. https://shop.example/a/../price%20list
  2. getPath() выделяет компонент
  3. /price%20list
  4. $value → echo, без HTTP
Выделить маршрут карточки после браузерного разбора.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://shop.example/a/../price%20list');
$value = $address->getPath();
echo $value, "\n";
Ожидаемый результат
/price%20list

new создаёт объект из буквальной строки. $address->getPath() читает один компонент; $value получает '/price%20list', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Выделить маршрут карточки после браузерного разбора. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/%7ecard/a%2fb');
echo $u->getPath(), "\n";
echo (new Url('https://shop.example'))->getPath(), "\n";
Ожидаемый результат
/%7ecard/a%2fb
/

WHATWG не применяет к percent-encoding те же правила нормализации, что RFC getter: %7e и регистр %2f здесь сохраняются. Это URL-путь, не путь к локальному файлу.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getQueryИзвлечь строку поисковых параметров без смешения с якорем.

PHP 8.5.0+ · uri

getQuery(): ?string

Извлечь строку поисковых параметров без смешения с якорем.

Запись getQuery(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; query без ?, null если отсутствует, "" если введён голый ?; + остаётся +.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Извлечь строку поисковых параметров без смешения с якорем.
  1. https://shop.example/find?q=%7etool&part=a%2fb#top
  2. getQuery() выделяет компонент
  3. q=%7etool&part=a%2fb
  4. $value → echo, без HTTP
Извлечь строку поисковых параметров без смешения с якорем.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://shop.example/find?q=%7etool&part=a%2fb#top');
$value = $address->getQuery();
echo $value, "\n";
Ожидаемый результат
q=%7etool&part=a%2fb

new создаёт объект из буквальной строки. $address->getQuery() читает один компонент; $value получает 'q=%7etool&part=a%2fb', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Извлечь строку поисковых параметров без смешения с якорем. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

foreach (['https://shop.example/p', 'https://shop.example/p?', 'https://shop.example/p?0'] as $s) {
    $q = (new Url($s))->getQuery();
    echo $q === null ? 'отсутствует' : ($q === '' ? 'пустой' : $q), "\n";
}
Ожидаемый результат
отсутствует
пустой
0

Не используйте if ($q) для проверки наличия: строка "0" ложна. Разбор в поля — отдельный договор, getter оставляет повторы параметров.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getFragmentПолучить браузерный якорь для карточки раздела.

PHP 8.5.0+ · uri

getFragment(): ?string

Получить браузерный якорь для карточки раздела.

Запись getFragment(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; fragment без #, null без fragment и "" при голом #; %-кодирование сохраняется.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Получить браузерный якорь для карточки раздела.
  1. https://shop.example/help#part%202
  2. getFragment() выделяет компонент
  3. part%202
  4. $value → echo, без HTTP
Получить браузерный якорь для карточки раздела.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://shop.example/help#part%202');
$value = $address->getFragment();
echo $value, "\n";
Ожидаемый результат
part%202

new создаёт объект из буквальной строки. $address->getFragment() читает один компонент; $value получает 'part%202', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Получить браузерный якорь для карточки раздела. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/help#%64elivery');
echo $u->getFragment(), "\n";
echo $u->withFragment(null)->toAsciiString(), "\n";
Ожидаемый результат
%64elivery
https://shop.example/help

Отделили якорь для списка ресурсов. Сервер HTTP не получает fragment как часть request target; UI должен отдельно проверять существование раздела.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getUsernameОпределить, что ссылка содержит встроенное имя пользователя.

PHP 8.5.0+ · uri

getUsername(): ?string

Определить, что ссылка содержит встроенное имя пользователя.

Запись getUsername(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; percent-encoded username; null когда и username, и password пусты, "" при пустом имени и непустом пароле.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Определить, что ссылка содержит встроенное имя пользователя.
  1. https://%61nna:demo@shop.example/
  2. getUsername() выделяет компонент
  3. %61nna
  4. $value → echo, без HTTP
Определить, что ссылка содержит встроенное имя пользователя.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://%61nna:demo@shop.example/');
$value = $address->getUsername();
echo $value, "\n";
Ожидаемый результат
%61nna

new создаёт объект из буквальной строки. $address->getUsername() читает один компонент; $value получает '%61nna', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Определить, что ссылка содержит встроенное имя пользователя. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

foreach (['https://@shop.example/', 'https://:demo@shop.example/'] as $s) {
    $name = (new Url($s))->getUsername();
    echo $name === null ? 'credentials отсутствуют' : ($name === '' ? 'имя пустое' : 'имя задано'), "\n";
}
Ожидаемый результат
credentials отсутствуют
имя пустое

WHATWG удаляет пустой @ при сериализации. Это отличается от RFC userinfo. Не путайте отсутствие имени с отсутствием всех credentials.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getPasswordОтметить пароль в импортируемой ссылке и скрыть его в отчёте.

PHP 8.5.0+ · uri

getPassword(): ?string

Отметить пароль в импортируемой ссылке и скрыть его в отчёте.

Запись getPassword(): ?string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?string; percent-encoded password, null когда оба поля credentials пусты, "" если задано лишь имя.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Отметить пароль в импортируемой ссылке и скрыть его в отчёте.
  1. https://anna:d%65mo@shop.example/
  2. getPassword() выделяет компонент
  3. d%65mo
  4. $value → echo, без HTTP
Отметить пароль в импортируемой ссылке и скрыть его в отчёте.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://anna:d%65mo@shop.example/');
$value = $address->getPassword();
echo $value, "\n";
Ожидаемый результат
d%65mo

new создаёт объект из буквальной строки. $address->getPassword() читает один компонент; $value получает 'd%65mo', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Отметить пароль в импортируемой ссылке и скрыть его в отчёте. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

foreach (['https://shop.example/', 'https://anna@shop.example/'] as $s) {
    $password = (new Url($s))->getPassword();
    echo $password === null ? 'нет credentials' : ($password === '' ? 'пароль пустой' : 'пароль скрыт'), "\n";
}
Ожидаемый результат
нет credentials
пароль пустой

Демонстрационный demo не является настоящим секретом. Getter и debugInfo не редактируют пароль автоматически; SensitiveParameter защищает аргумент трассировки, а не содержимое объекта.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::getPortРазличить стандартный и явно нестандартный порт веб-сервиса.

PHP 8.5.0+ · uri

getPort(): ?int

Различить стандартный и явно нестандартный порт веб-сервиса.

Запись getPort(): ?int описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет; () обязательны.
Результат?int; явный нестандартный порт 0…65535, null при отсутствии или стандартном порте данной special-схемы.
ОшибкиДля уже корректно созданного объекта обычного отказа данных нет. Неверное число/тип аргументов нарушает договор PHP; ошибки создания рассматриваются отдельно. Внутренний сбой RFC-парсера может дать Uri\UriError, это не «компонент отсутствует».
ВерсияPHP 8.5.0; расширение uri.
Различить стандартный и явно нестандартный порт веб-сервиса.
  1. https://shop.example:8443/p
  2. getPort() выделяет компонент
  3. 8443
  4. $value → echo, без HTTP
Различить стандартный и явно нестандартный порт веб-сервиса.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://shop.example:8443/p');
$value = $address->getPort();
echo $value, "\n";
Ожидаемый результат
8443

new создаёт объект из буквальной строки. $address->getPort() читает один компонент; $value получает '8443', echo печатает его. URI не открывается и сетевого запроса нет.

Теперь проверим границу, важную при обработке импортированных ссылок. В следующем примере === сравнивает значение вместе с типом; foreach, если используется, проходит по небольшому списку адресов.

Различить стандартный и явно нестандартный порт веб-сервиса. Граница данных.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

foreach (['https://shop.example:443/', 'http://shop.example:80/', 'https://shop.example:8443/'] as $s) {
    $u = new Url($s);
    echo $u->getPort() === null ? 'стандартный/не указан' : $u->getPort(), "\n";
}
Ожидаемый результат
стандартный/не указан
стандартный/не указан
8443

null не означает отсутствие сетевого порта у протокола; канонизация убрала стандартное число. Если приложению нужен эффективный порт, задайте явную таблицу разрешённых схем.

Это компоненты WHATWG URL, а не необработанный ввод. Канонизация уже произошла при создании. Возвращённую строку нельзя автоматически считать безопасной для HTML, shell или исходящего HTTP-запроса.

Практика: замените адрес на ссылку вашего учебного каталога без учётных данных, предскажите значение этого компонента и проверьте его. Не обращайтесь к сети: сравните только строки.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\Rfc3986\Uri::__constructРазобрать ссылку один раз и затем работать с её компонентами.

PHP 8.5.0+ · uri

__construct(string $uri, ?Uri\Rfc3986\Uri $baseUrl = null)

Разобрать ссылку один раз и затем работать с её компонентами.

Запись __construct(string $uri, ?Uri\Rfc3986\Uri $baseUrl = null) описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$uriСтрока адреса/ссылки. Не выполняется HTTP-запрос.
$baseUrl = nullОбъект Uri\Rfc3986\Uri для разрешения относительной ссылки, не строка. Без базы допускается относительный URI. Переданная база должна быть абсолютной; в PHP 8.5.11 это проверяется даже при абсолютном первом аргументе.
Результатnew возвращает новый final readonly объект; сам __construct не возвращает отдельного результата.
ОтказUri\InvalidUriException при неверном URI или относительной базе; Uri\UriError при внутреннем отказе.
Ссылка доставки
  1. https://shop.example/help/delivery
  2. new проверяет и разбирает строку
  3. $address хранит объект
  4. getter возвращает shop.example
Создать адрес страницы доставкиСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$address = new Uri('https://shop.example/help/delivery');
echo $address->getHost(), "\n";
Ожидаемый результат
shop.example

new вызывает конструктор и сохраняет объект в $address. Метод затем читает host. Класс находится в namespace; use даёт короткое имя только в этом файле.

Относительная ссылка имеет смысл в контексте другой страницы. Последний сегмент базового URL без завершающего / считается именем ресурса. Следующий вызов не читает ни файл, ни сайт.

Собрать ссылку на соседнюю карточкуСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$base = new Uri('https://shop.example/catalog/tools/list');
$card = new Uri('../drill', $base);
echo $card->toString(), "\n";
echo $base->toString(), "\n";
Ожидаемый результат
https://shop.example/catalog/drill
https://shop.example/catalog/tools/list

Сначала отбрасывается list, затем .. поднимает на один каталог. База остаётся прежним объектом. Для операций над файловой системой нужен иной API.

Повторно вызывать __construct на готовом readonly объекте нельзя: Error. Создайте другой объект или используйте with-метод. Ошибка PHP-типа даёт TypeError, а не null. Перед первым вызовом на старом PHP проверьте class_exists; библиотека присутствует с PHP 8.5.0.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::parse, Uri\Rfc3986\Uri::resolve.

Uri\Rfc3986\Uri::parseПроверить массовый импорт ссылок, где неправильная запись ожидаема.

PHP 8.5.0+ · uri

static parse(string $uri, ?Uri\Rfc3986\Uri $baseUrl = null): ?static

Проверить массовый импорт ссылок, где неправильная запись ожидаема.

Запись static parse(string $uri, ?Uri\Rfc3986\Uri $baseUrl = null): ?static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$uri, $baseUrlКак у конструктора: строка ссылки и необязательный объект того же класса; чужой класс — TypeError.
Результат?static: новый Uri либо null при отказе парсинга. Не false.
ОшибкиОшибки PHP-типов/аргументов не подавляются. null — только обычная невозможность разобрать/разрешить адрес.
Импорт одной ссылки
  1. Строка https://shop.example/help
  2. Uri::parse(...)
  3. Объект или null
  4. Проверка !== null → вывод адреса
Проверить введённый адрес без try/catchСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$candidate = Uri::parse('https://shop.example/help');
if ($candidate !== null) {
    echo $candidate->toString(), "\n";
} else {
    echo "Исправьте адрес\n";
}
Ожидаемый результат
https://shop.example/help

:: вызывает статический метод класса, без предварительного new. !== null отделяет успех от ошибки до вызова метода у объекта.

Отклонить повреждённую percent-последовательностьСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

foreach (['https://shop.example/%ZZ', '../help'] as $text) {
    $u = Uri::parse($text);
    echo $u === null ? 'ошибка синтаксиса' : $u->toString(), "\n";
}
Ожидаемый результат
ошибка синтаксиса
../help

RFC принимает относительный URI без базы. Поэтому «parse не null» ещё не означает готовую абсолютную веб-ссылку; для такой политики отдельно нужны схема и host.

Следующий шаг: решите заранее, допустимы ли относительные ссылки и автоматические исправления. Не заменяйте null исходной непроверенной строкой, если дальше ожидается проверенный объект.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::__construct.

Uri\Rfc3986\Uri::resolveВосстановить полную ссылку из относительной записи HTML или конфигурации.

PHP 8.5.0+ · uri

resolve(string $uri): static

Восстановить полную ссылку из относительной записи HTML или конфигурации.

Запись resolve(string $uri): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$uriОтносительный или абсолютный адрес; текущий объект — база.
РезультатНовый объект, исходный не меняется.
ОтказUri\InvalidUriException для ошибочной ссылки/относительной базы.
Соседний документ
  1. База https://shop.example/help/start
  2. resolve("delivery")
  3. Заменить start на delivery
  4. https://shop.example/help/delivery
Получить адрес соседнего документаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$page = new Uri('https://shop.example/help/start');
$delivery = $page->resolve('delivery');
echo $delivery->toString(), "\n";
Ожидаемый результат
https://shop.example/help/delivery

Текущий объект становится базой, resolve получает только относительную строку. delivery заменяет start; существующий $page не изменяется.

Различить каталог, корень и новый узелСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$base = new Uri('https://shop.example/help/');
foreach (['delivery', '/catalog', '//cdn.example/image.png'] as $text) {
    echo $base->resolve($text)->toString(), "\n";
}
Ожидаемый результат
https://shop.example/help/delivery
https://shop.example/catalog
https://cdn.example/image.png

Ссылка /catalog начинается от корня узла; //cdn.example наследует только схему и заменяет host. Поэтому «разрешить относительно доверенной базы» не ограничивает результат тем же доменом.

База должна быть абсолютной. Относительный объект Uri допустим как значение, но вызов resolve у такого объекта даёт Uri\InvalidUriException. Не путайте нормализацию . и .. с существованием каталогов на диске.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::__construct, Uri\Rfc3986\Uri::withPath.

Uri\Rfc3986\Uri::equalsУбрать дубликаты ссылок по явно выбранному правилу fragment.

PHP 8.5.0+ · uri

equals(Uri\Rfc3986\Uri $uri, Uri\UriComparisonMode $comparisonMode = Uri\UriComparisonMode::ExcludeFragment): bool

Убрать дубликаты ссылок по явно выбранному правилу fragment.

Запись equals(Uri\Rfc3986\Uri $uri, Uri\UriComparisonMode $comparisonMode = Uri\UriComparisonMode::ExcludeFragment): bool описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
Первый аргументОбъект того же класса; другой класс — TypeError.
$comparisonModeIncludeFragment или ExcludeFragment (по умолчанию), не строка и не bool.
Результатbool; совпадение нормализованных сериализаций по выбранному режиму.
ОграничениеНе гарантирует одинаковый ресурс/ответ, владение доменом или безопасное соединение.
Два якоря
  1. help#payment и help#delivery
  2. Режим по умолчанию исключает fragment
  3. true → Один ресурс
  4. IncludeFragment → false
Сравнить две ссылки на разделы одной страницыСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$a = new Uri('https://shop.example/help#payment');
$b = new Uri('https://shop.example/help#delivery');
echo $a->equals($b) ? "Один ресурс\n" : "Разные адреса\n";
echo $a->equals($b, \Uri\UriComparisonMode::IncludeFragment) ? "Один якорь\n" : "Разные якоря\n";
Ожидаемый результат
Один ресурс
Разные якоря

По умолчанию ExcludeFragment игнорирует fragment. IncludeFragment учитывает его. Это выбранный алгоритм эквивалентности строк, не доказательство одинакового ответа сервера.

Проверить влияние стандартного портаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$a = new Uri('https://shop.example:443/');
$b = new Uri('https://shop.example/');
echo $a->equals($b) ? "эквивалентны\n" : "различаются\n";
Ожидаемый результат
различаются

WHATWG удаляет стандартный порт; RFC в этом API сохраняет его. Выбирайте один парсер для формирования и сравнения ключей, не чередуйте правила между проверкой и использованием.

equals сравнивает нормализованные сериализации выбранного класса, с учётом режима fragment. Это не === (тождество объектов), не DNS, не сравнение содержимого сайта. Порядок query-пар не сортируется; HTTP-сервер может придавать ему значение.

Перед первым запуском: как устроен вызов и что он проверяет.

Uri\Rfc3986\Uri::toStringПодготовить разобранный адрес к хранению или отображению в нужной форме.

PHP 8.5.0+ · uri

toString(): string

Подготовить разобранный адрес к хранению или отображению в нужной форме.

Запись toString(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатstring; нормализованная сериализация RFC; не удаляет стандартный порт HTTP.
ОтказПри внутренней невозможности RFC-сериализации возможен Uri\UriError; тип/число аргументов проверяет PHP. Обычная валидная строка возвращается без сети.
Объект → строка
  1. HTTPS://Shop.Example/a/../%7ecard
  2. toString() выбирает форму
  3. https://shop.example/~card
  4. Перед HTML отдельное экранирование
Получить строку адреса для следующего слоя программыСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('HTTPS://Shop.Example/a/../%7ecard');
echo $u->toString(), "\n";
Ожидаемый результат
https://shop.example/~card

Raw сохраняет эту исходную запись компонентов; normalized сводит регистр, unreserved percent и путь. Строка по-прежнему не является HTTP-запросом.

Сохранить границы сериализацииСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://[2001:DB8::1]/');
echo $u->toString(), "\n";
Ожидаемый результат
https://[2001:0db8:0000:0000:0000:0000:0000:0001]/

Даже toRawString повторно сериализует IPv6 полностью развёрнутыми строчными hex-группами. Для аудита точного исходного текста или протокола подписи храните входную строку отдельно.

У этих классов нет __toString: используйте явный метод вместо echo $u или (string) $u. Полученная строка может содержать credentials, query-токены и персональные данные. Полный var_dump/журнал допустим только на фиктивных тестовых адресах.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::toRawString.

Uri\Rfc3986\Uri::toRawStringПодготовить разобранный адрес к хранению или отображению в нужной форме.

PHP 8.5.0+ · uri

toRawString(): string

Подготовить разобранный адрес к хранению или отображению в нужной форме.

Запись toRawString(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатstring; сериализация исходных компонентов, с исключением канонической записи IPv6.
ОтказПри внутренней невозможности RFC-сериализации возможен Uri\UriError; тип/число аргументов проверяет PHP. Обычная валидная строка возвращается без сети.
Объект → строка
  1. HTTPS://Shop.Example/a/../%7ecard
  2. toRawString() выбирает форму
  3. HTTPS://Shop.Example/a/../%7ecard
  4. Перед HTML отдельное экранирование
Получить строку адреса для следующего слоя программыСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('HTTPS://Shop.Example/a/../%7ecard');
echo $u->toRawString(), "\n";
Ожидаемый результат
HTTPS://Shop.Example/a/../%7ecard

Raw сохраняет эту исходную запись компонентов; normalized сводит регистр, unreserved percent и путь. Строка по-прежнему не является HTTP-запросом.

Сохранить границы сериализацииСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://[2001:DB8::1]/');
echo $u->toRawString(), "\n";
Ожидаемый результат
https://[2001:0db8:0000:0000:0000:0000:0000:0001]/

Даже toRawString повторно сериализует IPv6 полностью развёрнутыми строчными hex-группами. Для аудита точного исходного текста или протокола подписи храните входную строку отдельно.

У этих классов нет __toString: используйте явный метод вместо echo $u или (string) $u. Полученная строка может содержать credentials, query-токены и персональные данные. Полный var_dump/журнал допустим только на фиктивных тестовых адресах.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::toString.

Uri\Rfc3986\Uri::__debugInfoРазобрать локальную ошибку, не отдавая полный URI пользователю.

PHP 8.5.0+ · uri

__debugInfo(): array

Разобрать локальную ошибку, не отдавая полный URI пользователю.

Запись __debugInfo(): array описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатarray с состоянием для диагностики. PHP 8.5.11 показывает scheme, username, password, host, port, path, query, fragment; это не публичные writable properties.
ОграничениеФормат диагностики не используйте как долговременный формат обмена. Наличие SensitiveParameter у setter не скрывает debugInfo.
Выбор разрешённых полей
  1. Объект https://shop.example:8443/p
  2. __debugInfo() → массив
  3. $state["host"] → shop.example
  4. $state["port"] → 8443
Посмотреть только несекретное поле состоянияСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example:8443/p?q=1#top');
$state = $u->__debugInfo();
echo $state['host'], "\n", $state['port'], "\n";
Ожидаемый результат
shop.example
8443

__debugInfo возвращает массив, который использует var_dump. Прямой вызов показан ради договора; для бизнес-логики предпочтительнее getter.

Отобрать разрешённые поля для локальной диагностикиСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://anna:demo@shop.example/p?token=demo');
$state = $u->__debugInfo();
echo $state['scheme'], '://', $state['host'], "\n";
echo array_key_exists('password', $state) ? "Полный dump содержит поле пароля\n" : "Нет поля\n";
Ожидаемый результат
https://shop.example
Полный dump содержит поле пароля

Только scheme и host попали в сообщение. Даже путь может содержать токен, поэтому нет универсальной функции «безопасно логировать весь URL». demo — фиктивные значения.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getScheme.

Uri\Rfc3986\Uri::__serializeПоддержать локальное сохранение объекта стандартным механизмом PHP.

PHP 8.5.0+ · uri

__serialize(): array

Поддержать локальное сохранение объекта стандартным механизмом PHP.

Запись __serialize(): array описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатarray состояния, который serialize() затем кодирует в PHP-строку.
PHP 8.5.11Внутренний формат [["uri" => строка], []]: RFC сохраняет raw-сериализацию, WHATWG — ASCII. Не редактируйте формат вручную и не обещайте его стабильность другим реализациям.
ОграничениеCredentials и query могут попасть в состояние. Нет шифрования или подписи; сеть не используется.
Снимок состояния
  1. https://shop.example/help
  2. __serialize()
  3. Массив для механизма PHP
  4. Исходный объект прежний
Получить данные PHP-сериализации адресаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/help');
$data = $u->__serialize();
echo is_array($data) ? "Массив состояния\n" : "Другой тип\n";
echo $u->toString(), "\n";
Ожидаемый результат
Массив состояния
https://shop.example/help

__serialize возвращает array, не текст serialize(). Упоминание string в Return Values текущей страницы PHP.net противоречит её же сигнатуре; здесь используется подтверждённый тип PHP 8.5.11.

Сохранить и восстановить свой объект в памятиСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/help#delivery');
$bytes = serialize($u);
$copy = unserialize($bytes, ['allowed_classes' => [Uri::class]]);
echo $copy instanceof Uri && $copy->equals($u, \Uri\UriComparisonMode::IncludeFragment) ? "Адрес восстановлен\n" : "Ошибка\n";
echo $copy === $u ? "Тот же объект\n" : "Другой объект\n";
Ожидаемый результат
Адрес восстановлен
Другой объект

Обе стороны контролируем мы, ввод не внешний. allowed_classes не делает недоверенную PHP-сериализацию безопасной. Для внешнего обмена удобнее строка URL в JSON и повторный parse с вашей политикой.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::__unserialize.

Uri\Rfc3986\Uri::__unserializeПонять восстановление состояния и корректно обработать его отказ.

PHP 8.5.0+ · uri

__unserialize(array $data): void

Понять восстановление состояния и корректно обработать его отказ.

Запись __unserialize(array $data): void описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$dataМассив, подготовленный __serialize для этого класса. Не JSON и не готовая строка serialize().
Результатvoid; заполняет только ещё не инициализированный объект в механизме восстановления.
Отказ PHP 8.5.11Неверная структура/строка URI → Exception; повторная инициализация → Exception с предыдущим Error. Уточнение по исходнику и отдельному запуску, не замена всех ошибок Uri на Exception.
Доверенный round-trip
  1. Свой объект → serialize
  2. PHP-строка только в памяти
  3. unserialize создаёт новый объект
  4. __unserialize восстанавливает → getter
Восстановить доверенный адрес стандартным вызовомСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$saved = serialize(new Uri('https://shop.example/help'));
$restored = unserialize($saved, ['allowed_classes' => [Uri::class]]);
if ($restored instanceof Uri) {
    echo $restored->toString(), "\n";
}
Ожидаемый результат
https://shop.example/help

unserialize создаёт ещё не инициализированный объект и передаёт его состояние в __unserialize. Прикладной код не должен повторно инициализировать уже готовый readonly объект.

Понять отказ повторной инициализацииСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/help');
try {
    $u->__unserialize($u->__serialize());
} catch (Throwable $e) {
    echo $e::class, "\n";
    echo $e->getPrevious() instanceof Error ? "Предыдущая причина: Error\n" : "Другая причина\n";
}
echo $u->toString(), "\n";
Ожидаемый результат
Exception
Предыдущая причина: Error
https://shop.example/help

Точно наблюдаемая PHP 8.5.11 цепочка: внешний Exception, предыдущий Error о readonly. Поэтому catch(Error) один не ловит этот конкретный вызов. Вызываем Throwable только на узкой границе учебной диагностики, не подавляем все ошибки приложения.

Текущая страница PHP.net описывает Error для повторного вызова и InvalidUriException для неправильного URI. Tagged PHP 8.5.11 в этом hook оборачивает readonly Error в Exception, а неправильную структуру/URI отклоняет обычным Exception. Это версионное расхождение явно отделено от правил parse/конструктора. При неверном типе $data возникает TypeError. Не собирайте сериализованные payload из внешнего ввода.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::__serialize, Uri\Rfc3986\Uri::parse.

Uri\WhatWg\Url::__constructРазобрать ссылку один раз и затем работать с её компонентами.

PHP 8.5.0+ · uri

__construct(string $uri, ?Uri\WhatWg\Url $baseUrl = null, &$softErrors = null)

Разобрать ссылку один раз и затем работать с её компонентами.

Запись __construct(string $uri, ?Uri\WhatWg\Url $baseUrl = null, &$softErrors = null) описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$uriСтрока адреса/ссылки. Не выполняется HTTP-запрос.
$baseUrl = nullОбъект Uri\WhatWg\Url для разрешения относительной ссылки, не строка. Для относительного ввода база обязательна. Абсолютный URL обычно задаёт собственный адрес; особые same-scheme ссылки следуют алгоритму WHATWG.
&$softErrorsНеобязательная выходная переменная, заполняемая списком UrlValidationError; успешный вызов заменяет её, в том числе на []. При жёстком отказе смотрите exception->errors: эта выходная переменная не обновляется. Знак & — запись результата в переданную переменную.
Результатnew возвращает новый final readonly объект; сам __construct не возвращает отдельного результата.
ОтказUri\WhatWg\InvalidUrlException с массивом errors.
Ссылка доставки
  1. https://shop.example/help/delivery
  2. new проверяет и разбирает строку
  3. $address хранит объект
  4. getter возвращает shop.example
Создать адрес страницы доставкиСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$address = new Url('https://shop.example/help/delivery');
echo $address->getAsciiHost(), "
";
Ожидаемый результат
shop.example

new вызывает конструктор и сохраняет объект в $address. Метод затем читает host. Класс находится в namespace; use даёт короткое имя только в этом файле.

Относительная ссылка имеет смысл в контексте другой страницы. Последний сегмент базового URL без завершающего / считается именем ресурса. Следующий вызов не читает ни файл, ни сайт.

Собрать ссылку на соседнюю карточкуСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$base = new Url('https://shop.example/catalog/tools/list');
$card = new Url('../drill', $base);
echo $card->toAsciiString(), "\n";
echo $base->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/catalog/drill
https://shop.example/catalog/tools/list

Сначала отбрасывается list, затем .. поднимает на один каталог. База остаётся прежним объектом. Для операций над файловой системой нужен иной API.

Принять URL с диагностикой исправленияСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$warnings = [];
$u = new Url('https:shop.example', null, $warnings);
echo $u->toAsciiString(), "\n";
echo $warnings[0]->type->name, ':', $warnings[0]->failure ? 'hard' : 'soft', "\n";
Ожидаемый результат
https://shop.example/
SpecialSchemeMissingFollowingSolidus:soft

Успешный объект не означает отсутствие ошибок в исходной записи. Программа может принять автоматическое исправление либо отклонить любой soft error согласно своим требованиям; тип enum полезнее нестабильного текста сообщения.

Повторно вызывать __construct на готовом readonly объекте нельзя: Error. Создайте другой объект или используйте with-метод. Ошибка PHP-типа даёт TypeError, а не null. Перед первым вызовом на старом PHP проверьте class_exists; библиотека присутствует с PHP 8.5.0.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::parse, Uri\WhatWg\Url::resolve.

Uri\WhatWg\Url::parseПроверить массовый импорт ссылок, где неправильная запись ожидаема.

PHP 8.5.0+ · uri

static parse(string $uri, ?Uri\WhatWg\Url $baseUrl = null, &$errors = null): ?static

Проверить массовый импорт ссылок, где неправильная запись ожидаема.

Запись static parse(string $uri, ?Uri\WhatWg\Url $baseUrl = null, &$errors = null): ?static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$uri, $baseUrlКак у конструктора: строка ссылки и необязательный объект того же класса; чужой класс — TypeError.
&$errorsВыходная переменная: список мягких/жёстких UrlValidationError. Заменяется результатом текущего разбора, даже при null. Передайте переменную, а не литерал [].
Результат?static: новый Url либо null при отказе парсинга. Не false.
ОшибкиОшибки PHP-типов/аргументов не подавляются. null — только обычная невозможность разобрать/разрешить адрес.
Импорт одной ссылки
  1. Строка https://shop.example/help
  2. Url::parse(...)
  3. Объект или null
  4. Проверка !== null → вывод адреса
Проверить введённый адрес без try/catchСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$candidate = Url::parse('https://shop.example/help');
if ($candidate !== null) {
    echo $candidate->toAsciiString(), "\n";
} else {
    echo "Исправьте адрес\n";
}
Ожидаемый результат
https://shop.example/help

:: вызывает статический метод класса, без предварительного new. !== null отделяет успех от ошибки до вызова метода у объекта.

Показать причину отказа портаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$errors = [];
$candidate = Url::parse('https://shop.example:70000/', null, $errors);
echo $candidate === null ? "Адрес отклонён\n" : "Адрес принят\n";
echo $errors[0]->type->name, ':', $errors[0]->failure ? 'hard' : 'soft', "\n";
Ожидаемый результат
Адрес отклонён
PortOutOfRange:hard

parse возвращает null, но ошибки доступны по ссылке. Не печатайте context в публичном сообщении: там может оказаться часть секретного URL.

Следующий шаг: решите заранее, допустимы ли относительные ссылки и автоматические исправления. Не заменяйте null исходной непроверенной строкой, если дальше ожидается проверенный объект.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::__construct.

Uri\WhatWg\Url::resolveВосстановить полную ссылку из относительной записи HTML или конфигурации.

PHP 8.5.0+ · uri

resolve(string $uri, &$softErrors = null): static

Восстановить полную ссылку из относительной записи HTML или конфигурации.

Запись resolve(string $uri, &$softErrors = null): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$uriОтносительный или абсолютный адрес; текущий объект — база.
РезультатНовый объект, исходный не меняется.
ОтказUri\WhatWg\InvalidUrlException; диагностика по контракту конструктора.
Соседний документ
  1. База https://shop.example/help/start
  2. resolve("delivery")
  3. Заменить start на delivery
  4. https://shop.example/help/delivery
Получить адрес соседнего документаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$page = new Url('https://shop.example/help/start');
$delivery = $page->resolve('delivery');
echo $delivery->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/help/delivery

Текущий объект становится базой, resolve получает только относительную строку. delivery заменяет start; существующий $page не изменяется.

Различить каталог, корень и новый узелСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$base = new Url('https://shop.example/help/');
foreach (['delivery', '/catalog', '//cdn.example/image.png'] as $text) {
    echo $base->resolve($text)->toAsciiString(), "\n";
}
Ожидаемый результат
https://shop.example/help/delivery
https://shop.example/catalog
https://cdn.example/image.png

Ссылка /catalog начинается от корня узла; //cdn.example наследует только схему и заменяет host. Поэтому «разрешить относительно доверенной базы» не ограничивает результат тем же доменом.

Вторая необязательная &$softErrors работает как третий аргумент конструктора: успешный результат со списком исправлений, а при исключении диагностика находится в errors самого исключения. Opaque-база mailto не умеет разрешать обычный дочерний путь; fragment-ссылка имеет отдельные правила WHATWG.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::__construct, Uri\WhatWg\Url::withPath.

Uri\WhatWg\Url::equalsУбрать дубликаты ссылок по явно выбранному правилу fragment.

PHP 8.5.0+ · uri

equals(Uri\WhatWg\Url $url, Uri\UriComparisonMode $comparisonMode = Uri\UriComparisonMode::ExcludeFragment): bool

Убрать дубликаты ссылок по явно выбранному правилу fragment.

Запись equals(Uri\WhatWg\Url $url, Uri\UriComparisonMode $comparisonMode = Uri\UriComparisonMode::ExcludeFragment): bool описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
Первый аргументОбъект того же класса; другой класс — TypeError.
$comparisonModeIncludeFragment или ExcludeFragment (по умолчанию), не строка и не bool.
Результатbool; совпадение нормализованных сериализаций по выбранному режиму.
ОграничениеНе гарантирует одинаковый ресурс/ответ, владение доменом или безопасное соединение.
Два якоря
  1. help#payment и help#delivery
  2. Режим по умолчанию исключает fragment
  3. true → Один ресурс
  4. IncludeFragment → false
Сравнить две ссылки на разделы одной страницыСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$a = new Url('https://shop.example/help#payment');
$b = new Url('https://shop.example/help#delivery');
echo $a->equals($b) ? "Один ресурс\n" : "Разные адреса\n";
echo $a->equals($b, \Uri\UriComparisonMode::IncludeFragment) ? "Один якорь\n" : "Разные якоря\n";
Ожидаемый результат
Один ресурс
Разные якоря

По умолчанию ExcludeFragment игнорирует fragment. IncludeFragment учитывает его. Это выбранный алгоритм эквивалентности строк, не доказательство одинакового ответа сервера.

Проверить влияние стандартного портаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$a = new Url('https://shop.example:443/');
$b = new Url('https://shop.example/');
echo $a->equals($b) ? "эквивалентны\n" : "различаются\n";
Ожидаемый результат
эквивалентны

WHATWG удаляет стандартный порт; RFC в этом API сохраняет его. Выбирайте один парсер для формирования и сравнения ключей, не чередуйте правила между проверкой и использованием.

equals сравнивает нормализованные сериализации выбранного класса, с учётом режима fragment. Это не === (тождество объектов), не DNS, не сравнение содержимого сайта. Порядок query-пар не сортируется; HTTP-сервер может придавать ему значение.

Перед первым запуском: как устроен вызов и что он проверяет.

Uri\WhatWg\Url::toAsciiStringПодготовить разобранный адрес к хранению или отображению в нужной форме.

PHP 8.5.0+ · uri

toAsciiString(): string

Подготовить разобранный адрес к хранению или отображению в нужной форме.

Запись toAsciiString(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатstring; готовая WHATWG-сериализация, домен в ASCII/IDNA.
ОтказПри внутренней невозможности RFC-сериализации возможен Uri\UriError; тип/число аргументов проверяет PHP. Обычная валидная строка возвращается без сети.
Объект → строка
  1. https://пример.рф/price%20list?q=%7e
  2. toAsciiString() выбирает форму
  3. https://xn--e1afmkfd.xn--p1ai/price%20list?q=%7e
  4. Перед HTML отдельное экранирование
Получить строку адреса для следующего слоя программыСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://пример.рф/price%20list?q=%7e');
echo $u->toAsciiString(), "\n";
Ожидаемый результат
https://xn--e1afmkfd.xn--p1ai/price%20list?q=%7e

Меняется форма домена IDNA/Unicode. Пробел в пути остаётся %20, а query не подвергается полному URL-decoding. Название Unicode не обещает раскодирования всех компонентов.

Сохранить границы сериализацииСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/catalog?size=M&color=blue');
echo htmlspecialchars($u->toAsciiString(), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), "\n";
Ожидаемый результат
https://shop.example/catalog?size=M&amp;color=blue

Сначала получаем URL-строку, затем отдельно экранируем для HTML. Этот CLI вывод показывает преобразованный текст; HTTP-ответ здесь не отправляется. В JSON нужен json_encode, для каждого контекста — свой encoder.

У этих классов нет __toString: используйте явный метод вместо echo $u или (string) $u. Полученная строка может содержать credentials, query-токены и персональные данные. Полный var_dump/журнал допустим только на фиктивных тестовых адресах.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toUnicodeString.

Uri\WhatWg\Url::toUnicodeStringПодготовить разобранный адрес к хранению или отображению в нужной форме.

PHP 8.5.0+ · uri

toUnicodeString(): string

Подготовить разобранный адрес к хранению или отображению в нужной форме.

Запись toUnicodeString(): string описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатstring; готовая WHATWG-сериализация, домен в Unicode, когда применимо.
ОтказПри внутренней невозможности RFC-сериализации возможен Uri\UriError; тип/число аргументов проверяет PHP. Обычная валидная строка возвращается без сети.
Объект → строка
  1. https://пример.рф/price%20list?q=%7e
  2. toUnicodeString() выбирает форму
  3. https://пример.рф/price%20list?q=%7e
  4. Перед HTML отдельное экранирование
Получить строку адреса для следующего слоя программыСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://пример.рф/price%20list?q=%7e');
echo $u->toUnicodeString(), "\n";
Ожидаемый результат
https://пример.рф/price%20list?q=%7e

Меняется форма домена IDNA/Unicode. Пробел в пути остаётся %20, а query не подвергается полному URL-decoding. Название Unicode не обещает раскодирования всех компонентов.

Сохранить границы сериализацииСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/catalog?size=M&color=blue');
echo htmlspecialchars($u->toUnicodeString(), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), "\n";
Ожидаемый результат
https://shop.example/catalog?size=M&amp;color=blue

Сначала получаем URL-строку, затем отдельно экранируем для HTML. Этот CLI вывод показывает преобразованный текст; HTTP-ответ здесь не отправляется. В JSON нужен json_encode, для каждого контекста — свой encoder.

У этих классов нет __toString: используйте явный метод вместо echo $u или (string) $u. Полученная строка может содержать credentials, query-токены и персональные данные. Полный var_dump/журнал допустим только на фиктивных тестовых адресах.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::__debugInfoРазобрать локальную ошибку, не отдавая полный URI пользователю.

PHP 8.5.0+ · uri

__debugInfo(): array

Разобрать локальную ошибку, не отдавая полный URI пользователю.

Запись __debugInfo(): array описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатarray с состоянием для диагностики. PHP 8.5.11 показывает scheme, username, password, host, port, path, query, fragment; это не публичные writable properties.
ОграничениеФормат диагностики не используйте как долговременный формат обмена. Наличие SensitiveParameter у setter не скрывает debugInfo.
Выбор разрешённых полей
  1. Объект https://shop.example:8443/p
  2. __debugInfo() → массив
  3. $state["host"] → shop.example
  4. $state["port"] → 8443
Посмотреть только несекретное поле состоянияСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example:8443/p?q=1#top');
$state = $u->__debugInfo();
echo $state['host'], "\n", $state['port'], "\n";
Ожидаемый результат
shop.example
8443

__debugInfo возвращает массив, который использует var_dump. Прямой вызов показан ради договора; для бизнес-логики предпочтительнее getter.

Отобрать разрешённые поля для локальной диагностикиСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://anna:demo@shop.example/p?token=demo');
$state = $u->__debugInfo();
echo $state['scheme'], '://', $state['host'], "\n";
echo array_key_exists('password', $state) ? "Полный dump содержит поле пароля\n" : "Нет поля\n";
Ожидаемый результат
https://shop.example
Полный dump содержит поле пароля

Только scheme и host попали в сообщение. Даже путь может содержать токен, поэтому нет универсальной функции «безопасно логировать весь URL». demo — фиктивные значения.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getScheme.

Uri\WhatWg\Url::__serializeПоддержать локальное сохранение объекта стандартным механизмом PHP.

PHP 8.5.0+ · uri

__serialize(): array

Поддержать локальное сохранение объекта стандартным механизмом PHP.

Запись __serialize(): array описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
АргументыНет.
Результатarray состояния, который serialize() затем кодирует в PHP-строку.
PHP 8.5.11Внутренний формат [["uri" => строка], []]: RFC сохраняет raw-сериализацию, WHATWG — ASCII. Не редактируйте формат вручную и не обещайте его стабильность другим реализациям.
ОграничениеCredentials и query могут попасть в состояние. Нет шифрования или подписи; сеть не используется.
Снимок состояния
  1. https://shop.example/help
  2. __serialize()
  3. Массив для механизма PHP
  4. Исходный объект прежний
Получить данные PHP-сериализации адресаСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/help');
$data = $u->__serialize();
echo is_array($data) ? "Массив состояния\n" : "Другой тип\n";
echo $u->toAsciiString(), "\n";
Ожидаемый результат
Массив состояния
https://shop.example/help

__serialize возвращает array, не текст serialize(). Упоминание string в Return Values текущей страницы PHP.net противоречит её же сигнатуре; здесь используется подтверждённый тип PHP 8.5.11.

Сохранить и восстановить свой объект в памятиСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/help#delivery');
$bytes = serialize($u);
$copy = unserialize($bytes, ['allowed_classes' => [Url::class]]);
echo $copy instanceof Url && $copy->equals($u, \Uri\UriComparisonMode::IncludeFragment) ? "Адрес восстановлен\n" : "Ошибка\n";
echo $copy === $u ? "Тот же объект\n" : "Другой объект\n";
Ожидаемый результат
Адрес восстановлен
Другой объект

Обе стороны контролируем мы, ввод не внешний. allowed_classes не делает недоверенную PHP-сериализацию безопасной. Для внешнего обмена удобнее строка URL в JSON и повторный parse с вашей политикой.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::__unserialize.

Uri\WhatWg\Url::__unserializeПонять восстановление состояния и корректно обработать его отказ.

PHP 8.5.0+ · uri

__unserialize(array $data): void

Понять восстановление состояния и корректно обработать его отказ.

Запись __unserialize(array $data): void описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$dataМассив, подготовленный __serialize для этого класса. Не JSON и не готовая строка serialize().
Результатvoid; заполняет только ещё не инициализированный объект в механизме восстановления.
Отказ PHP 8.5.11Неверная структура/строка URI → Exception; повторная инициализация → Exception с предыдущим Error. Уточнение по исходнику и отдельному запуску, не замена всех ошибок Uri на Exception.
Доверенный round-trip
  1. Свой объект → serialize
  2. PHP-строка только в памяти
  3. unserialize создаёт новый объект
  4. __unserialize восстанавливает → getter
Восстановить доверенный адрес стандартным вызовомСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$saved = serialize(new Url('https://shop.example/help'));
$restored = unserialize($saved, ['allowed_classes' => [Url::class]]);
if ($restored instanceof Url) {
    echo $restored->toAsciiString(), "\n";
}
Ожидаемый результат
https://shop.example/help

unserialize создаёт ещё не инициализированный объект и передаёт его состояние в __unserialize. Прикладной код не должен повторно инициализировать уже готовый readonly объект.

Понять отказ повторной инициализацииСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/help');
try {
    $u->__unserialize($u->__serialize());
} catch (Throwable $e) {
    echo $e::class, "\n";
    echo $e->getPrevious() instanceof Error ? "Предыдущая причина: Error\n" : "Другая причина\n";
}
echo $u->toAsciiString(), "\n";
Ожидаемый результат
Exception
Предыдущая причина: Error
https://shop.example/help

Точно наблюдаемая PHP 8.5.11 цепочка: внешний Exception, предыдущий Error о readonly. Поэтому catch(Error) один не ловит этот конкретный вызов. Вызываем Throwable только на узкой границе учебной диагностики, не подавляем все ошибки приложения.

Текущая страница PHP.net описывает Error для повторного вызова и InvalidUriException для неправильного URI. Tagged PHP 8.5.11 в этом hook оборачивает readonly Error в Exception, а неправильную структуру/URI отклоняет обычным Exception. Это версионное расхождение явно отделено от правил parse/конструктора. При неверном типе $data возникает TypeError. Не собирайте сериализованные payload из внешнего ввода.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::__serialize, Uri\WhatWg\Url::parse.

Uri\Rfc3986\Uri::withSchemeПеревести подготовленную ссылку каталога на другую схему.

PHP 8.5.0+ · uri

withScheme(?string $scheme): static

Перевести подготовленную ссылку каталога на другую схему.

Запись withScheme(?string $scheme): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$schemeСхема без :. null удаляет схему, пустая строка недопустима. RFC проверяет синтаксис, но не смысл конкретного протокола: mailto://host/path возможен как общий URI.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Перевести подготовленную ссылку каталога на другую схему.
  1. http://shop.example/p
  2. withScheme('https')
  3. https://shop.example/p
  4. $original по-прежнему http://shop.example/p
Перевести подготовленную ссылку каталога на другую схему.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$original = new Uri('http://shop.example/p');
$changed = $original->withScheme('https');
echo $changed->toString(), "\n";
echo $original->toString(), "\n";
Ожидаемый результат
https://shop.example/p
http://shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withSchemeСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/p');
echo $u->withScheme(null)->toString(), "\n";
try { $u->withScheme(''); } catch (\Uri\InvalidUriException $e) { echo "Пустая схема отклонена\n"; }
Ожидаемый результат
//shop.example/p
Пустая схема отклонена

null — удаление компонента; это не то же, что неверная пустая схема. Получится относительная network-path ссылка, которую нельзя автоматически считать абсолютной HTTPS-ссылкой.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getScheme, Uri\Rfc3986\Uri::toString.

Uri\Rfc3986\Uri::withHostПодготовить ссылку на зеркальный каталог.

PHP 8.5.0+ · uri

withHost(?string $host): static

Подготовить ссылку на зеркальный каталог.

Запись withHost(?string $host): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$hostИмя узла или IPv4/IPv6 со скобками, без порта и пути; Unicode-домен предварительно требует ASCII/IDNA либо WHATWG. null удаляет host, "" создаёт пустой host. Удаление host при наличии port/userinfo запрещено.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Подготовить ссылку на зеркальный каталог.
  1. https://shop.example/p
  2. withHost('cdn.example')
  3. https://cdn.example/p
  4. $original по-прежнему https://shop.example/p
Подготовить ссылку на зеркальный каталог.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$original = new Uri('https://shop.example/p');
$changed = $original->withHost('cdn.example');
echo $changed->toString(), "\n";
echo $original->toString(), "\n";
Ожидаемый результат
https://cdn.example/p
https://shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withHostСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example:8443/p');
try { $u->withHost(null); } catch (\Uri\InvalidUriException $e) { echo "Сначала удалите порт\n"; }
echo $u->withPort(null)->withHost(null)->toString(), "\n";
Ожидаемый результат
Сначала удалите порт
https:/p

Компоненты связаны. Сохранили схему и путь, удалили authority; результат допустим как общий URI, но непригоден как обычная ссылка магазина. Политику HTTP нужно проверять отдельно.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getHost, Uri\Rfc3986\Uri::toString.

Uri\Rfc3986\Uri::withPathПолучить ссылку на файл прайс-листа, не меняя host.

PHP 8.5.0+ · uri

withPath(string $path): static

Получить ссылку на файл прайс-листа, не меняя host.

Запись withPath(string $path): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$pathПолный путь без query/fragment. Пустая строка допустима; null не соответствует типу. RFC не кодирует пробел автоматически: передавайте корректный path и кодируйте отдельные динамические сегменты.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Получить ссылку на файл прайс-листа, не меняя host.
  1. https://shop.example/old
  2. withPath('/price%20list.csv')
  3. https://shop.example/price%20list.csv
  4. $original по-прежнему https://shop.example/old
Получить ссылку на файл прайс-листа, не меняя host.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$original = new Uri('https://shop.example/old');
$changed = $original->withPath('/price%20list.csv');
echo $changed->toString(), "\n";
echo $original->toString(), "\n";
Ожидаемый результат
https://shop.example/price%20list.csv
https://shop.example/old

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withPathСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/old');
$file = 'drill set';
echo $u->withPath('/items/' . rawurlencode($file))->toString(), "\n";
try { $u->withPath('/one two'); } catch (\Uri\InvalidUriException $e) { echo "Пробел нужно кодировать\n"; }
Ожидаемый результат
https://shop.example/items/drill%20set
Пробел нужно кодировать

rawurlencode обрабатывает один сегмент, а / оставлен разделителем. Не кодируйте весь URL: тогда исчезнет смысл :/?; не допускайте . и .. как пользовательские сегменты без отдельного правила.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getPath, Uri\Rfc3986\Uri::toString.

Uri\Rfc3986\Uri::withPortНастроить адрес тестового сервиса на отдельный порт.

PHP 8.5.0+ · uri

withPort(?int $port): static

Настроить адрес тестового сервиса на отдельный порт.

Запись withPort(?int $port): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$portНеотрицательный int либо null для удаления. RFC в PHP 8.5.11 не ограничивается 65535; для реального сетевого соединения приложение должно проверять диапазон. Без host установить порт нельзя.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Настроить адрес тестового сервиса на отдельный порт.
  1. https://shop.example/p
  2. withPort(8443)
  3. https://shop.example:8443/p
  4. $original по-прежнему https://shop.example/p
Настроить адрес тестового сервиса на отдельный порт.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$original = new Uri('https://shop.example/p');
$changed = $original->withPort(8443);
echo $changed->toString(), "\n";
echo $original->toString(), "\n";
Ожидаемый результат
https://shop.example:8443/p
https://shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withPortСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example:8443/p');
echo $u->withPort(null)->toString(), "\n";
try { $u->withPort(-1); } catch (\Uri\InvalidUriException $e) { echo "Отрицательный порт отклонён\n"; }
Ожидаемый результат
https://shop.example/p
Отрицательный порт отклонён

null убирает :, а отрицательное число не является корректным текстом RFC-порта. Стандартный 443 автоматически не удаляется: это отличие от WHATWG.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getPort, Uri\Rfc3986\Uri::toString.

Uri\Rfc3986\Uri::withQueryПостроить ссылку на отфильтрованный каталог.

PHP 8.5.0+ · uri

withQuery(?string $query): static

Построить ссылку на отфильтрованный каталог.

Запись withQuery(?string $query): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$queryQuery-компонент без первого ?. null удаляет ?, "" оставляет явный пустой ?. Пары параметров метод не собирает, HTML-экранирование не делает.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Построить ссылку на отфильтрованный каталог.
  1. https://shop.example/catalog
  2. withQuery('category=tools&page=2')
  3. https://shop.example/catalog?category=tools&page=2
  4. $original по-прежнему https://shop.example/catalog
Построить ссылку на отфильтрованный каталог.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$original = new Uri('https://shop.example/catalog');
$changed = $original->withQuery('category=tools&page=2');
echo $changed->toString(), "\n";
echo $original->toString(), "\n";
Ожидаемый результат
https://shop.example/catalog?category=tools&page=2
https://shop.example/catalog

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withQueryСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/find?q=old');
$query = http_build_query(['q' => 'drill set', 'page' => 2], '', '&', PHP_QUERY_RFC3986);
echo $u->withQuery($query)->toString(), "\n";
echo $u->withQuery('')->toString(), "\n";
echo $u->withQuery(null)->toString(), "\n";
Ожидаемый результат
https://shop.example/find?q=drill%20set&page=2
https://shop.example/find?
https://shop.example/find

http_build_query преобразует массив именованных значений в query. PHP_QUERY_RFC3986 использует %20; это отдельно от структуры Uri. Для повторных одинаковых ключей выберите явный формат протокола, не потеряйте их при преобразовании в массив.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getQuery, Uri\Rfc3986\Uri::toString.

Uri\Rfc3986\Uri::withFragmentДать ссылку на раздел доставки внутри справки.

PHP 8.5.0+ · uri

withFragment(?string $fragment): static

Дать ссылку на раздел доставки внутри справки.

Запись withFragment(?string $fragment): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$fragmentИмя fragment без #, в корректном RFC-кодировании. null удаляет #; "" оставляет явный пустой fragment. Метод не проверяет HTML id.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Дать ссылку на раздел доставки внутри справки.
  1. https://shop.example/help
  2. withFragment('delivery')
  3. https://shop.example/help#delivery
  4. $original по-прежнему https://shop.example/help
Дать ссылку на раздел доставки внутри справки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$original = new Uri('https://shop.example/help');
$changed = $original->withFragment('delivery');
echo $changed->toString(), "\n";
echo $original->toString(), "\n";
Ожидаемый результат
https://shop.example/help#delivery
https://shop.example/help

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withFragmentСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$u = new Uri('https://shop.example/help#delivery');
echo $u->withFragment('')->toString(), "\n";
echo $u->withFragment(null)->toString(), "\n";
try { $u->withFragment('#payment'); } catch (\Uri\InvalidUriException $e) { echo "Передайте имя без решётки\n"; }
Ожидаемый результат
https://shop.example/help#
https://shop.example/help
Передайте имя без решётки

В отличие от WHATWG setter, RFC не снимает начальную # за вас. Видимый fragment — часть клиентской навигации, а не команда серверу.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getFragment, Uri\Rfc3986\Uri::toString.

Uri\Rfc3986\Uri::withUserInfoУбрать встроенные учётные данные из учебной ссылки.

PHP 8.5.0+ · uri

withUserInfo(#[\SensitiveParameter] ?string $userinfo): static

Убрать встроенные учётные данные из учебной ссылки.

Запись withUserInfo(#[\SensitiveParameter] ?string $userinfo): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$userinfoВесь блок username[:password] без @, либо null для удаления. #[SensitiveParameter] скрывает этот аргумент в поддерживаемой трассировке, но не строку объекта, debugInfo или журнал. Пустая строка оставляет @; нужен host.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Убрать встроенные учётные данные из учебной ссылки.
  1. https://anna:demo@shop.example/p
  2. withUserInfo(null)
  3. https://shop.example/p
  4. $original по-прежнему https://anna:demo@shop.example/p
Убрать встроенные учётные данные из учебной ссылки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$original = new Uri('https://anna:demo@shop.example/p');
$changed = $original->withUserInfo(null);
echo $changed->toString(), "\n";
echo $original->toString(), "\n";
Ожидаемый результат
https://shop.example/p
https://anna:demo@shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withUserInfoСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\Rfc3986\Uri as Uri;

$base = new Uri('https://shop.example/p');
$testName = 'team:west';
$u = $base->withUserInfo(rawurlencode($testName) . ':demo');
echo $u->getUsername(), "\n";
echo $u->withUserInfo(null)->toString(), "\n";
Ожидаемый результат
team%3Awest
https://shop.example/p

Кодируем отдельное имя, чтобы двоеточие в нём не стало разделителем пароля. demo — фиктивное значение. В современных HTTP-приложениях credentials в URL обычно следует отклонять, а не строить автоматически.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\Rfc3986\Uri::getUserInfo, Uri\Rfc3986\Uri::toString.

Uri\WhatWg\Url::withSchemeОбновить браузерную ссылку с HTTP на HTTPS.

PHP 8.5.0+ · uri

withScheme(string $scheme): static

Обновить браузерную ссылку с HTTP на HTTPS.

Запись withScheme(string $scheme): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$schemeНовая схема; WHATWG принимает также запись с :. null не разрешён. Смена special↔non-special и некоторые переходы file не выполняются: метод может вернуть новый объект со старым значением без исключения. Проверяйте результат.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Обновить браузерную ссылку с HTTP на HTTPS.
  1. http://shop.example/p
  2. withScheme('https')
  3. https://shop.example/p
  4. $original по-прежнему http://shop.example/p
Обновить браузерную ссылку с HTTP на HTTPS.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('http://shop.example/p');
$changed = $original->withScheme('https');
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/p
http://shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withSchemeСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/p');
$changed = $u->withScheme('mailto');
echo $changed->getScheme(), "\n";
echo $changed === $u ? "Тот же объект\n" : "Новый объект без такой смены\n";
Ожидаемый результат
https
Новый объект без такой смены

Как browser protocol setter, операция не превращает hierarchical HTTPS URL в mailto. Создайте новый Url для другого рода адреса. Успешный вызов не гарантирует, что желаемое значение применено.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getScheme, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::withHostЗаменить домен каталога на международное имя.

PHP 8.5.0+ · uri

withHost(?string $host): static

Заменить домен каталога на международное имя.

Запись withHost(?string $host): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$hostHostname, не authority: не передавайте порт, userinfo, путь. Unicode-домен проходит IDNA. null/"" не могут убрать обязательный host HTTPS; неприменимые операции с opaque URL могут ничего не менять. Setter может остановиться на разделителе.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Заменить домен каталога на международное имя.
  1. https://shop.example/p
  2. withHost('пример.рф')
  3. https://xn--e1afmkfd.xn--p1ai/p
  4. $original по-прежнему https://shop.example/p
Заменить домен каталога на международное имя.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('https://shop.example/p');
$changed = $original->withHost('пример.рф');
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://xn--e1afmkfd.xn--p1ai/p
https://shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withHostСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/p');
echo $u->withHost('cdn.example/ignored')->toAsciiString(), "\n";
try { $u->withHost(null); } catch (\Uri\WhatWg\InvalidUrlException $e) { echo "HTTPS требует host\n"; }
Ожидаемый результат
https://cdn.example/p
HTTPS требует host

Суффикс /ignored не становится путём и не гарантированно отклоняется. Для поля «имя домена» приложение должно задавать отдельный строгий договор; withHost не является валидатором всей введённой строки.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getAsciiHost, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::withPathСобрать ссылку на документ с пробелом в имени.

PHP 8.5.0+ · uri

withPath(string $path): static

Собрать ссылку на документ с пробелом в имени.

Запись withPath(string $path): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$pathPathname; WHATWG кодирует необходимые символы, нормализует dot-segments. Для HTTP(S) относительная запись превращается в путь от корня. Opaque path (mailto и др.) не переписывается как иерархический.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Собрать ссылку на документ с пробелом в имени.
  1. https://shop.example/old
  2. withPath('/price list.csv')
  3. https://shop.example/price%20list.csv
  4. $original по-прежнему https://shop.example/old
Собрать ссылку на документ с пробелом в имени.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('https://shop.example/old');
$changed = $original->withPath('/price list.csv');
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/price%20list.csv
https://shop.example/old

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withPathСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/old');
echo $u->withPath('/items/a?b#c')->toAsciiString(), "\n";
echo $u->withPath('/a/%2e%2e/b')->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/items/a%3Fb%23c
https://shop.example/b

? и # внутри setter-значения становятся данными пути, не query/fragment. Кодированный .. считается навигационным сегментом: percent-кодирование само по себе не защищает от изменения маршрута.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getPath, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::withPortВыбрать порт отдельного учебного HTTPS-сервиса.

PHP 8.5.0+ · uri

withPort(?int $port): static

Выбрать порт отдельного учебного HTTPS-сервиса.

Запись withPort(?int $port): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$portint 0…65535 или null. Стандартный порт схемы убирается; file/URL без host не получает обычный сетевой порт. Неприменимая операция может не менять значение.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Выбрать порт отдельного учебного HTTPS-сервиса.
  1. https://shop.example/p
  2. withPort(8443)
  3. https://shop.example:8443/p
  4. $original по-прежнему https://shop.example/p
Выбрать порт отдельного учебного HTTPS-сервиса.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('https://shop.example/p');
$changed = $original->withPort(8443);
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example:8443/p
https://shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withPortСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example:8443/p');
echo $u->withPort(443)->toAsciiString(), "\n";
try { $u->withPort(70000); } catch (\Uri\WhatWg\InvalidUrlException $e) { echo "Порт вне диапазона\n"; }
Ожидаемый результат
https://shop.example/p
Порт вне диапазона

В WHATWG 443 для https — стандартный и не хранится как явный порт. Не используйте это правило для RFC Uri: там 70000 может быть синтаксически представимым.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getPort, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::withQueryДобавить фильтр к готовой ссылке каталога.

PHP 8.5.0+ · uri

withQuery(?string $query): static

Добавить фильтр к готовой ссылке каталога.

Запись withQuery(?string $query): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$queryСтрока search: допускается начальный ?, который снимается. null и "" удаляют query; "?" оставляет пустой query. WHATWG кодирует нужные символы, но не разделяет значения параметров за вас.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Добавить фильтр к готовой ссылке каталога.
  1. https://shop.example/catalog
  2. withQuery('category=tools&page=2')
  3. https://shop.example/catalog?category=tools&page=2
  4. $original по-прежнему https://shop.example/catalog
Добавить фильтр к готовой ссылке каталога.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('https://shop.example/catalog');
$changed = $original->withQuery('category=tools&page=2');
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/catalog?category=tools&page=2
https://shop.example/catalog

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withQueryСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/find?q=old');
$query = http_build_query(['q' => 'drill set'], '', '&', PHP_QUERY_RFC3986);
echo $u->withQuery($query)->toAsciiString(), "\n";
echo $u->withQuery('')->toAsciiString(), "\n";
echo $u->withQuery('?')->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/find?q=drill%20set
https://shop.example/find
https://shop.example/find?

Пустая строка здесь удаляет компонент, что отличается от RFC withQuery(""). http_build_query задаёт границы данных: простой "q=" . $input позволил бы & в input добавить другой параметр.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getQuery, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::withFragmentСоздать ссылку на конкретную часть справки.

PHP 8.5.0+ · uri

withFragment(?string $fragment): static

Создать ссылку на конкретную часть справки.

Запись withFragment(?string $fragment): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$fragmentFragment, допускается начальная #. null и "" удаляют fragment, "#" задаёт явно пустой. Нужные символы кодируются по WHATWG; HTML id не проверяется.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Создать ссылку на конкретную часть справки.
  1. https://shop.example/help
  2. withFragment('delivery')
  3. https://shop.example/help#delivery
  4. $original по-прежнему https://shop.example/help
Создать ссылку на конкретную часть справки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('https://shop.example/help');
$changed = $original->withFragment('delivery');
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/help#delivery
https://shop.example/help

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withFragmentСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/help#delivery');
echo $u->withFragment('part two')->toAsciiString(), "\n";
echo $u->withFragment('')->toAsciiString(), "\n";
echo $u->withFragment('#')->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/help#part%20two
https://shop.example/help
https://shop.example/help#

Три разных намерения: имя с пробелом, отсутствие fragment, пустой fragment. Это не установка DOM-фокуса и не проверка наличия раздела: UI выполняет их отдельно.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getFragment, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::withUsernameУдалить имя из ссылки со встроенными credentials.

PHP 8.5.0+ · uri

withUsername(?string $username): static

Удалить имя из ссылки со встроенными credentials.

Запись withUsername(?string $username): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$usernameОтдельное имя: символы-разделители кодируются. null и "" очищают имя, но не пароль. Наличие password может сохранить пустой username; URL без host/file не поддерживает обычные credentials.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Удалить имя из ссылки со встроенными credentials.
  1. https://anna@shop.example/p
  2. withUsername(null)
  3. https://shop.example/p
  4. $original по-прежнему https://anna@shop.example/p
Удалить имя из ссылки со встроенными credentials.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('https://anna@shop.example/p');
$changed = $original->withUsername(null);
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://shop.example/p
https://anna@shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withUsernameСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://shop.example/p');
$withName = $u->withUsername('team:west');
echo $withName->getUsername(), "\n";
echo $withName->withUsername(null)->toAsciiString(), "\n";
Ожидаемый результат
team%3Awest
https://shop.example/p

Передаём отдельное имя, не user:password. WHATWG кодирует двоеточие как данные имени. Для полного удаления credentials требуется также withPassword(null).

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getUsername, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\Url::withPasswordУдалить пароль из фиктивной учебной ссылки.

PHP 8.5.0+ · uri

withPassword(#[\SensitiveParameter] ?string $password): static

Удалить пароль из фиктивной учебной ссылки.

Запись withPassword(#[\SensitiveParameter] ?string $password): static описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$passwordОтдельный пароль: специальные символы кодируются; null/"" очищают только пароль. #[SensitiveParameter] относится к аргументу, но не к возвращённому объекту/его сериализации. URL без подходящего host не поддерживает credentials.
РезультатНовый объект того же final readonly класса; исходный не изменён. Для WHATWG новое значение может нормализоваться или не примениться по правилам URL setter.
ОтказНекорректный компонент или недопустимое сочетание компонентов: Uri\InvalidUriException (у WHATWG — подкласс Uri\WhatWg\InvalidUrlException с errors). Неверный PHP-тип: TypeError при strict_types=1. Исходный объект не меняется даже при отказе.
ВерсияPHP 8.5.0; для 8.2–8.4 эти классы недоступны.
Удалить пароль из фиктивной учебной ссылки.
  1. https://anna:demo@shop.example/p
  2. withPassword(null)
  3. https://anna@shop.example/p
  4. $original по-прежнему https://anna:demo@shop.example/p
Удалить пароль из фиктивной учебной ссылки.Самостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$original = new Url('https://anna:demo@shop.example/p');
$changed = $original->withPassword(null);
echo $changed->toAsciiString(), "\n";
echo $original->toAsciiString(), "\n";
Ожидаемый результат
https://anna@shop.example/p
https://anna:demo@shop.example/p

with-метод создаёт новый объект. = сохраняет его в $changed; $original остаётся прежним. Если вызвать метод и отбросить возвращённое значение, дальнейшая работа со старой переменной не увидит изменения.

Теперь изменим требование и проверим конкретную границу этого компонента. try выполняет попытку, catch перехватывает только указанный отказ; создание/изменение строки не отправляет запрос.

Проверить ограничения: withPasswordСамостоятельный пример
<?php
declare(strict_types=1);

use Uri\WhatWg\Url as Url;

$u = new Url('https://anna@shop.example/p');
$test = $u->withPassword('demo:west');
echo $test->getPassword(), "\n";
echo $test->withUsername(null)->withPassword(null)->toAsciiString(), "\n";
Ожидаемый результат
demo%3Awest
https://shop.example/p

Только фиктивный demo:west допустим для вывода в уроке. В реальном интерфейсе не печатайте пароль. Смена username не очищает password, поэтому очищены оба поля.

Операция заменяет этот компонент, не обещая бизнес-корректность всего адреса. После сборки проверьте схему, host, port, credentials и нужные ограничения пути. Измеряйте стоимость на своих данных: последовательные with-вызовы создают отдельные объекты; не нужна цепочка ради самой цепочки.

Практика: предскажите результат повторного вызова с тем же аргументом и сравните строки. Даже если строки совпали, новый объект и исходный объект не обязаны быть тождественны по ===.

Перед первым запуском: как устроен вызов и что он проверяет.

Следующий шаг: Uri\WhatWg\Url::getPassword, Uri\WhatWg\Url::toAsciiString.

Uri\WhatWg\UrlValidationError::__constructСоздать запись для адаптера или теста отображения ошибок.

PHP 8.5.0+ · uri

__construct(string $context, Uri\WhatWg\UrlValidationErrorType $type, bool $failure)

Создать запись для адаптера или теста отображения ошибок.

Запись __construct(string $context, Uri\WhatWg\UrlValidationErrorType $type, bool $failure) описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$contextСтрока контекста; может быть чувствительной, не обещан номер позиции.
$typeКонкретный case pure enum, не его строковое имя.
$failurebool; true = отказ, false = мягкая диагностика.
Результатnew возвращает final readonly объект с public context/type/failure.
ОшибкаНеверные PHP-типы — TypeError в strict mode. Соответствие context/type не вычисляется; это контейнер, не валидатор.
Тест сообщения о порте
  1. :70000 + PortOutOfRange + true
  2. new UrlValidationError
  3. type и failure доступны через ->
  4. Нужна правка
Подготовить фиктивную запись для теста интерфейсаСамостоятельный пример
<?php
declare(strict_types=1);

$item = new Uri\WhatWg\UrlValidationError(
    ':70000', Uri\WhatWg\UrlValidationErrorType::PortOutOfRange, true
);
echo $item->type->name, "\n";
echo $item->failure ? "Нужна правка\n" : "Можно рассмотреть исправление\n";
Ожидаемый результат
PortOutOfRange
Нужна правка

new создаёт диагностические данные. Этот вызов не анализирует :70000, а принимает уже выбранные type/failure. Для настоящего разбора нужен Url::parse.

Не менять уже переданную диагностическую записьСамостоятельный пример
<?php
declare(strict_types=1);

$item = new Uri\WhatWg\UrlValidationError('sample', Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit, false);
try { $item->failure = true; } catch (Error $e) { echo "Запись readonly\n"; }
echo $item->failure ? "hard\n" : "soft\n";
Ожидаемый результат
Запись readonly
soft

Тип final readonly исключает наследование и изменение полей после инициализации. Если тесту нужен другой результат, создайте другую запись; не переписывайте историю ошибки.

Перед первым запуском: как устроен вызов и что он проверяет.

Uri\WhatWg\InvalidUrlException::__constructПередать отказ URL вместе со структурированной причиной вызывающему коду.

PHP 8.5.0+ · uri

__construct(string $message = "", array $errors = [], int $code = 0, ?Throwable $previous = null)

Передать отказ URL вместе со структурированной причиной вызывающему коду.

Запись __construct(string $message = "", array $errors = [], int $code = 0, ?Throwable $previous = null) описывает договор PHP 8.5+. $ перед именем обозначает параметр, ? перед типом допускает null; null означает отсутствие, а пустая строка — отдельное значение. static в возвращаемом типе означает объект того же класса. Вызов без аргументов всё равно заканчивается скобками ().

Часть договораСмысл
$messageЧеловеческое описание, по умолчанию ""; не включайте секретный адрес без необходимости.
$errorsСписок UrlValidationError, по умолчанию []. Public readonly array после создания. Значения-ссылки и не-list/не-объекты отклоняются ValueError в PHP 8.5.11.
$codeЦелое число приложения, default0; не обязан быть HTTP-статусом.
$previousПредыдущая причина Throwable либо null.
Результат/ошибкиnew возвращает исключение; не бросает его сам. TypeError для неверного типа; ValueError для неправильного списка; readonly-защита при повторной инициализации errors.
Адресный отказ
  1. Готовая запись PortOutOfRange
  2. [$item] → errors
  3. message и code17 → Exception
  4. Доступны getMessage и errors[0]
Собрать адресный отказ из диагностической записиСамостоятельный пример
<?php
declare(strict_types=1);

$item = new Uri\WhatWg\UrlValidationError(':70000', Uri\WhatWg\UrlValidationErrorType::PortOutOfRange, true);
$error = new Uri\WhatWg\InvalidUrlException('Ссылка карточки17 отклонена', [$item], 17);
echo $error->getMessage(), "\n";
echo $error->errors[0]->type->name, "\n";
Ожидаемый результат
Ссылка карточки17 отклонена
PortOutOfRange

[$item] — список с индексом0. Код17 принадлежит приложению. Объект исключения пока только создан; чтобы прервать выполнение, понадобился бы throw $error.

Проверить структуру диагностического спискаСамостоятельный пример
<?php
declare(strict_types=1);

$cause = new RuntimeException('Фиктивная причина импорта');
$error = new Uri\WhatWg\InvalidUrlException('Адрес отклонён', [], 0, $cause);
echo $error->getPrevious() === $cause ? "Причина сохранена\n" : "Нет причины\n";
try { new Uri\WhatWg\InvalidUrlException('bad', ['message']); }
catch (ValueError $e) { echo "Нужен список UrlValidationError\n"; }
Ожидаемый результат
Причина сохранена
Нужен список UrlValidationError

Массив должен быть последовательным списком диагностических объектов. Строки, произвольные ключи и ссылочные элементы не принимаются (проверено по PHP 8.5.11). Это строже простого типа array в сигнатуре.

Перед первым запуском: как устроен вызов и что он проверяет.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.