Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

ext/pcre: add PREG_THROW_ON_ERROR flag - #22797

#22797
Draft
aldemeery wants to merge 2 commits into
php:masterphp/php-src:masterfrom
aldemeery:preg-throw-on-erroraldemeery/php-src:preg-throw-on-errorCopy head branch name to clipboard
Draft

ext/pcre: add PREG_THROW_ON_ERROR flag#22797
aldemeery wants to merge 2 commits into
php:masterphp/php-src:masterfrom
aldemeery:preg-throw-on-erroraldemeery/php-src:preg-throw-on-errorCopy head branch name to clipboard

Conversation

@aldemeery

@aldemeery aldemeery commented Jul 18, 2026

Copy link
Copy Markdown

This PR adds an opt-in PREG_THROW_ON_ERROR flag to the preg_*() functions.
Pass it and any PCRE error the call records in preg_last_error() is additionally thrown as a \PregException, so it can be caught instead of inspected by hand.
Same idea as JSON_THROW_ON_ERROR (7.3) and FILTER_THROW_ON_FAILURE (8.5).

RFC: https://wiki.php.net/rfc/preg_throw_on_error

What it does

The flag only changes how an error is delivered. A call behaves exactly as it does without the flag, byte for byte, and additionally throws at the end if it recorded an error.
The exception carries the same code and message preg_last_error()/preg_last_error_msg() report.
There is one throw site and it reads the same state those functions read, so the two can never disagree.

Covered:

  • All preg_*() functions that take $flags. preg_replace() and preg_filter() gain an optional $flags parameter, the only two that lacked one.
  • Compile errors (malformed pattern) and execution errors (backtrack or recursion limit, bad UTF-8, JIT stack).
  • A new global \PregException extends \Exception (@strict-properties, not final), following the extension-exceptions naming guidance.

Notes for review

  • Compile errors still emit their usual warning and additionally throw. The exception carries the generic PREG_INTERNAL_ERROR / "Internal error" that preg_last_error() reports. The detailed "Compilation failed: ..." text stays on the warning, as today. Making preg_last_error_msg() carry that detail would change the non-flag path, so it is left for a separate change.
  • Arrays: the flag mirrors preg_last_error(), throwing whatever error the same call leaves there. That is last-one-wins for preg_replace() over an array and first-and-stop for preg_grep(), matching each function's existing behavior. Whether the preg_*() functions should fail fast on arrays is a separate question about those functions and is out of scope here.
  • Errors from user callbacks are never masked. A failing preg_*() inside a preg_replace_callback() callback does not make a successful outer call throw, and a callback's own exception always wins.
  • On the throwing path, the by-reference outputs ($matches, $count) hold exactly what the same call without the flag would leave in them.
  • The public C API is unchanged, so extensions built against ext/pcre keep working without a recompile.

Targets the next feature release after 8.6.

Tests assert the invariant directly, that the exception's code and message equal preg_last_error() / preg_last_error_msg() byte for byte across compile and execution errors, and that a call without the flag behaves exactly as before.

@aldemeery
aldemeery force-pushed the preg-throw-on-error branch from cc56e25 to cf51084 Compare July 28, 2026 00:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.