d8DetectabilityOperational debt — how invisible misuse is to your safety net
Closest to 'silent in production until users hit it' (d9), scored d8 because no PHP-specific tool flags greedy-vs-lazy mismatches; the bug typically passes tests with simple inputs and only surfaces when production data contains repeated delimiters. Careful code review can sometimes catch it.
e1EffortRemediation debt — work required to fix once spotted
Closest to 'one-line patch or single-call swap' (e1) — per quick_fix, adding ? to the quantifier (.* → .*?) or switching to a negated character class is a single-token edit within one pattern.
b3BurdenStructural debt — long-term weight of choosing wrong
Closest to 'localised tax' (b3) — regex patterns are localised to where they're used; greedy/lazy choice doesn't shape system architecture, but applies broadly across web/cli contexts wherever regex is used, slightly above minimal commitment.
t7TrapCognitive debt — how counter-intuitive correct behaviour is
Closest to 'serious trap' (t7) per the misconception: developers assume lazy is universally safer/more correct, and greedy .* silently captures too much across repeated delimiters. The 'obvious' fix (switch to lazy) is itself often wrong vs. a negated character class — contradicts intuition.
Greedy quantifiers (*, +, ?) match as much as possible; lazy quantifiers (*?, +?, ??) match as little as possible — the difference determines which text is captured when multiple matches are possible.
Explanation
By default, quantifiers are greedy — they consume the maximum number of characters that still allow the overall pattern to match. Adding ? after a quantifier makes it lazy — it consumes the minimum. For example, /<.+>/ on '<b>bold</b>' matches the entire string '<b>bold</b>' (greedy); <.+?> matches only '<b>' (lazy). This distinction is critical when parsing HTML-like content, extracting substrings between delimiters, or matching the shortest possible token in a string with repeated delimiters. PHP uses PCRE which supports both modes for *, +, ?, and {n,m}.
Common Misconception
✗ Lazy quantifiers are always safer or more correct than greedy ones. Neither is universally correct — the right choice depends on what you are trying to match. Lazy matching on .*? inside a complex pattern can produce unexpected empty matches or match too little. For extracting content between known delimiters, a negated character class ([^<]+) is often more precise and faster than lazy matching (.*?).
Why It Matters
The greedy/lazy distinction is responsible for a large proportion of regex bugs in PHP code. A pattern that works correctly on simple test strings frequently misbehaves on real data that contains the delimiter character more than once. Understanding this prevents silent data extraction errors where your regex captures the wrong substring — a particularly insidious bug because it often passes testing but fails on edge-case production data.
Common Mistakes
Using .* to match content between delimiters when [^delimiter]* is more precise and performs better.
Testing regex only on minimal inputs — greedy bugs appear when the input contains multiple instances of the delimiter.
Mixing greedy and lazy quantifiers in the same pattern without understanding how backtracking interacts between them.
Assuming lazy quantifiers prevent catastrophic backtracking — they reduce it in some cases but can introduce different backtracking patterns.
Code Examples
✗ Vulnerable
// Greedy — matches from first < to LAST >
$html = '<b>bold</b> and <i>italic</i>';
preg_match('/<.+>/', $html, $m);
// $m[0] = '<b>bold</b> and <i>italic</i>' — wrong
✓ Fixed
// Lazy — matches from < to next >
preg_match('/<.+?>/', $html, $m);
// $m[0] = '<b>' — correct
// Even better — negated class, no backtracking
preg_match('/<[^>]+>/', $html, $m);
// $m[0] = '<b>' — faster and more precise
💬 Greedy quantifiers are a classic permissive condition that makes catastrophic backtracking possible — they don't deterministically cause it (requires a vulnerable pattern + input), which matches 'enables' semantics. Parallel to the existing regex_lookahead → enables → regex_catastrophic edge.
🤝 Adopt this term£79/year · your link shown here
Added23 Mar 2026
Edited5 Apr 2026
Views93
Curated in Warsaw under one editorial standard. 1,534 terms, single voice. About this reference →
🧱FUNDAMENTALS— new to this? Start with the ground floor.
RegexgeneralA regex (regular expression) is a pattern you write to search, match, or replace text. It's like a super-powered find-and-replace that can match flexible patterns instead of exact words.
Regex turns hours of manual text hunting into a single line of code. From form validation to log parsing to data cleanup, pattern matching is everywhere in real-world programming.
💡 When a regex misbehaves, check if your special characters need escaping — dots, brackets, and slashes often do.
Add ? after any quantifier to make it lazy: .* becomes .*?, .+ becomes .+? — or use a negated character class [^x]+ for content that should not contain character x