Перейти к содержимому
Поиск
Php Разработка

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

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11468 глав6256 карточек справочника
Дерево руководства

Глава 165 · После первого каталога; регулярные выражения вводятся постепенно

MongoDB: BSON Regex, буквальный ввод и понятный поиск каталога

Префикс, скобки и плюс, регистр, многострочные флаги, проверка формы, массивы меток, сохранённые правила, интерфейс, Extended JSON и фактический explain.

От запроса посетителя к нужным карточкам

Пользователь вводит CUP- и хочет увидеть первые карточки с таким началом артикула. Другой вводит Mug (XL)+ и ожидает буквальные скобки и плюс. Третьему нужен полный cup без зависимости от регистра. Эти задачи похожи внешне, но требуют разных условий. В этой главе сначала получим понятные товары, затем разберём, как передать правило MongoDB и сохранить его без потери смысла.

Регулярное выражение, или regex, — текстовое правило сопоставления. Обычные буквы обозначают себя; отдельные символы имеют специальный смысл. Например, ^CUP- означает CUP- в начале строки. Pattern — сам шаблон; flags — отдельные режимы вроде i для игнорирования регистра. Не нужно заранее знать сложную грамматику: для первого поиска достаточно этих двух частей.

В BSON Regex объект служит контейнером pattern/flags. new создаёт контейнер; стрелка -> вызывает метод чтения его значений; поиск начинается лишь после отправки Query через Manager. На сайте PHP preg_match выполняет сопоставление в PHP, а BSON Regex отправляется базе. Базовый маршрут: шаблоны PHP, объекты и вызовы методов, первый каталог MongoDB. Текущий раздел объясняет именно границу с сервером.

Первый фильтр до передачи в PHP результата
  1. Документы CUP-01, CUP-02, X-CUP-03, LAMP-01
  2. Требование: начало артикула → pattern ^CUP-, flags пусты
  3. Query: поле sku + projection + sort + limit
  4. MongoDB сопоставляет строки → PHP получает только CUP-01 и CUP-02
$rule = new MongoDB\BSON\Regex('^CUP-');
$filter = ['sku' => $rule];

Здесь ^ — якорь начала, CUP- — буквальный префикс, sku — выбранное поле документа. Второй аргумент flags пропущен и равен пустой строке. Это ещё описание запроса; полный самостоятельный первый пример ниже выполняет его и показывает две карточки.

PHP pattern, BSON Regex и серверный запрос

ЗаписьГде действуетЧто обозначает
preg_match('/^CUP-/', $text)PHPПроверка уже полученной строки средствами PHP
new MongoDB\BSON\Regex('^CUP-', 'i')BSON-значениеPattern без внешних delimiter и отдельные flags
['sku' => $rule]Фильтр MongoDBПравило для поля sku, выполняемое базой
(string)$ruleПредставлениеСтрока для диагностики, не готовый PHP pattern
json_encode($rule)JSON-представлениеВызов JsonSerializable; формат нужно согласовать с получателем

Не все похожие записи взаимозаменяемы. В BSON pattern нельзя копировать внешние /.../ из preg_match. Если slash является частью самого названия, он остаётся данными. Пользовательская строка проходит preg_quote, когда требуется буквальный поиск; это не превращает строку в произвольную программу.

В MongoDB 6.1+ сопоставление выполняет PCRE2. Поддерживаемые серверные options включают i, m, s, x; u принимается, но UTF уже включён. g не является глобальным режимом поиска MongoDB. Для x/s в этой главе применяется документированная операторная форма $regex с отдельным $options. Ввод посетителя не выбирает эти режимы свободно.

Запустить программы и открыть реальные результаты

Девять архивов — самостоятельные CLI-программы для PHP 8.4+ / ext-mongodb 2.5+ и отдельной MongoDB 8.0+. Используемый стенд: PHP 8.5.11, расширение 2.5.5, сервер 8.0.34. Composer не требуется. README каждого ZIP описывает установку подходящей DLL, выбор CLI php.ini и запуск собственного mongod с отдельным каталогом данных и bind_ip=127.0.0.1.

php --ri mongodb
$env:PHPMAN_MONGODB_URI='mongodb://127.0.0.1:27075/?directConnection=true&retryWrites=false'
$env:PHPMAN_MONGODB_DATABASE='php_manual_lab'
php example.php

Рядом должны находиться example.php и mr126-helper.php из одного архива. После запуска откройте result.html: там таблица настоящего результата и промежуточные данные. result.json содержит строки таблицы; metrics.json — версии, проверки и SHA256. Готовые результаты на странице не отправляют запросы с браузера читателя в учебную базу.

Все примеры создают только свою коллекцию mongodb126_regex_… со случайным окончанием. После успешного create появляется право удалить это точное имя; finally выполняет очистку, listCollections проверяет отсутствие. Собственный индекс последнего примера исчезает вместе с коллекцией. Рабочие данные и настройки сервера не меняются; принудительное завершение процесса может прервать finally.

Первые карточки: артикул начинается с CUP-

На странице категории нужны кружки с артикулами CUP-01 и CUP-02. Набор X-CUP-03 содержит похожий фрагмент, но не относится к выбранному префиксу. Получим только две нужные карточки, сразу ограничив поля и число строк в запросе.

Входные данные и понятия

Вход — четыре документа с ID, sku и title. Префикс — начальная часть текста. Шаблон ^CUP- читается как «начало строки, затем буквальные CUP-». Символ ^ здесь имеет специальное значение, а остальные символы просто описывают артикул. BSON Regex хранит этот шаблон для MongoDB; сам объект не запускает поиск.

Как строится и выполняется поиск
  1. Четыре артикула → выбрать требование «начинается с CUP-»
  2. Создать Regex с pattern ^CUP-, flags пусты
  3. Поле sku → фильтр MongoDB; projection, sort и limit заданы до PHP
  4. База возвращает CUP-01/CUP-02 → таблица двух товаров

Короткая запись текущего действия

$rule = new MongoDB\BSON\Regex('^CUP-');
$filter = ['sku' => $rule]; // ^ означает начало строки, а не любой фрагмент.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

IDАртикулНазвание
1CUP-01Белая кружка
2CUP-02Синяя кружка

Как понимать результат

Шаблон передаётся без PHP-разделителей /.../. Второй аргумент необязателен и здесь равен пустой строке. Helper выполняет настоящий find, выбирает ID, sku, title, сортирует по ID и ограничивает выдачу двумя строками. Набор X-CUP-03 не совпадает, потому что CUP- находится не в начале.

Границы и ошибки применения

limit ограничивает выдачу, но сам по себе не доказывает дешёвую обработку запроса. Если предметная модель уже имеет поле category, обычное равенство по category может лучше выражать категорию. Regex полезен, когда требование действительно касается формы текста. Для полного точного артикула сначала рассмотрите обычное равенство.

Полная самостоятельная программа, helper и архив
Первые карточки: артикул начинается с CUP-Самостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
mr126Insert($manager,$namespace,[['_id'=>1,'sku'=>'CUP-01','title'=>'Белая кружка'],['_id'=>2,'sku'=>'CUP-02','title'=>'Синяя кружка'],
        ['_id'=>3,'sku'=>'X-CUP-03','title'=>'Набор'],['_id'=>4,'sku'=>'LAMP-01','title'=>'Лампа']]);
    $rule=new MongoDB\BSON\Regex('^CUP-');$found=mr126Find($manager,$namespace,['sku'=>$rule],['_id'=>1,'sku'=>1,'title'=>1],2);
    $checks=['only_prefix_items'=>mr126Ids($found)===[1,2],'default_empty_flags'=>$rule->getFlags()==='',
        'pattern_has_anchor'=>$rule->getPattern()==='^CUP-','typed_regex'=>$rule instanceof MongoDB\BSON\RegexInterface];
    $details=['rule'=>mr126Describe($rule),'found'=>$found];
    return array_map(fn($d)=>[$d['_id'],$d['sku'],$d['title']],$found);
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-sku-prefix',['ID', 'Артикул', 'Название'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-sku-prefix: OK
';
Ожидаемый результат
mongodb126-regex-sku-prefix: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Поменяйте pattern на CUP- без ^. Набор X-CUP-03 тоже начнёт подходить. Чтобы увидеть его, увеличьте только учебный limit до 3. Сначала формулируйте требование к строке, затем выбирайте синтаксис.

