In Laravel, what do $request->boolean(), integer(), date() and enum() return when a field is missing, empty or malformed?
answer
- filter_var with FILTER_VALIDATE_BOOLEAN
- integer() is a plain int cast
- defaults cover absent keys only
- date() throws InvalidFormatException
- enum() falls back via tryFrom
basics
~20 sboolean() is true only for 1, true, on and yes; integer() is an (int) cast, so bad text gives 0; date() returns null when empty but throws on bad input; enum() returns the default for empty or unknown values.
solid answer
~40 sThe typed readers convert raw strings without validating them. `boolean('remote')` runs `filter_var(..., FILTER_VALIDATE_BOOLEAN)`: `1`, `true`, `on` and `yes` give `true`, anything else `false`, and the default (`false`) applies only when the key is absent. `integer('per_page', 20)` is `(int)` on the value, so `abc` gives `0`, `12abc` gives `12`, and an emptied field gives `0`, not 20. `date('posted_after')` returns `null` when the field is not filled, parses leniently with Carbon, or uses a format if given, and throws `Carbon\Exceptions\InvalidFormatException` for garbage. `enum('type', JobType::class)` returns the default (`null`) when the value is empty, the class is not backed, or `tryFrom()` fails. Validate first; these helpers are for shaping trusted input.
code
php · 16 lines<?php
use App\Enums\JobType;
use Illuminate\Http\Request;
// ?remote=on&per_page=abc&posted_after=yesterday&type=freelance
public function index(Request $request)
{
$remote = $request->boolean('remote'); // true ("on")
$perPage = $request->integer('per_page', 20); // 0, not 20: (int) 'abc'
$safePerPage = $request->clamp('per_page', 10, 50, 20); // 20 fallback, clamped to 10..50
$since = $request->date('posted_after'); // Carbon, parsed leniently
$type = $request->enum('type', JobType::class, JobType::FullTime); // FullTime: 'freelance' is no case
return compact('remote', 'perPage', 'safePerPage', 'since', 'type');
}go deeper
Recall that boolean() understands on, yes, true and 1, that date() gives a Carbon instance, and that enum() maps a string to a backed enum case.
Explain each helper's failure mode: absent keys use the default, empty fields cast to 0 or false, date() throws, enum() falls back through tryFrom.
Spot the 500s and silent zeroes these helpers cause on unvalidated input, and pair them with validation or clamp() on public search endpoints.
Decide where conversion lives: typed readers in controllers, validated data objects or form requests, and make the choice consistent across the codebase.
## Why typed readers exist Everything that arrives over HTTP is a string, an array of strings or, for JSON payloads, a scalar the client chose. Laravel's `Illuminate\Http\Request` inherits a family of **typed readers** from the `InteractsWithData` trait that convert a field into a PHP type in one call. They are convenient, but each has precise rules for absent, empty and malformed values, and those rules are what a middle-level interview checks. The running example is a job-board search: `?remote=on&per_page=abc&posted_after=yesterday&type=contract`. ## The four helpers at a glance | Helper | Signature | Absent key | Empty (null) value | Malformed value | |---|---|---|---|---| | `boolean()` | `boolean($key = null, $default = false)` | `$default` passed through `filter_var` | `false` | `false` | | `integer()` | `integer($key, $default = 0)` | `(int) $default` | `0` | `(int)` cast: `'abc'` gives `0`, `'12abc'` gives `12` | | `date()` | `date($key, $format = null, $tz = null)` | `null` | `null` | throws `InvalidFormatException` | | `enum()` | `enum($key, $enumClass, $default = null)` | `$default` | `$default` | `$default` | ## boolean() for checkboxes `boolean()` calls `filter_var($value, FILTER_VALIDATE_BOOLEAN)`. PHP's filter returns `true` for `"1"`, `"true"`, `"on"` and `"yes"` and `false` for everything else, including values it cannot interpret, because the method does not pass `FILTER_NULL_ON_FAILURE`. So `remote=maybe` silently reads as `false`. An unchecked checkbox is not sent, so the default applies; a common form pattern places `<input type="hidden" name="remote" value="0">` before the checkbox so the key is always present. ## integer() and float() are casts, not parsers `integer()` is literally `(int) $this->input($key, $default)`. Three consequences follow: 1. The default is used only when the key is **absent**. A field emptied to `null` by `ConvertEmptyStringsToNull` casts to `0`. 2. Text casts to `0`, and a leading number wins: `'12abc'` becomes `12`, `'3.9'` becomes `3`. 3. Nothing is range-checked, so `per_page=100000` passes straight through. The laravel/docs page says a failed cast returns the default you specify; the pinned source casts with `(int)`, so a failed cast returns `0`. For bounded numbers the trait also offers `clamp($key, $min, $max, $default = 0)`, which substitutes the default for non-numeric input and clamps the result into range. ## date() and interval() can throw `date()` first checks `isNotFilled()`; a missing or empty field returns `null`. Otherwise: - **Without a format**, it calls `Date::parse()`, which delegates to Carbon's lenient parser, so relative strings such as `yesterday` or `next monday` succeed. - **With a format**, it calls `Date::createFromFormat($format, $value, $tz)`. - **On bad input**, both paths throw `Carbon\Exceptions\InvalidFormatException`, a subclass of `InvalidArgumentException`. Unvalidated, that becomes a 500 error. `interval()` follows the same pattern for `CarbonInterval` values. ## enum() and enums() never throw `enum('type', JobType::class)` returns the default when the field is not filled, when the class is not a **backed** enum, or when `JobType::tryFrom($value)` returns `null`. `enums('types', JobType::class)` maps an array of values and drops the invalid ones. The related `whenEnum()` runs a callback only for a valid case. ## Practical guidance - **Validate before converting** anything whose failure mode is an exception (`date()`, `interval()`) or a silent wrong value (`integer()` returning `0`). - **Use `boolean()` for flags** and `enum()` for fixed choices, so controllers compare typed values rather than strings. - **Treat defaults as "absent" defaults**; if an empty field must also fall back, write `$request->integer('per_page') ?: 20` or use `clamp()`. - **Remember `string()`/`str()`** return a `Stringable`, and `array()` casts to an array, returning `[]` for an absent key. ## A note on JSON payloads When an API client posts JSON, values keep their JSON types. `{"remote": false}` reaches `boolean()` as a real boolean, which `filter_var` returns unchanged, and `{"per_page": 25}` reaches `integer()` as an int. The helpers still apply their rules, so the same controller serves both HTML forms, where everything is a string, and JSON clients. The trap is in the other direction: a JSON `null` is a present key, so `integer('per_page', 20)` returns `0` and `enum()` returns its default, exactly as for an emptied form field.
- A user submits posted_after=2026-09-01 and the controller calls $request->date('posted_after', 'd/m/Y'). What happens?The value is filled, so `date()` calls `Date::createFromFormat('d/m/Y', ...)`. The value does not match the format, so Carbon throws `Carbon\Exceptions\InvalidFormatException`, an `InvalidArgumentException`. Without validation earlier in the request, that surfaces as a server error. Validate the field with a date rule first, then read it with `date()`.
- When would you use $request->clamp() instead of integer() for a per_page parameter?Whenever the number must stay in a range. `clamp('per_page', 10, 50, 20)` replaces a non-numeric value with the default and then clamps it between 10 and 50, while `integer()` returns `0` for text and passes huge values through, which can page thousands of rows.
saying these in an interview costs you the question
- integer('per_page', 20) returns 20 when the value is not numeric
- boolean() returns null for values it cannot recognise
- date() returns null when the format does not match
- enum() throws a ValueError for an unknown value
- The typed helpers validate input, so no rules are needed