preg_match stops at the first match and fills $matches with the full match plus groups. preg_match_all walks the subject and, with PREG_SET_ORDER, gives you one row per match. Using the wrong one is how a “parse this log line” helper becomes a loop that only sees the first error.
Also Read: What Laravel APP_KEY actually encrypts (and when not to rotate it)
Delimiters, flags, and the first character
A pattern that starts with a letter is not delimited. Wrap it: /pattern/i. If it already starts with /, ~, or #, leave it. Capture groups are why you bother: /(\d{4})-(\d{2})-(\d{2})/ on a date string is three groups, not a boolean. Hashtags in a caption want preg_match_all and /#(\w+)/.
Also Read: Laravel: PHP date format
The PHP regex tester on this site runs preg_match / preg_match_all with lowered backtrack and recursion limits so a greedy experiment fails instead of sitting on a worker. Submit is a POST on purpose; a pattern in a query string is a gift to crawlers. Example links only fill the form.
Also Read: 220 billable days: turning a day rate into take-home pay
When you should not write a regex
Slugs, titles, and “does this start with https” are Str helpers. Email-shaped strings can be filter_var. Regex is for the leftover shapes: log formats, weakly specified vendor IDs, capture groups you will actually use. If the pattern is longer than a tweet, it is probably two patterns.
When it returns nothing and you expected a match, print preg_last_error_msg() before you add more .*. Catastrophic backtracking looks like a timeout, not a tidy 0.
