Alternation With An Empty Branch

ID

php.regex_empty_alternative

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Code Smell

Language

Php

Tags

code-smell, regex

Description

Reports an alternation with an empty branch: (a|b|), (|a), a||b. The empty branch matches the empty string, so the whole alternation is optional and, at any position, always succeeds.

Rationale

// Bad
preg_match('/^(GET|POST|)$/', 'GET');   // 1
preg_match('/^(GET|POST|)$/', '');      // 1 -- the empty branch matched
  • The pattern was written to accept two method names and now accepts three things, one of which is nothing.

  • Almost always the residue of an edit: a branch was deleted and its bar left behind, or a trailing bar was typed while extending the list.

  • The pattern silently stops rejecting what it was written to reject, so the failure surfaces as bad data downstream rather than as a validation error.

Remediation

Drop the stray bar. When the value really is optional, say so where the reader looks for it — with ? on the group, or with an explicit check.

// Good
preg_match('/^(GET|POST)$/', $s);      // the empty case was a typo
preg_match('/^(GET|POST)?$/', $s);     // optional, and it says so

What is not reported

Only a lexically empty branch is reported — one whose span holds no token at all. A branch consisting of an anchor (/(^|,)/) or of a zero-width assertion (/(\b|,)/) is the deliberate "this or the boundary" idiom and is left alone. Each alternation is judged at its own level, the specific group or the top level that directly contains it, so an empty branch inside a nested group is never attributed to the level around it.

© 2026 Xygeni. All rights reserved