e
Escapes HTML special characters the same way Blade's double braces do.
e(\Illuminate\Contracts\Support\DeferringDisplayableValue|\Illuminate\Contracts\Support\Htmlable|\BackedEnum|string|int|float|null $value, bool $doubleEncode = true): stringParameters
| Parameter | Type | Description |
|---|---|---|
$$value | \Illuminate\Contracts\Support\DeferringDisplayableValue|\Illuminate\Contracts\Support\Htmlable|\BackedEnum|string|int|float|null | The value to escape. Htmlable is returned raw, BackedEnum is reduced to its backing value, and null becomes an empty string. |
$$doubleEncodeoptional | bool= true | Whether existing HTML entities are escaped again. |
Return value
stringThe HTML-escaped string, or the raw output of toHtml() when the value is Htmlable.
Errors
Passing an object that is not Htmlable, DeferringDisplayableValue or BackedEnum and has no __toString() raises a TypeError from htmlspecialchars().
Changelog
- PHP 10.0BackedEnum values are unwrapped to their backing value before escaping; earlier versions raised a TypeError.
e() is the escaping function Blade's {{ }} compiles to. It calls htmlspecialchars() with the ENT_QUOTES | ENT_SUBSTITUTE flags, the UTF-8 charset, and $doubleEncode defaulting to true. Before escaping it unwraps three kinds of value: a DeferringDisplayableValue is resolved first, an Htmlable is returned from its own toHtml() without escaping, and a BackedEnum is reduced to its backing value.
When to reach for it
Any time you build markup outside Blade: a mail body assembled in PHP, an inline SVG label, a notification rendered as HTML, or a string handed to a client-side template. Inside Blade you almost never call it directly, because {{ }} already does.
What trips people up
Double encoding is the big one. e('&') returns &, because the existing entity is escaped again. That is correct and safe; it only looks wrong when the value was already escaped further upstream, which is the actual bug. Pass false as the second argument only when you know the input contains valid entities.
The Htmlable shortcut is the other trap: anything implementing it — including HtmlString — passes through untouched, so wrapping untrusted data in an HtmlString defeats e() entirely.
Example
When to use it
- Escape user-supplied text you are concatenating into an HTML email body.
- Interpolate a value safely into a string of markup built in PHP.
- Match Blade's exact escaping behaviour inside a custom directive or component.
Frequently asked questions
What does the e() helper do in Laravel?
It runs htmlspecialchars() with ENT_QUOTES | ENT_SUBSTITUTE, UTF-8, and double encoding enabled, which is exactly what Blade's {{ }} syntax compiles to. It also unwraps DeferringDisplayableValue and BackedEnum values first, and returns Htmlable values raw.
Why does e() turn & into & even when the string already had entities?
Because $doubleEncode defaults to true, so an existing entity like & is escaped again into &. Passing false as the second argument disables that, but seeing double-encoded output usually means the value was escaped earlier in the pipeline and should be fixed there.
Does e() protect a value wrapped in an HtmlString?
No. HtmlString implements Htmlable, and e() returns Htmlable values from toHtml() without escaping them. That is the intended behaviour for trusted markup, so never wrap untrusted input in an HtmlString.
More examples
Htmlable and BackedEnum are handled specially
The enum path is convenience — you get the backing value escaped, not a TypeError. The HtmlString path is the dangerous one: e() deliberately trusts Htmlable, so anything you wrap in an HtmlString bypasses escaping completely. Never wrap user input in one.
<?php
use Illuminate\Support\HtmlString;
enum Status: string
{
case Draft = 'draft & pending';
}
// A backed enum is reduced to its value, then escaped.
echo e(Status::Draft), "\n";
// draft & pending
// An Htmlable is returned by toHtml() with no escaping at all.
echo e(new HtmlString('<strong>bold</strong>')), "\n";
// <strong>bold</strong>What Blade compiles to
This is the whole difference between the two Blade syntaxes. {{ }} routes through e() and produces inert text; {!! !!} emits the string verbatim, which is why it must never receive user input.
<?php
$name = '<script>alert(1)</script>';
// {{ $name }} in a Blade template compiles to roughly this:
echo e($name), "\n";
// <script>alert(1)</script>
// {!! $name !!} compiles to no escaping at all:
echo $name, "\n";
// <script>alert(1)</script>Escaping while building markup in PHP
Only the interpolated values pass through e(); the surrounding tags you wrote yourself stay as markup. The apostrophe becomes ' because ENT_QUOTES is always set, which matters when the value ends up inside a single-quoted attribute.
<?php
$user = ['name' => 'O\'Brien & Sons', 'bio' => '<b>Founded 1904</b>'];
$html = '<article>'
.'<h2>'.e($user['name']).'</h2>'
.'<p>'.e($user['bio']).'</p>'
.'</article>';
echo $html, "\n";
// <article><h2>O'Brien & Sons</h2><p><b>Founded 1904</b></p></article>
Discussion