Re: [RFC] [VOTE] PREG_THROW_ON_ERROR
| From: | Tim Düsterhus | Date: | Thu, 10 Sep 2026 10:41:26 +0000 |
| Subject: | Re: [RFC] [VOTE] PREG_THROW_ON_ERROR | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-132468@lists.php.net to get a copy of this message | ||
Hi
On 2026-09-07 07:16, Osama Aldemeery wrote:
First...wrapping couples the exception you catch to the flag. Without it,That is correct, but as I mentioned before, the new flag is an entirely new feature that requires an explicit opt-in. Adopting a new feature without reading the associated documentation to find out how it works will generally result in sadness, and I believe this case is no different. Also adding and removing the flag would not just affectpreg_replace_callback()throws whatever the callback throws. With it, the same call always throws aPregException. So the flag silently changes which exception a caller has to handle, and the two have to move together:try { preg_replace_callback( '/[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}/', function ($matches) { return mask_credit_card($matches[0]); // throws MaskException }, $contents, ); } catch (MaskException $e) { // becomes dead the moment the flag is added, and comes back the moment it's removed }
MaskException, but would of course also affect whether or not a PregException is thrown and whether or not the code proceeds after an error was encountered. Any existing error handling would need to adapted as well. So the changes required to adopt the flag are much more far-reaching than whether or not a catch block for a custom exception would need to be adjusted.
Second...wrapping a callback's exception in aI think that is fine: Just add a new PREG_CALLBACK_ERROR that is only emitted when PREG_THROW_ON_ERROR is set.PregExceptionproduces aPregExceptionthat maps to no preg error.
You can be holding aAh, good that you mention this, because it's not mentioned in the RFC and I didn't check the implementation: ThePregExceptionwhilepreg_last_error()andpreg_last_error_msg()report no error at all. That is an exception whose type says a regex error happened when, by preg's own state, none did.
preg_last_error() value should *not* be touched when the PREG_THROW_ON_ERROR flag is set. Once you opt into exception-based error handling, the other error handling path should be bypassed entirely. This is consistent with how JSON_THROW_ON_ERROR already works: https://3v4l.org/Ijt3R#veol
<?php
echo "Start\n";
var_dump(json_last_error());
echo "\n";
echo "Error without flag\n";
json_decode('{');
var_dump(json_last_error());
echo "\n";
echo "Clear error\n";
json_decode('true'); // clear error
var_dump(json_last_error());
echo "\n";
echo "Error with flag\n";
try { json_decode('{', flags: JSON_THROW_ON_ERROR); } catch (\JsonException $e) { echo $e->getMessage(), "\n"; }
var_dump(json_last_error());
echo "\n";
echo "Set different error\n";
json_decode(str_repeat('[', 1000));
var_dump(json_last_error());
echo "and check that it is not overwritten when JSON_THROW_ON_ERROR is set\n";
try { json_decode('{', flags: JSON_THROW_ON_ERROR); } catch (\JsonException $e) { echo $e->getMessage(), "\n"; }
var_dump(json_last_error());
This is separate from theSo with the above note that$e->getMessage() === preg_last_error_msg()guarantee I raised before. Even setting that aside, it's incoherent on its own terms, because the flag isPREG_THROW_ON_ERRORandpreg_last_error()is what an error is. So keeping that honest means a barePregExceptioncan no longer stand for two different things at once.
preg_last_error() should remain untouched, I believe having a single PregException for everything is fine (or PregError + PregException, as pointed out by Robert).
Best regards
Tim Düsterhus