Найти название со скобками и плюсом как обычный текст

Посетитель ввёл название Mug (XL)+. Скобки и плюс для него являются частью товара. Если отправить ввод прямо как regex, скобки станут группой, а плюс — повторением. Нужен поиск буквального фрагмента, который найдёт синий товар и подарочный вариант с теми же символами.

Входные данные и понятия

Есть четыре названия. Два содержат точный фрагмент Mug (XL)+, одно содержит Mug XL без скобок/плюса, одно — другой размер. preg_quote превращает специальные для regex символы в буквальные. Это подготовка pattern в PHP, а не выполнение серверного поиска.

Как строится и выполняется поиск
  1. Текст формы Mug (XL)+ → считать его данными
  2. preg_quote → экранированный pattern без разделителей
  3. Regex передан фильтру title → поиск выполняет MongoDB
  4. ID 1 и 3 найдены; похожий текст без нужных символов не проходит

Короткая запись текущего действия

$text = 'Mug (XL)+';
$rule = new MongoDB\BSON\Regex(preg_quote($text));
// Скобки и плюс во вводе остаются буквальными символами названия.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

IDНайденное название
1Mug (XL)+ blue
3Gift: Mug (XL)+ red

Как понимать результат

Здесь нет начального ^, поэтому буквальный фрагмент допускается внутри названия Gift: Mug (XL)+ red. В diagnostics сохранены исходный текст, экранированный pattern, flags и найденные документы. Все значения исходного ввода остаются обычными данными и не задают операторы MongoDB.

Границы и ошибки применения

preg_quote решает задачу буквального текста, но не ограничивает длину, разрешённые поля, стоимость поиска или доступ пользователя. Эти условия добавляются отдельно. Второй аргумент delimiter для BSON-шаблона не нужен: внешних PHP-разделителей здесь нет. Не пытайтесь обезвредить ввод только ручной заменой скобки — специальных символов больше.

Полная самостоятельная программа, helper и архив
Найти название со скобками и плюсом как обычный текстСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
mr126Insert($manager,$namespace,[['_id'=>1,'sku'=>'M-1','title'=>'Mug (XL)+ blue'],['_id'=>2,'sku'=>'M-2','title'=>'Mug XL blue'],
        ['_id'=>3,'sku'=>'M-3','title'=>'Gift: Mug (XL)+ red'],['_id'=>4,'sku'=>'M-4','title'=>'Mug (L) red']]);
    $text='Mug (XL)+';$rule=new MongoDB\BSON\Regex(preg_quote($text));
    $found=mr126Find($manager,$namespace,['title'=>$rule]);
    $checks=['literal_not_group'=>mr126Ids($found)===[1,3],'quote_preserves_punctuation'=>$rule->getPattern()===preg_quote($text),
        'no_injected_flags'=>$rule->getFlags()===''];
    $details=['input'=>$text,'rule'=>mr126Describe($rule),'found'=>$found];
    return array_map(fn($d)=>[$d['_id'],$d['title']],$found);
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-literal-title',['ID', 'Найденное название'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-literal-title: OK
';
Ожидаемый результат
mongodb126-regex-literal-title: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Добавьте товар, содержащий буквальное [sale]. Для поиска используйте ту же preg_quote, а не новый набор ручных replace. Затем сравните поиск фрагмента с префиксом ^ плюс тем же экранированным вводом.

Вопрос из практики: BSON Regex search with parentheses. Буквальный текст названия со скобками становится regex-синтаксисом. Урок использует preg_quote и собственные товары, не повторяет ответ с ручным экранированием. Обсуждение используется как постановка задачи, не как современная техническая спецификация. Решение и данные составлены отдельно.

Вхождение, полное совпадение и регистр — разные требования

Форма выбора значения должна найти Cup, cup и CUP, но не cup-holder, teacup или строку с лишним переводом строки. Флаг i разрешает разный регистр, однако сам по себе не ограничивает длину совпадения. Покажем три разных требования на одной коллекции.

Входные данные и понятия

Шесть строк отличаются регистром, положением cup и завершающим переводом строки. Обычное равенство name=cup использует стандартное сравнение нашего стенда. Regex cup с i ищет вхождение без учёта регистра. Границы \A и \z требуют начало и абсолютный конец всей строки.

Как строится и выполняется поиск
  1. Одна коллекция из шести имён
  2. Обычное равенство cup → только ID 2
  3. Regex cup + i → все шесть содержат нужный фрагмент
  4. Regex \Acup\z + i → только ID 1, 2, 3

Короткая запись текущего действия

$contains = new MongoDB\BSON\Regex('cup', 'i');
$whole = new MongoDB\BSON\Regex('\A' . preg_quote('cup') . '\z', 'i');
// i меняет регистр; \A и \z задают абсолютные границы всей строки.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

ТребованиеID результата
Обычное равенство2
Вхождение, i1, 2, 3, 4, 5, 6
Вся строка, i1, 2, 3

Как понимать результат

Таблица не объявляет один запрос «правильнее» другого: каждый соответствует своему требованию. Для строгого полного совпадения использованы абсолютные границы, чтобы не принять лишний перевод строки. $ в некоторых режимах допускает позицию перед завершающим переводом строки; эта тонкость важна для проверки целого значения.

Границы и ошибки применения

i — регистронезависимость, а не поиск без диакритики, не fuzzy-поиск и не языковая collation. Важные идентификаторы лучше хранить с явным договором нормализации и обычным равенством/индексом, когда это соответствует предметной области. Данный пример сравнивает ASCII cup; он не обещает одинаковую нормализацию всех языков.

Полная самостоятельная программа, helper и архив
Вхождение, полное совпадение и регистр — разные требованияСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
$names=['Cup','cup','CUP','cup-holder','teacup',"cup\n"];$documents=[];
    foreach ($names as $i=>$name) { $documents[]=['_id'=>$i+1,'name'=>$name]; }
    mr126Insert($manager,$namespace,$documents);
    $contains=new MongoDB\BSON\Regex('cup','i');$exact=new MongoDB\BSON\Regex('\Acup\z','i');
    $filters=['Обычное равенство'=>['name'=>'cup'],'Вхождение, i'=>['name'=>$contains],'Вся строка, i'=>['name'=>$exact]];
    $rows=[];$ids=[];
    foreach ($filters as $label=>$filter) { $ids[$label]=mr126Ids(mr126Find($manager,$namespace,$filter,['_id'=>1,'name'=>1]));$rows[]=[$label,implode(', ',$ids[$label])]; }
    $checks=['equality_is_exact_case'=>$ids['Обычное равенство']===[2],'contains_has_six'=>$ids['Вхождение, i']===[1,2,3,4,5,6],
        'absolute_boundaries_three'=>$ids['Вся строка, i']===[1,2,3],'flag_is_i'=>$exact->getFlags()==='i'];
    $details=['input_names'=>$names,'contains'=>mr126Describe($contains),'whole_string'=>mr126Describe($exact)];return $rows;
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-case-and-boundaries',['Требование', 'ID результата'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-case-and-boundaries: OK
';
Ожидаемый результат
mongodb126-regex-case-and-boundaries: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Добавьте строку cupcake и повторите три запроса. Она должна войти во вхождение, но не в полный матч. Для кода регистрации логина сформулируйте правила пробелов и регистра отдельно, до выбора regex.

Многострочное описание: m, s, x и порядок флагов

