respect-validation/docs/comparing-empty-values.md
Henrique Moody 562d98d805
Refactor the NotEmpty rule
Since we have the ability to use `not` as a prefix, having rules that
validate negative behaviour makes them a bit inflexible, verbose, and
harder to understand.

This commit will refactor the `NotEmpty`, and rename it to `Falsy`. It
will no longer trim strings, because Blank does a much better job at it;
it only simulates the behaviour of PHP’s native `empty()` function.

Because `Falsy`, `Blank`, and `Undef` have similar behaviour, I created
a page to demonstrate the difference and show when the user should use
one or the other.

Assisted-by: Cursor (claude-4.5-opus-high)
2025-12-29 12:48:35 +01:00

139 lines
4.5 KiB
Markdown

# Comparing empty values
The [Undef](rules/Undef.md), [Blank](rules/Blank.md), and [Falsy](rules/Falsy.md) rules all validate "empty-like" values, but they differ in strictness and use cases. This guide helps you understand when to use each one.
## Quick Comparison
| Input | Undef | Falsy | Blank |
| ---------------- | :---: | :---: | :---: |
| `null` | ✅ | ✅ | ✅ |
| `''` | ✅ | ✅ | ✅ |
| `' '` | ❌ | ❌ | ✅ |
| `0` | ❌ | ✅ | ✅ |
| `0.0` | ❌ | ✅ | ✅ |
| `'0'` | ❌ | ✅ | ✅ |
| `'0.0'` | ❌ | ❌ | ✅ |
| `false` | ❌ | ✅ | ✅ |
| `[]` | ❌ | ✅ | ✅ |
| `['']` | ❌ | ❌ | ✅ |
| `[0]` | ❌ | ❌ | ✅ |
| `[' ']` | ❌ | ❌ | ✅ |
| `new stdClass()` | ❌ | ❌ | ✅ |
Legend: ✅ = valid (passes the validation), ❌ = invalid (does not pass the validation)
## Understanding Each Rule
### Undef (Most Restrictive)
The `Undef` rule is the most restrictive. It only considers two values as "undefined":
- `null`
- `''` (empty string)
This rule is ideal when you want to check if a value was explicitly not provided, such as an optional form field that was left empty or a missing API parameter.
```php
v::undef()->isValid(null); // true
v::undef()->isValid(''); // true
v::undef()->isValid(0); // false - 0 is a defined value
v::undef()->isValid(' '); // false - whitespace is defined
```
**Use when:** You need to distinguish between "no value provided" and "any value provided" (including zeros, whitespace, and empty arrays).
### Falsy (Moderate)
The `Falsy` rule uses PHP's native `empty()` function behavior. It considers values that PHP treats as "empty" in boolean contexts:
- `null`
- `''` (empty string)
- `0`, `0.0` (zero numbers)
- `'0'` (string zero)
- `false`
- `[]` (empty array)
```php
v::falsy()->isValid(null); // true
v::falsy()->isValid(''); // true
v::falsy()->isValid(0); // true
v::falsy()->isValid('0'); // true
v::falsy()->isValid(false); // true
v::falsy()->isValid([]); // true
v::falsy()->isValid(' '); // false - whitespace is not empty()
```
**Use when:** You want to match PHP's native "truthiness" behavior, such as validating values that would fail an `if ($value)` check.
### Blank (Most Permissive)
The `Blank` rule is the most permissive. It considers a value blank if it contains no meaningful content:
- Everything that `Falsy` considers falsy
- Whitespace-only strings (` `, `\t`, `\n`)
- Numeric strings representing zero (`'0.0'`, `'0.00'`)
- Arrays containing only blank values (recursively)
- Empty `stdClass` objects
```php
v::blank()->isValid(null); // true
v::blank()->isValid(''); // true
v::blank()->isValid(' '); // true - whitespace only
v::blank()->isValid('0.0'); // true - numeric zero string
v::blank()->isValid(['']); // true - array with blank value
v::blank()->isValid([[''], [0]]); // true - nested blanks
v::blank()->isValid(new stdClass()); // true - empty object
```
**Use when:** You want to check if a value has any meaningful content at all, ignoring whitespace, zeros, and empty nested structures.
## Common Scenarios
### Form Validation
```php
// Accept field only if user typed something meaningful
v::not(v::blank())->isValid($userInput);
// Check if optional field was provided at all
v::not(v::undef())->isValid($optionalField);
```
### API Validation
```php
// Parameter must be defined (null and empty string are not acceptable)
v::not(v::undef())->isValid($requiredParam);
// Parameter can be zero but not empty
v::not(v::undef())->isValid(0); // passes - 0 is defined
```
### Conditional Logic
```php
// Match PHP's if() behavior
v::falsy()->isValid($value); // same as: !$value
// Check for truly empty values beyond PHP's empty()
v::blank()->isValid($value);
```
## Decision Guide
Choose the rule based on what you consider "empty":
1. **Use `Undef`** when only `null` and `''` should be considered empty. Zero, false, and empty arrays are valid values.
2. **Use `Falsy`** when you want to match PHP's `empty()` behavior. Good for boolean-like checks.
3. **Use `Blank`** when whitespace-only strings, nested empty arrays, and empty objects should also be considered empty.
---
See also:
- [Undef](rules/Undef.md)
- [Blank](rules/Blank.md)
- [Falsy](rules/Falsy.md)
- [NullType](rules/NullType.md)