Импортированные описания содержат строки Header и stock: 7, иногда число находится на новой строке. Нужно понимать, какой флаг меняет границы строк, какой — поведение точки, а какой позволяет комментировать шаблон. Это три отдельные возможности.

Входные данные и понятия

ID 1 содержит Header, затем stock: 7; ID 2 начинается с stock: 0; ID 3 содержит stock:, затем 7. Флаг m заставляет ^/$ учитывать границы каждой строки. Флаг s разрешает точке совпасть с переводом строки. Флаг x игнорирует неэкранированные пробелы и комментарий от # до конца строки в самом pattern.

Как строится и выполняется поиск
  1. Три известных многострочных notes → фиксированные безопасные правила
  2. ^stock: без m проверяет начало всего текста; с m — начало каждой строки
  3. stock:.*7 с s проходит через перевод строки
  4. x сохраняет нужный пробел через [ ]; mi сохраняется как im

Короткая запись текущего действия

$rule = new MongoDB\BSON\Regex('stock:.*7', 's');
$filter = ['notes' => ['$regex'=>$rule->getPattern(), '$options'=>$rule->getFlags()]];
// s позволяет точке пройти через перевод строки; m имеет другое назначение.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

ВариантСохранённые flagsID результата
Без m2, 3
mm1, 2, 3
ss1, 3
xx1
mi → imim1, 2, 3

Как понимать результат

Для флагов s/x используется операторная форма $regex + $options. Pattern и flags берутся из объекта Regex, поэтому сохраняется явное разделение частей. В варианте x класс [ ] обозначает настоящий пробел данных; без него пробел шаблона был бы проигнорирован. Конструктор сортирует буквы mi в im, не меняя выбранные режимы.

Границы и ошибки применения

Флаг m не позволяет точке перескакивать через новую строку: это действие s. x изменяет чтение шаблона, а не удаляет пробелы из документа. u сервер принимает, но UTF уже включён по умолчанию; g не поддерживается как глобальный модификатор MongoDB. Набор флагов должен задавать разработчик, а не произвольное поле формы.

Полная самостоятельная программа, helper и архив
Многострочное описание: m, s, x и порядок флаговСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
mr126Insert($manager,$namespace,[['_id'=>1,'notes'=>"Header\nstock: 7"],['_id'=>2,'notes'=>"stock: 0\nend"],['_id'=>3,'notes'=>"stock:\n7"]]);
    $rules=['Без m'=>new MongoDB\BSON\Regex('^stock:'),'m'=>new MongoDB\BSON\Regex('^stock:','m'),
        's'=>new MongoDB\BSON\Regex('stock:.*7','s'),'x'=>new MongoDB\BSON\Regex("stock: [ ] 7 # quantity\n",'x'),
        'mi → im'=>new MongoDB\BSON\Regex('^STOCK:','mi')];
    $rows=[];$found=[];$descriptions=[];
    foreach ($rules as $label=>$rule) {
        $filter=['notes'=>['$regex'=>$rule->getPattern(),'$options'=>$rule->getFlags()]];
        $found[$label]=mr126Ids(mr126Find($manager,$namespace,$filter,['_id'=>1,'notes'=>1]));
        $rows[]=[$label,$rule->getFlags(),implode(', ',$found[$label])];$descriptions[$label]=mr126Describe($rule);
    }
    $checks=['no_m_first_line'=>$found['Без m']===[2,3],'m_each_line'=>$found['m']===[1,2,3],
        's_crosses_newline'=>$found['s']===[1,3],'x_comment_and_spaces'=>$found['x']===[1],
        'flags_sorted'=>$rules['mi → im']->getFlags()==='im' && $found['mi → im']===[1,2,3]];
    $details=['rules'=>$descriptions,'notes'=>["Header\nstock: 7","stock: 0\nend","stock:\n7"]];return $rows;
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-multiline-flags',['Вариант', 'Сохранённые flags', 'ID результата'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-multiline-flags: OK
';
Ожидаемый результат
mongodb126-regex-multiline-flags: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Уберите s из правила stock:.*7: ID 3 перестанет подходить, ID 1 останется. Затем уберите m из ^stock: и объясните, почему ID 1 исчезает, а ID 3 остаётся.

Форма принимает текст, а не произвольный запрос или regex

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

Входные данные и понятия

Разрешены только поля sku/title и строка длиной 2–80 байт без NUL. Это осознанный транспортный лимит байт; для ограничения числа символов UTF-8 потребовалось бы отдельное правило. Первые два случая — обычный текст, остальные содержат запрещённое поле, массив, пустую/слишком длинную строку или нулевой байт.

Как строится и выполняется поиск
  1. Проверить тип и allowlist поля → проверить текст
  2. Допустимый текст → preg_quote → ^literal → свой Query
  3. Недопустимый ввод → ответ приложения без запроса
  4. Отдельная фиксированная ошибка разработчика [ → constructor сохраняет, сервер отвергает 51091

Короткая запись текущего действия

if (!is_string($field) || !in_array($field, ['sku','title'], true)) {
    throw new InvalidArgumentException('field_not_allowed');
}
$filter = [$field => new MongoDB\BSON\Regex('^' . preg_quote($text))];
// Полный helper также проверяет тип, длину и NUL в text.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

СлучайРешение программыID или причина отсутствия запроса
1Принят1, 2
2Принят1
3Отклонён: field_not_allowedЗапрос не отправлен
4Отклонён: invalid_search_textЗапрос не отправлен
5Отклонён: invalid_search_textЗапрос не отправлен
6Отклонён: invalid_search_textЗапрос не отправлен
7Отклонён: invalid_search_textЗапрос не отправлен

Как понимать результат

Пять пользовательских случаев отвергнуты до обращения к MongoDB. Для допустимых случаев поля выдачи и limit тоже задаёт код. В diagnostics отдельно проверены NUL в constructor pattern/flags и синтаксически неверный постоянный pattern [. Конструктор BSON-значения не компилирует серверный regex: успешное создание объекта не гарантирует успешный запрос.

Границы и ошибки применения

В production нужны также права пользователя и обязательные фильтры области данных. Это не готовая система авторизации. maxTimeMS ограничивает обработку серверной операции, но не обещает фиксированное общее время HTTP. Обрабатывается только ожидаемый код 51091; неизвестные ошибки не превращаются в успешный пустой поиск. Произвольный regex посетителя не допускается.

Полная самостоятельная программа, helper и архив
Форма принимает текст, а не произвольный запрос или regexСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
mr126Insert($manager,$namespace,[['_id'=>1,'sku'=>'CUP-01','title'=>'Mug (XL)'],['_id'=>2,'sku'=>'CUP-02','title'=>'Mug small']]);
    $cases=[['sku','CUP-'],['title','Mug (XL)'],['$where','CUP-'],['title',['$ne'=>'']],['title',''],['title',str_repeat('a',81)],['title',"a\0b"]];
    $rows=[];$statuses=[];
    foreach ($cases as $i=>[$field,$input]) {
        try { $filter=mr126InputRule($field,$input);$result=mr126Find($manager,$namespace,$filter,['_id'=>1,'sku'=>1],3);
            $status='Принят';$ids=implode(', ',mr126Ids($result)); }
        catch (InvalidArgumentException $error) { $status='Отклонён: '.$error->getMessage();$ids='Запрос не отправлен'; }
        $statuses[]=$status;$rows[]=[$i+1,$status,$ids];
    }
    $nulPattern=false;$nulFlags=false;
    try { new MongoDB\BSON\Regex("x\0y"); } catch (MongoDB\Driver\Exception\InvalidArgumentException) { $nulPattern=true; }
    try { new MongoDB\BSON\Regex('x',"i\0m"); } catch (MongoDB\Driver\Exception\InvalidArgumentException) { $nulFlags=true; }
    $invalid=new MongoDB\BSON\Regex('[');$serverCode=null;
    try { mr126Find($manager,$namespace,['title'=>$invalid]); }
    catch (MongoDB\Driver\Exception\CommandException $error) { if ($error->getCode()!==51091) { throw $error; }$serverCode=$error->getCode(); }
    $checks=['allowed_searches'=>$rows[0][2]==='1, 2' && $rows[1][2]==='1','five_rejected_before_query'=>count(array_filter($statuses,fn($s)=>str_starts_with($s,'Отклонён:')))===5,
        'constructor_nul_rejected'=>$nulPattern && $nulFlags,'syntax_checked_by_server'=>$invalid->getPattern()==='[' && $serverCode===51091];
    $details=['input_cases'=>['sku/CUP-','title/Mug (XL)','$where forbidden','array instead of text','empty text','81 bytes','embedded NUL'],
        'fixed_programmer_error'=>['constructor_accepted'=>$invalid->getPattern(),'server_code'=>$serverCode],
        'constructor_rejects_nul'=>['pattern'=>$nulPattern,'flags'=>$nulFlags]];return $rows;
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-input-policy',['Случай', 'Решение программы', 'ID или причина отсутствия запроса'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-input-policy: OK
';
Ожидаемый результат
mongodb126-regex-input-policy: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Добавьте разрешённое поле brand с собственным индексом и определённым назначением. Измените allowlist и подготовьте реальные данные; не заменяйте allowlist проверкой «в поле нет пробелов». Для кириллицы отдельно решите, нужен ли лимит байт или символов.

Массив меток: совпадение элемента, elemMatch и набор правил

У товара несколько меток: blue, metal, wood. Требуется найти целую метку blue, а не blueberry. Затем условие расширяется до blue или red. Покажем, как Regex применяется к элементам массива и почему $elemMatch нельзя заполнять одним голым объектом Regex.

Входные данные и понятия

Четыре товара содержат массивы строк labels. Правила blue/red заключены между абсолютными границами и используют i. Прямой Regex в поле массива может совпасть с отдельным строковым элементом. $elemMatch принимает документ условий; в нём $regex и $options оформлены операторами.

Как строится и выполняется поиск
  1. labels каждого товара → сравнивать строковые элементы
  2. Прямое правило целого blue → ID 1 и 3
  3. $elemMatch с документом условий → те же ID 1 и 3
  4. $in из двух BSON Regex → ID 1, 3 и 4

Короткая запись текущего действия

$blue = new MongoDB\BSON\Regex('\Ablue\z', 'i');
$filter = ['labels' => $blue]; // Совпасть может один строковый элемент списка.
$explicit = ['labels' => ['$elemMatch' => ['$regex'=>$blue->getPattern(), '$options'=>$blue->getFlags()]]];

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

ПоискID товаров
Один Regex1, 3
Оператор в elemMatch1, 3
blue или red1, 3, 4

Как понимать результат

Первый и второй запросы дают одинаковый результат при одном условии и известной схеме массива. Второй полезен как корректная форма для дальнейшего развития условий одного элемента. В $in передаются именно BSON Regex-значения; вложенные документы оператора $regex не являются заменой этого синтаксиса.

Границы и ошибки применения

В этом примере labels гарантированно массив строк. Прямая форма может также совпасть со скалярной строкой в смешанной схеме, тогда как $elemMatch требует массив. Для массива документов нужно отдельно понимать совместность нескольких условий одного элемента. Не вставляйте PHP-строку /blue/i в pattern: разделители станут частью серверного шаблона.

Полная самостоятельная программа, helper и архив
Массив меток: совпадение элемента, elemMatch и набор правилСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
mr126Insert($manager,$namespace,[['_id'=>1,'sku'=>'A','labels'=>['blue','metal']],['_id'=>2,'sku'=>'B','labels'=>['blueberry','wood']],
        ['_id'=>3,'sku'=>'C','labels'=>['blue','wood']],['_id'=>4,'sku'=>'D','labels'=>['red']]]);
    $blue=new MongoDB\BSON\Regex('\Ablue\z','i');$red=new MongoDB\BSON\Regex('\Ared\z','i');
    $filters=['Один Regex'=>['labels'=>$blue],'Оператор в elemMatch'=>['labels'=>['$elemMatch'=>['$regex'=>$blue->getPattern(),'$options'=>$blue->getFlags()]]],
        'blue или red'=>['labels'=>['$in'=>[$blue,$red]]]];
    $rows=[];$ids=[];
    foreach ($filters as $label=>$filter) { $ids[$label]=mr126Ids(mr126Find($manager,$namespace,$filter,['_id'=>1,'sku'=>1,'labels'=>1]));$rows[]=[$label,implode(', ',$ids[$label])]; }
    $checks=['direct_element_match'=>$ids['Один Regex']===[1,3],'elemmatch_object_shape'=>$ids['Оператор в elemMatch']===[1,3],
        'in_uses_bson_regex_values'=>$ids['blue или red']===[1,3,4]];
    $details=['rules'=>[mr126Describe($blue),mr126Describe($red)],'all_labels'=>mr126Find($manager,$namespace,[],['_id'=>1,'labels'=>1])];return $rows;
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-label-arrays',['Поиск', 'ID товаров'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-label-arrays: OK
';
Ожидаемый результат
mongodb126-regex-label-arrays: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Добавьте товар с labels=['blueberry','red']. По целому blue он не должен пройти, а по blue или red должен. Для массива объектов {name,active} постройте $elemMatch, связывающий имя и active в одном элементе.

Вопрос из практики: How to combine elemMatch with a regex. В $elemMatch передан Regex без документа операторов, а pattern содержит PHP-разделители. Урок различает прямое значение поля, документ условий и BSON Regex внутри $in. Обсуждение используется как постановка задачи, не как современная техническая спецификация. Решение и данные составлены отдельно.

Сохранить правило отбора, прочитать его тип и применить

Редактор каталога сохраняет правило подборки «Кружки», а другой запуск должен прочитать и применить его без потери флагов. Сохраним BSON Regex как значение документа и покажем, что обратно приходит типизированный объект с исходным pattern и flags.

Входные данные и понятия

В собственной коллекции есть три товара и документ правила. kind отделяет документы товаров от правила; _id=100 выбирает само правило. Pattern ^CUP- с i соответствует CUP-01 и cup-02. После чтения проверяется BSON-тип, затем правило применяется только к документам kind=product.

Как строится и выполняется поиск
  1. Созданный Regex → сохранён в поле rule
  2. Чтение документа правила → instanceof подтверждает ожидаемый тип
  3. RegexInterface описывает pattern/flags/display для редактора
  4. Прочитанное правило применяется к товарам → ID 1 и 2

Короткая запись текущего действия

$saved = $document['rule'];
if (!$saved instanceof MongoDB\BSON\RegexInterface) {
    throw new RuntimeException('В документе нет ожидаемого правила');
}
$description = mr126Describe($saved); // pattern, flags и отображение для редактора.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

IDАртикулПрочитанный patternПрочитанные flags
1CUP-01^CUP-i
2cup-02^CUP-i

Как понимать результат

Сравниваются значения до и после базы, а не идентичность двух PHP-объектов. json_encode вызывает JsonSerializable и сохраняет отдельное представление для просмотра; это не доказательство того, что правило стало обычной JSON-строкой в базе. В самой записи использован BSON Regex.

Границы и ошибки применения

Чтение правила из своей базы не отменяет доверительную границу. Если правила редактируют внешние пользователи, нужна ограниченная модель разрешённых операций, аудит и бюджет запроса; простого instanceof недостаточно. В учебном примере правило задаётся константой разработчика. Не выполняйте regex, полученный из неизвестного файла, только потому что он имеет подходящий BSON-тип.

Полная самостоятельная программа, helper и архив
Сохранить правило отбора, прочитать его тип и применитьСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
$created=new MongoDB\BSON\Regex('^CUP-','i');
    mr126Insert($manager,$namespace,[['_id'=>1,'kind'=>'product','sku'=>'CUP-01'],['_id'=>2,'kind'=>'product','sku'=>'cup-02'],
        ['_id'=>3,'kind'=>'product','sku'=>'LAMP-01'],['_id'=>100,'kind'=>'rule','label'=>'Кружки','rule'=>$created]]);
    $document=mr126Find($manager,$namespace,['_id'=>100],['_id'=>1,'label'=>1,'rule'=>1],1)[0];$saved=$document['rule'];
    if (!$saved instanceof MongoDB\BSON\Regex) { throw new RuntimeException('Expected BSON Regex from database'); }
    $found=mr126Find($manager,$namespace,['kind'=>'product','sku'=>$saved],['_id'=>1,'sku'=>1]);
    $original=mr126Describe($created);$loaded=mr126Describe($saved);
    $originalJson=json_decode(json_encode($created,JSON_THROW_ON_ERROR),true,512,JSON_THROW_ON_ERROR);
    $loadedJson=json_decode(json_encode($saved,JSON_THROW_ON_ERROR),true,512,JSON_THROW_ON_ERROR);
    $checks=['database_regex_type'=>$saved instanceof MongoDB\BSON\RegexInterface,'pattern_flags_preserved'=>$original===$loaded,
        'json_representation_preserved'=>$originalJson===$loadedJson,'saved_rule_returns_products'=>mr126Ids($found)===[1,2]];
    $details=['rule_label'=>$document['label'],'before'=>$original,'after'=>$loaded,'jsonSerialize_via_json_encode'=>$loadedJson];
    return array_map(fn($d)=>[$d['_id'],$d['sku'],$saved->getPattern(),$saved->getFlags()],$found);
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-saved-rule',['ID', 'Артикул', 'Прочитанный pattern', 'Прочитанные flags'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-saved-rule: OK
';
Ожидаемый результат
mongodb126-regex-saved-rule: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Сохраните второе фиксированное правило ^LAMP- и отдельную подпись «Лампы». Выберите его по ID, проверьте тип и получите ID 3. Не смешивайте идентификатор документа правила с его pattern.

RegexInterface, строка для экрана и два разных JSON-представления

Один экран описывает правило, независимо от того, создано оно сейчас или прочитано из базы. Кроме того, правило нужно вывести человеку и передать в BSON-aware интеграцию. Эти задачи требуют разных представлений: строка для экрана не равна формату обмена.

Входные данные и понятия

Функция принимает RegexInterface — типовой контракт с getPattern, getFlags и __toString. Оба фактических значения в примере являются BSON Regex. Pattern a/b содержит slash, flags mi сортируются в im. Два товара a/b и A/B совпадают, axb — нет.

Как строится и выполняется поиск
  1. Созданное и прочитанное Regex → одна типизированная функция
  2. getPattern/getFlags → отдельные значения; __toString → /a/b/im
  3. jsonSerialize → исторические $regex/$options
  4. Document.toCanonicalExtendedJSON → $regularExpression → отдельный формат обмена

Короткая запись текущего действия

function describeRule(MongoDB\BSON\RegexInterface $rule): array {
    return ['pattern'=>$rule->getPattern(), 'flags'=>$rule->getFlags(), 'display'=>(string)$rule];
}
// Интерфейс задаёт тип входа. Здесь передаются реальные Regex, не произвольные строки.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

ПредставлениеФактическое значение
Отображение/a/b/im
jsonSerialize{"$regex":"a/b","$options":"im"}
Canonical Extended JSON{"$regularExpression":{"pattern":"a/b","options":"im"}}
Найденные ID1, 2

Как понимать результат

Отображаемая строка /a/b/im содержит slash внутри pattern и не является готовым безопасным шаблоном PHP preg_match. Полный код её не исполняет. jsonSerialize возвращает mixed-представление для json_encode; напрямую код и автоматический вызов через json_encode($regex) дают одну форму. Canonical Extended JSON получен современным Document API и явно отличается.

Границы и ошибки применения

RegexInterface задаёт доступные методы и обязательные строковые возвращаемые типы; он не компилирует выражение и не гарантирует допустимость произвольного пользовательского объекта для BSON-кодирования. Здесь используются реальные Regex. Исторические функции BSON toJSON удалены в 2.x; их упоминание в старой документации не является инструкцией вызвать удалённую функцию.

Полная самостоятельная программа, helper и архив
RegexInterface, строка для экрана и два разных JSON-представленияСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
$created=new MongoDB\BSON\Regex('a/b','mi');
    mr126Insert($manager,$namespace,[['_id'=>1,'kind'=>'product','title'=>'a/b'],['_id'=>2,'kind'=>'product','title'=>'A/B'],
        ['_id'=>3,'kind'=>'product','title'=>'axb'],['_id'=>100,'kind'=>'rule','rule'=>$created]]);
    $loaded=mr126Find($manager,$namespace,['_id'=>100],['rule'=>1],1)[0]['rule'];
    if (!$loaded instanceof MongoDB\BSON\Regex) { throw new RuntimeException('Expected Regex'); }
    $first=mr126Describe($created);$second=mr126Describe($loaded);
    $flags=JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR;
    $legacy=json_encode($loaded->jsonSerialize(),$flags);
    $direct=json_encode($loaded,$flags);
    $canonical=MongoDB\BSON\Document::fromPHP(['rule'=>$loaded])->toCanonicalExtendedJSON();
    $canonicalValue=json_decode($canonical,true,512,JSON_THROW_ON_ERROR)['rule'];
    $found=mr126Find($manager,$namespace,['kind'=>'product','title'=>$loaded],['_id'=>1,'title'=>1]);
    $checks=['interface_describes_both'=>$first===$second,'sorted_flags'=>$loaded->getFlags()==='im','display_not_escaped_php'=>$second['display']==='/a/b/im',
        'legacy_json_shape'=>json_decode($legacy,true,512,JSON_THROW_ON_ERROR)===['$regex'=>'a/b','$options'=>'im'] && $legacy===$direct,
        'canonical_json_shape'=>$canonicalValue===['$regularExpression'=>['pattern'=>'a/b','options'=>'im']],
        'actual_rule_search'=>mr126Ids($found)===[1,2]];
    $details=['constructed'=>$first,'loaded'=>$second,'found'=>$found,'canonical_document'=>$canonical];
    return [['Отображение',(string)$loaded],['jsonSerialize',$legacy],['Canonical Extended JSON',json_encode($canonicalValue,$flags)],['Найденные ID',implode(', ',mr126Ids($found))]];
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-interface-json',['Представление', 'Фактическое значение'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-interface-json: OK
';
Ожидаемый результат
mongodb126-regex-interface-json: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Замените pattern на path/to/file и повторите сравнение представлений. Для вывода HTML экранируйте строку как текст. Для обмена выберите согласованный Extended JSON формат и соответствующий декодер, а не передавайте отображение /.../flags.

Префикс и вхождение: реальные строки и наблюдаемый explain

Каталог вырос: нужна первая страница артикулов с CUP- в начале либо в любом месте. Эти запросы возвращают разные товары и могут по-разному использовать индекс. Посмотрим настоящий план и результат без скачивания всей коллекции в PHP.

Входные данные и понятия

Создаются 120 небольших документов и собственный индекс sku/_id. Каждый двенадцатый артикул начинается с CUP-, часть остальных содержит X-CUP-. Оба запроса возвращают только _id/sku, сортируют по _id и ограничивают результат пятью строками. Планы снимаются отдельно через explain executionStats.

Как строится и выполняется поиск
  1. Контролируемые артикула → собственный индекс sku_lookup
  2. ^CUP- → первая страница ID 12,24,36,48,60
  3. CUP- без якоря → ID 1,12,13,24,25
  4. Обычные explain и отдельный hinted explain → фактические counters/plans в HTML

Короткая запись текущего действия

$prefix = ['sku'=>new MongoDB\BSON\Regex('^CUP-')];
$contains = ['sku'=>new MongoDB\BSON\Regex('CUP-')];
// Разные требования дают разные строки. Собственный индекс не стирает эту разницу.

Фрагмент выделяет один шаг. Полная программа ниже включает собственные документы, запросы, ограничения, ожидаемые ошибки и очистку.

Конкретный результат

УсловиеПервые пять ID по порядкуnReturned в explain
Префикс12, 24, 36, 48, 605
Вхождение1, 12, 13, 24, 255

Как понимать результат

Официальная оптимизация префикса касается case-sensitive шаблона с простым фиксированным началом. Она может ограничить область просмотра ключей. Поиск вхождения не задаёт такой области. В result.html сохранены планы, nReturned, просмотренные документы/ключи и время конкретного запуска; неизменным ожиданием является полезная выдача, а не название стадии или миллисекунды.

Границы и ошибки применения

Наш индекс начинается с sku, а выдача сортируется по _id: нельзя заранее обещать отсутствие сортировки. Hint показывает применимость указанного индекса, не доказывает, что он быстрее выбора оптимизатора. Флаг i не делает regex collation-aware; case-insensitive индекс не является универсальным ускорителем regex. При требовании поиска слов, ранжирования или ошибок ввода нужен отдельный поисковый механизм.

Полная самостоятельная программа, helper и архив
Префикс и вхождение: реальные строки и наблюдаемый explainСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mr126-helper.php';
$runtime=mr126Runtime();[$uri,$db]=mr126Config();$manager=mr126Manager($uri);
$runtime['server']=mr126BuildVersion($uri,$db);$checks=[];$details=[];
$rows=mr126WithCollection($manager,$db,function(string $namespace,string $collection) use($manager,$db,&$checks,&$details): array {
$documents=[];
    for ($i=1;$i<=120;++$i) {
        $prefix=$i%12===0?'CUP-':($i%12===1?'X-CUP-':'LAMP-');
        $documents[]=['_id'=>$i,'sku'=>$prefix.str_pad((string)$i,3,'0',STR_PAD_LEFT)];
    }
    mr126Insert($manager,$namespace,$documents);
    mr126Command($manager,$db,['createIndexes'=>$collection,'indexes'=>[['key'=>['sku'=>1,'_id'=>1],'name'=>'sku_lookup']]],true);
    $rules=['Префикс'=>new MongoDB\BSON\Regex('^CUP-'),'Вхождение'=>new MongoDB\BSON\Regex('CUP-')];
    $rows=[];$plans=[];$ids=[];
    foreach ($rules as $label=>$rule) {
        $filter=['sku'=>$rule];$ids[$label]=mr126Ids(mr126Find($manager,$namespace,$filter,['_id'=>1,'sku'=>1],5));
        $query=['find'=>$collection,'filter'=>$filter,'projection'=>['_id'=>1,'sku'=>1],'sort'=>['_id'=>1],'limit'=>5,'maxTimeMS'=>1000];
        $plans[$label]=mr126Command($manager,$db,['explain'=>$query,'verbosity'=>'executionStats'])[0];
        $rows[]=[$label,implode(', ',$ids[$label]),$plans[$label]['executionStats']['nReturned']];
        if ($label==='Префикс') { $query['hint']='sku_lookup';$plans['Hint: применимость']=mr126Command($manager,$db,['explain'=>$query,'verbosity'=>'executionStats'])[0]; }
    }
    $checks=['prefix_ids'=> $ids['Префикс']===[12,24,36,48,60],'contains_ids'=>$ids['Вхождение']===[1,12,13,24,25],
        'ordinary_explains_return_five'=>$plans['Префикс']['executionStats']['nReturned']===5 && $plans['Вхождение']['executionStats']['nReturned']===5,
        'hinted_applicability_returns_five'=>$plans['Hint: применимость']['executionStats']['nReturned']===5];
    $details=['seed_documents'=>120,'actual_explain'=>$plans,'policy'=>'Do not infer guaranteed IXSCAN, no-sort or speed-up from this fixture.'];return $rows;
});
$checks['owned_collection_removed']=true;
mr126Report('mongodb126-regex-index-prefix',['Условие', 'Первые пять ID по порядку', 'nReturned в explain'],$rows,$checks,$runtime,$details);
echo 'mongodb126-regex-index-prefix: OK
';
Ожидаемый результат
mongodb126-regex-index-prefix: OK

Настоящий запрос к отдельной локальной MongoDB. HTML/JSON сохраняют найденные строки и наблюдения. Неизменным ожиданием служат данные, а не время или фиксированный выбор оптимизатора.

Открыть найденные данные и наблюдения · Таблица JSON

Упражнение с направлением решения. Сравните реальные totalKeysExamined/totalDocsExamined обычных планов и hinted prefix. Объясните различия по данным и запросу, не объявляя результат маленького стенда универсальным benchmark. Затем сформулируйте, требуется ли вашему экрану префикс или вхождение.

Вопрос из практики: MongoDB index on regex fields not working. Поиск вхождения с i на большой коллекции ошибочно ожидается столь же эффективным, как поиск префикса. Урок показывает собственный индекс и фактический explain без универсальных обещаний. Обсуждение используется как постановка задачи, не как современная техническая спецификация. Решение и данные составлены отдельно.

Regex и RegexInterface: полный набор классовых и методных контрактов

Десять карточек раскрывают класс, интерфейс и все их собственные методы: сигнатуры, параметры, возвращаемые значения, ошибки, версии и два практических применения. Наличие этих карточек закрывает данный BSON-раздел, а не весь справочник MongoDB.

Класс или методПрактическая роль
MongoDB\BSON\Regex::__constructСоздать BSON-значение с pattern и flags для запроса или сохранённого правила.
MongoDB\BSON\Regex::getFlagsПрочитать режимы сохранённого шаблона и не смешивать их с pattern.
MongoDB\BSON\Regex::getPatternПолучить pattern без флагов и внешних delimiter.
MongoDB\BSON\Regex::jsonSerializeПолучить представление Regex, которое json_encode может записать в JSON.
MongoDB\BSON\Regex::__toStringПолучить короткое строковое представление правила для человека.
MongoDB\BSON\RegexBSON-тип регулярного выражения: хранит pattern/flags для фильтров и документов.
MongoDB\BSON\RegexInterfaceЗадать тип параметра, результата или свойства для представления BSON Regex в пользовательском коде.
MongoDB\BSON\RegexInterface::getFlagsПолучить строку режимов через общий тип RegexInterface.
MongoDB\BSON\RegexInterface::getPatternПрочитать шаблон без флагов через типизированный контракт.
MongoDB\BSON\RegexInterface::__toStringПолучить отображение правила через общий интерфейс.

Выбирать поиск по требованию и измеримому результату

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

Далее: индексы и страницы каталога, Document и Extended JSON, бинарные значения и типизированный обмен, ошибки команд и безопасная диагностика. Для PHP-обработки строк есть базовый раздел регулярных выражений, а полный перечень API доступен через справочник.

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

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

MongoDB\BSON\Regex::__constructСоздать BSON-значение с pattern и flags для запроса или сохранённого правила.

С ext-mongodb 1.0.0. С 1.2.0 flags необязателен и по умолчанию пуст, буквы сортируются, NUL отвергается исключением; раньше строки обрезались на первом NUL. · mongodb

final public function MongoDB\BSON\Regex::__construct(string $pattern, string $flags = "")

Параметры и способ применения

$pattern — строка регулярного выражения без внешних разделителей /.../. $flags — отдельная строка флагов; по умолчанию пустая. Символы флагов сортируются в алфавитном порядке. Требование буквального ввода реализуется preg_quote до создания Regex, а не самим constructor.

Результат

Новый объект Regex, содержащий pattern и flags. Конструктор не выполняет запрос, не ищет совпадения и не гарантирует компилируемость серверного шаблона.

Ошибки

MongoDB\Driver\Exception\InvalidArgumentException при ошибке разбора аргументов и при NUL в pattern или flags. Синтаксически неверный фиксированный pattern [ успешно сохраняется в объекте, но наша реальная MongoDB отвергает запрос кодом 51091; это отдельный серверный отказ.

Версии и ограничения

С ext-mongodb 1.0.0. С 1.2.0 flags необязателен и по умолчанию пуст, буквы сортируются, NUL отвергается исключением; раньше строки обрезались на первом NUL.

Не передавайте PHP delimiter или произвольные пользовательские операторы. i/m/s/x имеют разные функции; u избыточен для UTF в текущем сервере, g не поддерживается. Набор допустимых режимов приложения определяет разработчик.

Отобрать карточки по префиксу

$rule = new MongoDB\BSON\Regex('^CUP-');

Получены только CUP-01 и CUP-02; flags по умолчанию пустая строка.

Полная программа, найденные данные и архив

Превратить ввод в буквальный фрагмент

$rule = new MongoDB\BSON\Regex(preg_quote($text));

Скобки и плюс названия сохраняют буквальный смысл; реальный результат состоит из двух подходящих товаров.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\Regex::getFlagsПрочитать режимы сохранённого шаблона и не смешивать их с pattern.

С ext-mongodb 1.0.0; сортировка constructor применяется с 1.2.0. · mongodb

final public function MongoDB\BSON\Regex::getFlags(): string

Параметры и способ применения

Параметров нет; вызов выполняется на объекте Regex.

Результат

Строка флагов; пустая означает отсутствие явно переданных режимов. Для объектов, созданных современным constructor, буквы отсортированы: mi возвращается как im.

Ошибки

Официальный контракт перечисляет MongoDB\Driver\Exception\InvalidArgumentException при ошибке разбора аргументов.

Версии и ограничения

С ext-mongodb 1.0.0; сортировка constructor применяется с 1.2.0.

Getter не оценивает, полезен ли выбранный флаг для текста, и не гарантирует работу индекса. Flags не нужно повторно извлекать разбором строки /.../flags.

Передать режим отдельно в операторную форму

$filter = ['notes'=>['$regex'=>$rule->getPattern(), '$options'=>$rule->getFlags()]];

Фиксированные правила m/s/x дают разные списки документов; mi читается как im.

Полная программа, найденные данные и архив

Показать режим прочитанной подборки

$flags = $saved->getFlags();

Из базы возвращается i, поэтому правило находит и CUP-01, и cup-02.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\Regex::getPatternПолучить pattern без флагов и внешних delimiter.

С ext-mongodb 1.0.0. · mongodb

final public function MongoDB\BSON\Regex::getPattern(): string

Параметры и способ применения

Параметров нет; требуется объект Regex.

Результат

Строка шаблона, сохранённая в объекте. Возвращаемое значение не является найденным текстом и не является HTML/JSON-экранированием.

Ошибки

MongoDB\Driver\Exception\InvalidArgumentException при ошибке разбора аргументов.

Версии и ограничения

С ext-mongodb 1.0.0.

Не исполняйте pattern на клиентском PHP автоматически: там отдельные правила delimiter и доступные режимы. Для редактора покажите его как текст, экранированный под контекст вывода.

Увидеть превращение ввода в безопасный literal

$pattern = $rule->getPattern();

Diagnostics показывает реальные обратные слеши перед скобками и плюсом после preg_quote.

Полная программа, найденные данные и архив

Сверить сохранённую конфигурацию

$same = $saved->getPattern() === $created->getPattern();

Сравниваются значения до и после записи, а затем прочитанное правило действительно применяется к товарам.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\Regex::jsonSerializeПолучить представление Regex, которое json_encode может записать в JSON.

С ext-mongodb 1.2.0. Упоминание старой BSON\toJSON на официальной странице объясняет формат; сама функция удалена в 2.0, поэтому здесь применяется текущий Document API для сравнения. · mongodb

final public function MongoDB\BSON\Regex::jsonSerialize(): mixed

Параметры и способ применения

Параметров нет. Обычно json_encode($regex) сам вызывает метод JsonSerializable; прямой вызов полезен для понимания возвращаемых данных.

Результат

Данные для Extended JSON представления Regex. Документированный формат соответствует историческому driver-specific legacy Extended JSON, а не автоматически canonical/relaxed. В текущем примере получены $regex и $options.

Ошибки

MongoDB\Driver\Exception\InvalidArgumentException при ошибке разбора аргументов. Ошибки последующего json_encode — отдельный контракт PHP JSON; примеры используют JSON_THROW_ON_ERROR.

Версии и ограничения

С ext-mongodb 1.2.0. Упоминание старой BSON\toJSON на официальной странице объясняет формат; сама функция удалена в 2.0, поэтому здесь применяется текущий Document API для сравнения.

Не считайте произвольный json_decode полноценным BSON-декодером. Перед обменом согласуйте версию Extended JSON и способ восстановления типа. Возвращаемый тип mixed не следует сужать обещанием одного класса для всех версий.

Сверить JSON-представление сохранённой подборки

$before = json_encode($created, JSON_THROW_ON_ERROR);
$after = json_encode($saved, JSON_THROW_ON_ERROR);

Неявный вызов jsonSerialize проверяет сохранение представления прочитанного правила; запрос использует BSON Regex, а не эти строки.

Полная программа, найденные данные и архив

Различить legacy и canonical

$view = json_encode($loaded->jsonSerialize(), JSON_THROW_ON_ERROR);
$canonical = MongoDB\BSON\Document::fromPHP(['rule'=>$loaded])->toCanonicalExtendedJSON();

Фактическая таблица показывает $regex/$options отдельно от $regularExpression с pattern/options.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\Regex::__toStringПолучить короткое строковое представление правила для человека.

С ext-mongodb 1.0.0. Класс реализует Stringable на PHP 8+ с ext-mongodb 1.12.0. · mongodb

final public function MongoDB\BSON\Regex::__toString(): string

Параметры и способ применения

Параметров нет. Приведение (string)$regex вызывает этот метод.

Результат

Строковое представление вида /pattern/flags. Это не результат сопоставления и не самостоятельный формат BSON/JSON.

Ошибки

Страница метода не перечисляет отдельные исключения. Ошибки последующего использования строки, например как PHP preg-pattern или HTML, относятся к выбранному контексту.

Версии и ограничения

С ext-mongodb 1.0.0. Класс реализует Stringable на PHP 8+ с ext-mongodb 1.12.0.

В pattern может быть slash: a/b с im отображается как /a/b/im. Поэтому такую строку нельзя без преобразования и проверки передавать preg_match. Для сохранения берите объект или раздельные getPattern/getFlags.

Объяснить активный фильтр каталога

$display = (string) $rule;

В diagnostics рядом с найденными товарами показано /^CUP-/; это подпись фильтра, не второй запрос.

Полная программа, найденные данные и архив

Увидеть границу отображения

$display = (string) $loaded;

Получено /a/b/im, и программа намеренно не пытается исполнять его в PHP; серверный Regex действительно находит два товара.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\RegexBSON-тип регулярного выражения: хранит pattern/flags для фильтров и документов.

Класс с 1.0.0. С 1.2.0 реализовывал Serializable и JsonSerializable. С 1.3.0 реализует RegexInterface. С 1.12.0 реализует Stringable на PHP 8+. С 2.0.0 больше не реализует Serializable; это исторический переход, не повод применять удалённый контракт. · mongodb

final class MongoDB\BSON\Regex implements MongoDB\BSON\RegexInterface, MongoDB\BSON\Type, JsonSerializable, Stringable

Параметры и способ применения

Создаётся через __construct(string $pattern, string $flags = ""). Class final: наследование от него запрещено. Основное применение — запросы базы; оператор $regex является альтернативной формой задания условия.

Результат

Объект BSON-типа. Все пять собственных методов: __construct, getFlags(): string, getPattern(): string, jsonSerialize(): mixed, __toString(): string. Официальный synopsis не объявляет public pattern/flags properties: для прикладного чтения используются getter, даже если var_dump показывает диагностические поля.

Ошибки

Constructor отвергает NUL и неверные аргументы через MongoDB\Driver\Exception\InvalidArgumentException. Создание объекта не заменяет серверную проверку синтаксиса. Ошибки поиска и JSON-обмена рассматриваются отдельно в методах.

Версии и ограничения

Класс с 1.0.0. С 1.2.0 реализовывал Serializable и JsonSerializable. С 1.3.0 реализует RegexInterface. С 1.12.0 реализует Stringable на PHP 8+. С 2.0.0 больше не реализует Serializable; это исторический переход, не повод применять удалённый контракт.

BSON Regex, PHP preg_* и строка JSON — разные уровни. Нет публичного метода «выполнить regex»: операция поиска принадлежит Manager/Query. Не используйте тип как разрешение на выполнение недоверенного сложного шаблона.

Построить полезный фильтр

$filter = ['sku'=>new MongoDB\BSON\Regex('^CUP-')];

Два товара возвращаются ограниченным настоящим запросом; созданный объект только передаёт правило MongoDB.

Полная программа, найденные данные и архив

Сохранить и восстановить правило подборки

$document = ['kind'=>'rule', 'rule'=>new MongoDB\BSON\Regex('^CUP-', 'i')];

Запись содержит BSON Regex; после чтения проверяются тип/значения и выполняется поиск CUP/cup.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\RegexInterfaceЗадать тип параметра, результата или свойства для представления BSON Regex в пользовательском коде.

С ext-mongodb 1.3.0. С 1.15.0 на PHP 8+ возвращаемые типы были tentative; несоответствие вызывало deprecation и временно могло отмечаться ReturnTypeWillChange. С 2.0.0 объявленные возвращаемые типы обязательны. · mongodb

interface MongoDB\BSON\RegexInterface { public function getFlags(): string; public function getPattern(): string; public function __toString(): string; }

Параметры и способ применения

Интерфейс, реализуемый MongoDB\BSON\Regex. Он описывает три метода без аргументов: getFlags, getPattern и __toString; все возвращают string. Интерфейс сам не создаётся через new и не является классом компилятора.

Результат

Позволяет объявить понятный тип входа функции или свойства. В примерах mr126Describe получает реальные Regex, созданные constructor либо прочитанные из базы, и возвращает обычный массив описания.

Ошибки

Неверный тип аргумента пользовательской функции приводит к TypeError PHP. Методы реализации имеют собственные контракты; интерфейс не обещает сетевую операцию или автоматическое BSON-кодирование произвольного объекта.

Версии и ограничения

С ext-mongodb 1.3.0. С 1.15.0 на PHP 8+ возвращаемые типы были tentative; несоответствие вызывало deprecation и временно могло отмечаться ReturnTypeWillChange. С 2.0.0 объявленные возвращаемые типы обязательны.

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

Описать правило после чтения

function describeRule(MongoDB\BSON\RegexInterface $rule): array {
    return ['pattern'=>$rule->getPattern(), 'flags'=>$rule->getFlags(), 'display'=>(string)$rule];
}

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

Полная программа, найденные данные и архив

Одна функция для двух источников объекта

$first = mr126Describe($created);
$second = mr126Describe($loaded);

Сравниваются constructed/readback значения, а дополнительные JSON-представления показаны отдельно.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\RegexInterface::getFlagsПолучить строку режимов через общий тип RegexInterface.

С ext-mongodb 1.3.0. Tentative return type с 1.15.0 на PHP 8+; с 2.0.0 тип string обязателен. · mongodb

abstract public function MongoDB\BSON\RegexInterface::getFlags(): string

Параметры и способ применения

Параметров нет. Метод относится к контракту RegexInterface; в примерах вызывается на BSON Regex.

Результат

Строка флагов реализации. Для BSON Regex, созданного современным constructor, буквы отсортированы.

Ошибки

Официальная страница интерфейсного метода не перечисляет отдельные исключения. Реализация и вызывающий код могут иметь собственные ошибки; тип результата string обязателен.

Версии и ограничения

С ext-mongodb 1.3.0. Tentative return type с 1.15.0 на PHP 8+; с 2.0.0 тип string обязателен.

Сам интерфейс не преобразует flags и не запускает поиск. Нормализация определяется конкретной реализацией.

Показать режим сохранённой подборки

function flagsLabel(MongoDB\BSON\RegexInterface $rule): string { return $rule->getFlags(); }

Полный helper mr126Describe делает этот же вызов: режим i сохранён и реально влияет на CUP/cup.

Полная программа, найденные данные и архив

Описать созданное и загруженное правило

$flags = $rule->getFlags();

Оба реальных Regex имеют im; порядок букв не извлекается разбором display-строки.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\RegexInterface::getPatternПрочитать шаблон без флагов через типизированный контракт.

С ext-mongodb 1.3.0. Tentative return type с 1.15.0 на PHP 8+; с 2.0.0 тип string обязателен. · mongodb

abstract public function MongoDB\BSON\RegexInterface::getPattern(): string

Параметры и способ применения

Параметров нет. Метод относится к контракту RegexInterface; в примерах вызывается на BSON Regex.

Результат

Строка pattern реализации. В BSON Regex это значение, переданное constructor, без внешних delimiter.

Ошибки

Официальная страница интерфейсного метода не перечисляет отдельные исключения. Реализация и вызывающий код могут иметь собственные ошибки; тип результата string обязателен.

Версии и ограничения

С ext-mongodb 1.3.0. Tentative return type с 1.15.0 на PHP 8+; с 2.0.0 тип string обязателен.

Это не найденный фрагмент и не автоматически безопасный HTML. Доверительность и контекст вывода проверяются отдельно.

Сверить конфигурацию до и после базы

$pattern = $rule->getPattern();

Обе стороны передаются mr126Describe; ^CUP- возвращается без добавленных slash.

Полная программа, найденные данные и архив

Сохранить slash как часть данных

$pattern = $rule->getPattern();

Для a/b getter возвращает именно a/b, тогда как __toString добавляет представление /a/b/im.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

MongoDB\BSON\RegexInterface::__toStringПолучить отображение правила через общий интерфейс.

С ext-mongodb 1.3.0. Tentative return type с 1.15.0 на PHP 8+; с 2.0.0 тип string обязателен. · mongodb

abstract public function MongoDB\BSON\RegexInterface::__toString(): string

Параметры и способ применения

Параметров нет. Метод относится к контракту RegexInterface; в примерах вызывается на BSON Regex.

Результат

Строковое представление реализации. Реальный BSON Regex отображается как /pattern/flags.

Ошибки

Официальная страница интерфейсного метода не перечисляет отдельные исключения. Реализация и вызывающий код могут иметь собственные ошибки; тип результата string обязателен.

Версии и ограничения

С ext-mongodb 1.3.0. Tentative return type с 1.15.0 на PHP 8+; с 2.0.0 тип string обязателен.

У интерфейса контракт результата string; безопасное применение строки как PHP pattern не обещается.

Подпись сохранённой подборки для редактора

$label = (string) $rule;

Типизированный helper сохраняет display вместе с раздельными pattern/flags; это не формат хранения в MongoDB.

Полная программа, найденные данные и архив

Показать slash внутри pattern без исполнения

$label = (string) $rule;

Реальное значение /a/b/im выводится отдельно от legacy/canonical JSON и не передаётся preg_match.

Полная программа, найденные данные и архив

Связи: регулярные выражения PHP, BSON Document и Extended JSON, индексы и ограниченный каталог.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.