<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="en">
	<title>alies.dev</title>
	<subtitle>Alies Lapatsin — Staff Engineer writing about AI, PHP, Laravel, code quality, and developer tooling.</subtitle>
	<link href="https://alies.dev/feed/feed.xml" rel="self"/>
	<link href="https://alies.dev/"/>
	<updated>2026-08-11T00:00:00Z</updated>
	<id>https://alies.dev/</id>
	<author>
		<name>Alies Lapatsin</name>
		<email>hi@alies.dev</email>
	</author>
	
	<entry>
		<title>Nothing happens when you dispatch a Laravel job</title>
		<link href="https://alies.dev/articles/nothing-happens-when-you-dispatch/"/>
		<updated>2026-08-11T00:00:00Z</updated>
		<id>https://alies.dev/articles/nothing-happens-when-you-dispatch/</id>
		<content type="html">&lt;figure class=&quot;doors-hero&quot; aria-label=&quot;Four entrances into one queue building: the main entrance with a PendingDispatch checkpoint used by both bus spellings, a side door for Bus::dispatch past the checkpoint, and a freight door for Queue::push straight into storage&quot;&gt;
	&lt;svg viewBox=&quot;0 0 760 330&quot; role=&quot;img&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
		&lt;defs&gt;
			&lt;marker id=&quot;doors-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
				&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;doors-arrow-main&quot;&gt;&lt;/path&gt;
			&lt;/marker&gt;
			&lt;marker id=&quot;doors-arrow-side&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
				&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;doors-arrow-muted&quot;&gt;&lt;/path&gt;
			&lt;/marker&gt;
		&lt;/defs&gt;
		&lt;!-- building --&gt;
		&lt;rect x=&quot;530&quot; y=&quot;30&quot; width=&quot;200&quot; height=&quot;270&quot; rx=&quot;8&quot; class=&quot;doors-building&quot;&gt;&lt;/rect&gt;
		&lt;text x=&quot;630&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;doors-title&quot;&gt;queue&lt;/text&gt;
		&lt;g class=&quot;doors-slots&quot;&gt;
			&lt;rect x=&quot;560&quot; y=&quot;92&quot; width=&quot;140&quot; height=&quot;18&quot; rx=&quot;4&quot;&gt;&lt;/rect&gt;
			&lt;rect x=&quot;560&quot; y=&quot;120&quot; width=&quot;140&quot; height=&quot;18&quot; rx=&quot;4&quot;&gt;&lt;/rect&gt;
			&lt;rect x=&quot;560&quot; y=&quot;148&quot; width=&quot;140&quot; height=&quot;18&quot; rx=&quot;4&quot;&gt;&lt;/rect&gt;
			&lt;circle cx=&quot;576&quot; cy=&quot;101&quot; r=&quot;5&quot; class=&quot;doors-dot&quot;&gt;&lt;/circle&gt;
			&lt;circle cx=&quot;596&quot; cy=&quot;101&quot; r=&quot;5&quot; class=&quot;doors-dot&quot;&gt;&lt;/circle&gt;
			&lt;circle cx=&quot;576&quot; cy=&quot;129&quot; r=&quot;5&quot; class=&quot;doors-dot&quot;&gt;&lt;/circle&gt;
		&lt;/g&gt;
		&lt;text x=&quot;630&quot; y=&quot;286&quot; text-anchor=&quot;middle&quot; class=&quot;doors-meta&quot;&gt;workers pull from here&lt;/text&gt;
		&lt;!-- main entrance: two bus spellings, one checkpoint --&gt;
		&lt;g&gt;
			&lt;rect x=&quot;20&quot; y=&quot;40&quot; width=&quot;200&quot; height=&quot;62&quot; rx=&quot;6&quot; class=&quot;doors-door doors-door-main&quot;&gt;&lt;/rect&gt;
			&lt;text x=&quot;120&quot; y=&quot;66&quot; text-anchor=&quot;middle&quot; class=&quot;doors-code doors-code-main&quot;&gt;dispatch(new Job)&lt;/text&gt;
			&lt;text x=&quot;120&quot; y=&quot;88&quot; text-anchor=&quot;middle&quot; class=&quot;doors-code doors-code-main&quot;&gt;Job::dispatch()&lt;/text&gt;
			&lt;rect x=&quot;286&quot; y=&quot;38&quot; width=&quot;178&quot; height=&quot;66&quot; rx=&quot;6&quot; class=&quot;doors-checkpoint&quot;&gt;&lt;/rect&gt;
			&lt;text x=&quot;375&quot; y=&quot;60&quot; text-anchor=&quot;middle&quot; class=&quot;doors-checkpoint-title&quot;&gt;PendingDispatch&lt;/text&gt;
			&lt;text x=&quot;375&quot; y=&quot;79&quot; text-anchor=&quot;middle&quot; class=&quot;doors-gate&quot;&gt;unique · debounce · veto&lt;/text&gt;
			&lt;text x=&quot;375&quot; y=&quot;95&quot; text-anchor=&quot;middle&quot; class=&quot;doors-gate&quot;&gt;fluent config&lt;/text&gt;
			&lt;line x1=&quot;220&quot; y1=&quot;71&quot; x2=&quot;280&quot; y2=&quot;71&quot; class=&quot;doors-path-main&quot; marker-end=&quot;url(#doors-arrow)&quot;&gt;&lt;/line&gt;
			&lt;line x1=&quot;464&quot; y1=&quot;71&quot; x2=&quot;524&quot; y2=&quot;71&quot; class=&quot;doors-path-main&quot; marker-end=&quot;url(#doors-arrow)&quot;&gt;&lt;/line&gt;
		&lt;/g&gt;
		&lt;!-- side door: Bus::dispatch, past the checkpoint --&gt;
		&lt;g&gt;
			&lt;rect x=&quot;20&quot; y=&quot;150&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; class=&quot;doors-door&quot;&gt;&lt;/rect&gt;
			&lt;text x=&quot;120&quot; y=&quot;175&quot; text-anchor=&quot;middle&quot; class=&quot;doors-code&quot;&gt;Bus::dispatch($job)&lt;/text&gt;
			&lt;line x1=&quot;220&quot; y1=&quot;170&quot; x2=&quot;524&quot; y2=&quot;170&quot; class=&quot;doors-path-side&quot; marker-end=&quot;url(#doors-arrow-side)&quot;&gt;&lt;/line&gt;
			&lt;text x=&quot;372&quot; y=&quot;160&quot; text-anchor=&quot;middle&quot; class=&quot;doors-meta&quot;&gt;routing desk only, no checkpoint&lt;/text&gt;
		&lt;/g&gt;
		&lt;!-- freight door: Queue::push, straight into storage --&gt;
		&lt;g&gt;
			&lt;rect x=&quot;20&quot; y=&quot;234&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; class=&quot;doors-door&quot;&gt;&lt;/rect&gt;
			&lt;text x=&quot;120&quot; y=&quot;259&quot; text-anchor=&quot;middle&quot; class=&quot;doors-code&quot;&gt;Queue::push($job)&lt;/text&gt;
			&lt;line x1=&quot;220&quot; y1=&quot;254&quot; x2=&quot;524&quot; y2=&quot;254&quot; class=&quot;doors-path-side&quot; marker-end=&quot;url(#doors-arrow-side)&quot;&gt;&lt;/line&gt;
			&lt;text x=&quot;372&quot; y=&quot;244&quot; text-anchor=&quot;middle&quot; class=&quot;doors-meta&quot;&gt;freight door, straight to storage&lt;/text&gt;
		&lt;/g&gt;
	&lt;/svg&gt;
	&lt;figcaption&gt;Four ways in, one building. Only the main entrance has the checkpoint.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;style&gt;
	.doors-hero {
		margin: 0 0 2em;
		padding: 1.25em 1.25em 1em;
		border: 1px solid var(--color-border-muted);
		border-radius: 6px;
	}

	.doors-hero svg {
		display: block;
		width: 100%;
		height: auto;
		font-family: var(--font-family-monospace);
		color: var(--color-text, currentColor);
	}

	.doors-building {
		fill: var(--color-accent);
		fill-opacity: 0.04;
		stroke: var(--color-meta);
		stroke-width: 1.5;
	}

	.doors-slots rect {
		fill: none;
		stroke: var(--color-border-muted);
	}

	.doors-dot {
		fill: var(--color-accent);
	}

	.doors-door {
		fill: none;
		stroke: var(--color-meta);
	}

	.doors-door-main {
		fill: var(--color-accent);
		fill-opacity: 0.07;
		stroke: var(--color-accent);
		stroke-width: 2;
	}

	.doors-checkpoint {
		fill: var(--color-accent);
		fill-opacity: 0.1;
		stroke: var(--color-accent);
		stroke-width: 2;
	}

	.doors-title {
		font-size: 18px;
		font-weight: 700;
		fill: currentColor;
	}

	.doors-checkpoint-title {
		font-size: 13px;
		font-weight: 700;
		fill: var(--color-accent);
	}

	.doors-gate {
		font-size: 11px;
		fill: var(--color-accent);
	}

	.doors-code {
		font-size: 13px;
		fill: currentColor;
	}

	.doors-code-main {
		font-weight: 700;
	}

	.doors-meta {
		font-size: 11px;
		fill: var(--color-meta);
	}

	.doors-path-main {
		stroke: var(--color-accent);
		stroke-width: 2;
	}

	.doors-arrow-main {
		fill: var(--color-accent);
	}

	.doors-path-side {
		stroke: var(--color-meta);
		stroke-width: 1.5;
		stroke-dasharray: 6 5;
		opacity: 0.75;
	}

	.doors-arrow-muted {
		fill: var(--color-meta);
	}

	.doors-hero figcaption {
		margin-top: 0.6em;
		color: var(--color-meta);
		font-size: 0.75em;
		font-family: var(--font-family-monospace);
	}
&lt;/style&gt;
&lt;p&gt;You are reviewing a pull request:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark has-diff&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line diff remove&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Queue&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($incident)); &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($incident); &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The author writes &amp;quot;same thing, cleaner syntax.&amp;quot; Approve?&lt;/p&gt;
&lt;p&gt;Do not approve. Not yet. The two lines look interchangeable, and teams that treat them that way collect a specific set of production bugs: jobs on the wrong queue, duplicate &amp;quot;unique&amp;quot; jobs, work running inside the web request that everyone believed was async.&lt;/p&gt;
&lt;p&gt;I traced all three dispatch forms through the Laravel 13.24 source, with the 10.x, 11.x and 12.x branches open next to it for the places where behavior changed. The short version, so you can decide whether to keep reading: &lt;code&gt;Queue::push&lt;/code&gt; is a raw write to the queue backend that skips every dispatch-time feature the framework has added since, and keeps adding. The other two forms are one mechanism with two spellings. The practical conclusion is a team convention near the end, with a PHPStan rule to enforce it.&lt;/p&gt;
&lt;h2 id=&quot;what-each-call-actually-does&quot; tabindex=&quot;-1&quot;&gt;What each call actually does &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#what-each-call-actually-does&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Queue&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($incident));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($incident);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($incident));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;queue-push-the-low-level-door&quot; tabindex=&quot;-1&quot;&gt;Queue::push, the low-level door &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#queue-push-the-low-level-door&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Queue&lt;/code&gt; facade resolves &lt;code&gt;QueueManager&lt;/code&gt;, which forwards &lt;code&gt;push()&lt;/code&gt; to the default connection&#39;s driver. The payload is serialized and written to Redis, the database, or SQS before the line finishes. There is no command bus involved, no wrapper object, no deferral. What you pass is what gets stored, on the default connection, on that connection&#39;s default queue, with no delay.&lt;/p&gt;
&lt;h3 id=&quot;job-dispatch-the-command-bus-door&quot; tabindex=&quot;-1&quot;&gt;Job::dispatch, the command bus door &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#job-dispatch-the-command-bus-door&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The static &lt;code&gt;dispatch()&lt;/code&gt; comes from the &lt;code&gt;Dispatchable&lt;/code&gt; trait. It constructs your job and wraps it (&lt;a href=&quot;https://github.com/laravel/framework/blob/v13.24.0/src/Illuminate/Foundation/Bus/Dispatchable.php#L17-L20&quot;&gt;Dispatchable.php#L17&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$arguments)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; static::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;newPendingDispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$arguments));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing is enqueued at this point. The returned &lt;code&gt;PendingDispatch&lt;/code&gt; sits in memory until PHP destroys it, and the destructor does the real work (&lt;a href=&quot;https://github.com/laravel/framework/blob/v13.24.0/src/Illuminate/Foundation/Bus/PendingDispatch.php#L283-L300&quot;&gt;PendingDispatch.php#L283&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __destruct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;shouldDispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;addUniqueJobInformationToContext&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;job);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;acquireDebounceLock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;afterResponse) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        app&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Dispatcher&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::class&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatchAfterResponse&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;job);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        app&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Dispatcher&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::class&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;job);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;removeUniqueJobInformationFromContext&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;job);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a bare statement the object loses its last reference at the end of that statement, so dispatch feels immediate. It is not, and the whole fluent API depends on that. The deferral exists so you can finish configuring before anything ships:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($incident)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    -&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;onQueue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;alarms&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    -&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    -&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;afterCommit&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bus (&lt;code&gt;Illuminate&#92;Bus&#92;Dispatcher&lt;/code&gt;) then checks &lt;code&gt;ShouldQueue&lt;/code&gt;, resolves the connection from the job, and pushes with the job&#39;s queue and delay applied.&lt;/p&gt;
&lt;h3 id=&quot;dispatch-the-same-door-with-a-helper-sign&quot; tabindex=&quot;-1&quot;&gt;dispatch(), the same door with a helper sign &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#dispatch-the-same-door-with-a-helper-sign&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The global helper wraps whatever object you hand it in the same &lt;code&gt;PendingDispatch&lt;/code&gt;. Timing and behavior are identical to the static form. Two real differences: you construct the job yourself, and the helper accepts closures, which it wraps in &lt;code&gt;CallQueuedClosure&lt;/code&gt; and returns as &lt;code&gt;PendingClosureDispatch&lt;/code&gt; so you can attach &lt;code&gt;-&amp;gt;catch()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So the honest mental model is two forms, not three. There is the queue layer (&lt;code&gt;Queue::push&lt;/code&gt;) and the command bus (&lt;code&gt;::dispatch()&lt;/code&gt; and &lt;code&gt;dispatch()&lt;/code&gt;). Everything interesting lives in the gap between them.&lt;/p&gt;
&lt;p&gt;One more door hides in plain sight: &lt;code&gt;Bus::dispatch($job)&lt;/code&gt;. It enters the same &lt;code&gt;Illuminate&#92;Bus&#92;Dispatcher&lt;/code&gt;, but directly, with no &lt;code&gt;PendingDispatch&lt;/code&gt; around it. Routing works and &lt;code&gt;Bus::fake()&lt;/code&gt; sees it, while uniqueness, debouncing and the &lt;code&gt;PreparesForDispatch&lt;/code&gt; veto silently do not run. Treat it as &lt;code&gt;Queue::push&lt;/code&gt; with better camouflage and keep it out of application code too.&lt;/p&gt;
&lt;div class=&quot;bleed&quot;&gt;
&lt;pre class=&quot;mermaid&quot;&gt;flowchart TD
    H[&amp;quot;dispatch(new Job)&amp;quot;] --&amp;gt; P
    S[&amp;quot;Job::dispatch()&amp;quot;] --&amp;gt; P
    P[&amp;quot;PendingDispatch::__destruct()&amp;lt;br&amp;gt;fires at end of statement&amp;quot;] --&amp;gt; G
    G[&amp;quot;ShouldBeUnique lock&amp;lt;br&amp;gt;#[DebounceFor] token&amp;lt;br&amp;gt;PreparesForDispatch veto&amp;quot;] --&amp;gt; D
    B[&amp;quot;Bus::dispatch($job)&amp;quot;] -.-&amp;gt; D
    D[&amp;quot;Bus&#92;Dispatcher&amp;lt;br&amp;gt;routing: $queue · #[Queue] · Queue::route()&amp;quot;] --&amp;gt; E
    Q[&amp;quot;Queue::push($job)&amp;quot;] -.-&amp;gt; E
    E[&amp;quot;Queue::enqueueUsing()&amp;lt;br&amp;gt;after_commit gate&amp;quot;] --&amp;gt; W
    W[&amp;quot;driver write&amp;lt;br&amp;gt;Redis / database / SQS&amp;quot;]
    class G diagram-gates
    class B,Q diagram-side
&lt;/pre&gt;&lt;style&gt;
.mermaid .diagram-gates rect { stroke: var(--color-accent) !important; stroke-width: 2px !important; }
.mermaid .diagram-gates .nodeLabel { color: var(--color-accent) !important; }
.mermaid .diagram-side rect { stroke-dasharray: 6 5 !important; }
&lt;/style&gt;
&lt;/div&gt;
&lt;p&gt;Four entry points, one driver write. The dotted arrows are the side doors: they join the column below the gates, and everything above their entry point never runs.&lt;/p&gt;
&lt;h2 id=&quot;the-gap-in-one-table&quot; tabindex=&quot;-1&quot;&gt;The gap, in one table &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#the-gap-in-one-table&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Legend: ✅ honored or enforced, ❌ ignored, bypassed or unavailable.&lt;/p&gt;
&lt;div class=&quot;bleed&quot; style=&quot;font-size: calc(1em - 2px)&quot;&gt;
&lt;div class=&quot;table-scroll&quot; tabindex=&quot;0&quot;&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Queue::push&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Bus::dispatch&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;::dispatch()&lt;/code&gt; / &lt;code&gt;dispatch()&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enqueue moment (&lt;code&gt;after_commit&lt;/code&gt; off)&lt;/td&gt;
&lt;td&gt;during the call&lt;/td&gt;
&lt;td&gt;during the call&lt;/td&gt;
&lt;td&gt;on &lt;code&gt;PendingDispatch&lt;/code&gt; destruction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job&#39;s &lt;code&gt;$connection&lt;/code&gt;, &lt;code&gt;$queue&lt;/code&gt;, &lt;code&gt;$delay&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#[Queue]&lt;/code&gt;, &lt;code&gt;#[Connection]&lt;/code&gt;, &lt;code&gt;#[Delay]&lt;/code&gt; attributes (13)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Queue::route()&lt;/code&gt; central routing (13)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ShouldQueue&lt;/code&gt; missing&lt;/td&gt;
&lt;td&gt;queues anyway&lt;/td&gt;
&lt;td&gt;runs synchronously&lt;/td&gt;
&lt;td&gt;runs synchronously&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ShouldBeUnique&lt;/code&gt; lock&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#[DebounceFor]&lt;/code&gt; debouncing (13)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PreparesForDispatch&lt;/code&gt; cancel hook (13)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fluent &lt;code&gt;-&amp;gt;chain()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&amp;gt;catch()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ queued closures only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visible to &lt;code&gt;Bus::fake()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return value&lt;/td&gt;
&lt;td&gt;driver job id&lt;/td&gt;
&lt;td&gt;driver job id&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PendingDispatch&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Read the middle column top to bottom and the camouflage is visible: &lt;code&gt;Bus::dispatch&lt;/code&gt; agrees with the bus forms on everything a test would catch, and with &lt;code&gt;Queue::push&lt;/code&gt; on everything a test would not.&lt;/p&gt;
&lt;p&gt;Note what &lt;code&gt;Queue::push&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; skip. Payload-level settings (&lt;code&gt;tries&lt;/code&gt;, &lt;code&gt;backoff&lt;/code&gt;, &lt;code&gt;timeout&lt;/code&gt;, &lt;code&gt;maxExceptions&lt;/code&gt;, &lt;code&gt;failOnTimeout&lt;/code&gt;, encryption, batch id, an already configured chain) are applied by &lt;code&gt;createObjectPayload()&lt;/code&gt; on both paths. The push form skips routing and dispatch time decisions, which is exactly what makes its failures quiet.&lt;/p&gt;
&lt;h2 id=&quot;pitfall-1-the-job-lands-on-the-default-queue&quot; tabindex=&quot;-1&quot;&gt;Pitfall 1: the job lands on the default queue &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#pitfall-1-the-job-lands-on-the-default-queue&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Someone configures a job properly:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ShouldQueue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Queueable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __construct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Incident&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $incident)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;onQueue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;alarms&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;onConnection&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;redis-alarms&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then another file does &lt;code&gt;Queue::push(new WakeUpOnCallEngineerJob($incident))&lt;/code&gt;. The job runs, so nobody notices for months. But it runs on the default connection&#39;s default queue, because &lt;code&gt;push()&lt;/code&gt; takes its queue from an argument, not from the job. Your carefully provisioned &lt;code&gt;alarms&lt;/code&gt; worker pool sits idle while the default queue absorbs the load. A &lt;code&gt;delay()&lt;/code&gt; set the same way silently becomes zero.&lt;/p&gt;
&lt;p&gt;The bus path reads all three from the job (or, on Laravel 13, from &lt;code&gt;#[Queue]&lt;/code&gt;, &lt;code&gt;#[Connection]&lt;/code&gt; and &lt;code&gt;#[Delay]&lt;/code&gt; attributes). The push path needs them repeated as arguments, and nothing warns you when they disagree.&lt;/p&gt;
&lt;h2 id=&quot;pitfall-2-the-dispatch-that-moved&quot; tabindex=&quot;-1&quot;&gt;Pitfall 2: the dispatch that moved &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#pitfall-2-the-dispatch-that-moved&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Because the bus forms dispatch in a destructor, holding the return value moves the dispatch:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$pending &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($incident);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// nothing has been enqueued yet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;dispatched&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// log line appears before the job exists&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;unset&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($pending);        &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// enqueued here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assign the result to a variable for logging, collect pendings in an array, or return one from a helper method, and the enqueue slides to wherever that reference dies. That can be the end of the request. It can also cross a transaction boundary in either direction, which changes whether your &lt;code&gt;after_commit&lt;/code&gt; settings even see an open transaction. Inside a long-running worker or Octane, a reference that survives in a captured closure can delay a dispatch indefinitely.&lt;/p&gt;
&lt;p&gt;The fix is a habit: treat &lt;code&gt;Job::dispatch(...)&lt;/code&gt; as a statement, never as a value. If you need the job instance, build it first and hand it to &lt;code&gt;dispatch()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pitfall-3-the-queued-job-that-ran-inline&quot; tabindex=&quot;-1&quot;&gt;Pitfall 3: the queued job that ran inline &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#pitfall-3-the-queued-job-that-ran-inline&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The bus decides queue versus inline with one check (&lt;a href=&quot;https://github.com/laravel/framework/blob/v13.24.0/src/Illuminate/Bus/Dispatcher.php#L84-L89&quot;&gt;Dispatcher.php#L84&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;queueResolver &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;commandShouldBeQueued&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($command)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    ?&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatchToQueue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($command)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    :&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatchNow&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($command);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;commandShouldBeQueued()&lt;/code&gt; is just &lt;code&gt;$command instanceof ShouldQueue&lt;/code&gt;. Forget the interface and &lt;code&gt;dispatch()&lt;/code&gt; runs your job synchronously, inside the web request, with no retries, no backoff, no timeout supervision. The code works in every environment, which is the problem. It works slowly, in the wrong process, and nobody sees it until a slow external call inside the job turns into a slow endpoint.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Queue::push&lt;/code&gt; has the opposite failure: it queues anything you hand it, interface or not. So the same class behaves async in one call site and inline in another, depending on which door it went through.&lt;/p&gt;
&lt;p&gt;Make &lt;code&gt;ShouldQueue&lt;/code&gt; a review checklist item for every new job. When you genuinely want inline execution, say it with &lt;code&gt;dispatchSync()&lt;/code&gt;, which routes through the sync connection and keeps the intent visible.&lt;/p&gt;
&lt;h2 id=&quot;pitfall-4-unique-jobs-that-are-not-unique&quot; tabindex=&quot;-1&quot;&gt;Pitfall 4: unique jobs that are not unique &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#pitfall-4-unique-jobs-that-are-not-unique&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a job you dispatch yourself, &lt;code&gt;ShouldBeUnique&lt;/code&gt; is enforced in exactly one place, &lt;code&gt;PendingDispatch::shouldDispatch()&lt;/code&gt;, which acquires a cache lock before the bus is invoked. (Queued listeners, scheduled jobs and broadcasts acquire the same lock through their own dispatch paths.) &lt;code&gt;Queue::push&lt;/code&gt; never constructs a &lt;code&gt;PendingDispatch&lt;/code&gt;, so it never takes the lock. Every direct push of a &amp;quot;unique&amp;quot; job is a duplicate waiting to run.&lt;/p&gt;
&lt;p&gt;Two sharp edges even on the correct path:&lt;/p&gt;
&lt;p&gt;First, the default lock lifetime is &lt;strong&gt;forever&lt;/strong&gt;. &lt;code&gt;UniqueLock::acquire()&lt;/code&gt; falls back to &lt;code&gt;0&lt;/code&gt; seconds when you define no &lt;code&gt;uniqueFor&lt;/code&gt; (&lt;a href=&quot;https://github.com/laravel/framework/blob/v13.24.0/src/Illuminate/Bus/UniqueLock.php#L37-L47&quot;&gt;UniqueLock.php#L37&lt;/a&gt;), and a Laravel cache lock with zero seconds never expires on its own. If the lock is acquired and the job never runs to completion, nothing else with that key dispatches again until someone clears cache.&lt;/p&gt;
&lt;p&gt;Second, transactions. The lock is taken at destruct time, before any &lt;code&gt;after_commit&lt;/code&gt; deferral. On Laravel 10 and 11, if the transaction rolls back, the job is discarded but the lock stays behind, held until its &lt;code&gt;uniqueFor&lt;/code&gt; expiry, or forever per the previous paragraph. Laravel 12 added a rollback callback that releases the lock, and 13 keeps it. If you run unique jobs with &lt;code&gt;after_commit&lt;/code&gt; on 10 or 11, define &lt;code&gt;uniqueFor&lt;/code&gt; or accept that a rollback can wedge that job class.&lt;/p&gt;
&lt;p&gt;One more constraint the docs bury: &lt;code&gt;ShouldBeUnique&lt;/code&gt; does not imply &lt;code&gt;ShouldQueue&lt;/code&gt;. A unique job without &lt;code&gt;ShouldQueue&lt;/code&gt; acquires the lock and then runs inline, skipping the worker path that releases locks.&lt;/p&gt;
&lt;h2 id=&quot;pitfall-5-the-tests-that-pass-anyway&quot; tabindex=&quot;-1&quot;&gt;Pitfall 5: the tests that pass anyway &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#pitfall-5-the-tests-that-pass-anyway&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Bus::fake()&lt;/code&gt; and &lt;code&gt;Queue::fake()&lt;/code&gt; intercept different layers, and each is blind to the other&#39;s.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Bus::fake()&lt;/code&gt; records every job dispatched through the bus forms, including jobs without &lt;code&gt;ShouldQueue&lt;/code&gt;, because &lt;code&gt;BusFake::dispatch()&lt;/code&gt; records before the routing decision. It sees nothing from &lt;code&gt;Queue::push&lt;/code&gt;, which never touches the bus. &lt;code&gt;Queue::fake()&lt;/code&gt; sees &lt;code&gt;Queue::push&lt;/code&gt; directly, and sees the bus forms only when the job implements &lt;code&gt;ShouldQueue&lt;/code&gt; and actually reaches the queue layer. Install both and &lt;code&gt;Bus::fake()&lt;/code&gt; wins for bus dispatches, so &lt;code&gt;Queue::assertPushed&lt;/code&gt; finds nothing.&lt;/p&gt;
&lt;p&gt;Consequences worth memorizing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Under &lt;code&gt;Queue::fake()&lt;/code&gt;, &lt;code&gt;assertPushed&lt;/code&gt; stays green whether the call site says &lt;code&gt;Queue::push($job)&lt;/code&gt; or &lt;code&gt;WakeUpOnCallEngineerJob::dispatch(...)&lt;/code&gt;. Migrate between the two forms and the test suite cannot tell, while uniqueness, routing and after commit semantics all change underneath it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;QueueFake::later()&lt;/code&gt; records the job immediately and does not simulate the delay. &lt;code&gt;QueueFake&lt;/code&gt; also bypasses the transaction logic in &lt;code&gt;enqueueUsing()&lt;/code&gt; entirely. Fakes prove intent, never timing.&lt;/li&gt;
&lt;li&gt;The destructor applies in tests too. &lt;code&gt;$pending = Job::dispatch(); Bus::assertDispatched(...)&lt;/code&gt; fails because the destructor has not run. The assertion starts passing the moment you drop the assignment.&lt;/li&gt;
&lt;li&gt;A unique job whose lock is already held never reaches the fake, so &lt;code&gt;Bus::fake()&lt;/code&gt; records nothing, and &lt;code&gt;BusFake&lt;/code&gt; never releases locks. &lt;code&gt;QueueFake&lt;/code&gt; is better behaved: it tracks the unique jobs it records, &lt;code&gt;Queue::fake()&lt;/code&gt; releases their locks when the queue gets faked again, and &lt;code&gt;Queue::releaseUniqueJobLocks()&lt;/code&gt; does it on demand. A suite that dispatches unique jobs under &lt;code&gt;Bus::fake()&lt;/code&gt; without clearing cache between tests can still poison itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rule of thumb: assert intent (dispatched, chained, batched) with &lt;code&gt;Bus::fake()&lt;/code&gt;, assert routing (queue name, connection, payload) with &lt;code&gt;Queue::fake()&lt;/code&gt;, and never treat either as evidence about transactions or delays.&lt;/p&gt;
&lt;h2 id=&quot;pitfall-6-dispatched-inside-a-transaction&quot; tabindex=&quot;-1&quot;&gt;Pitfall 6: dispatched inside a transaction &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#pitfall-6-dispatched-inside-a-transaction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The classic bug: dispatch inside &lt;code&gt;DB::transaction()&lt;/code&gt;, the worker picks the job up before the commit lands, the job reads the database and finds nothing. Both dispatch doors are equally exposed, because the fix lives in the queue layer, in &lt;code&gt;enqueueUsing()&lt;/code&gt;, which both paths eventually call.&lt;/p&gt;
&lt;p&gt;The decision, as implemented in 13 (&lt;a href=&quot;https://github.com/laravel/framework/blob/v13.24.0/src/Illuminate/Queue/Queue.php#L396-L407&quot;&gt;Queue.php#L396&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; shouldDispatchAfterCommit&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($job)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ($job &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; ShouldQueueAfterCommit&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($job&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;afterCommit) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $job&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;afterCommit &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $job &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Closure&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; is_object&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($job) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; isset&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($job&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;afterCommit)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $job&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;afterCommit;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;dispatchAfterCommit &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the precedence is: the &lt;code&gt;ShouldQueueAfterCommit&lt;/code&gt; interface, then the job&#39;s own &lt;code&gt;afterCommit()&lt;/code&gt; or &lt;code&gt;beforeCommit()&lt;/code&gt; call, then the connection&#39;s &lt;code&gt;after_commit&lt;/code&gt; config. On 10 and 11 the interface was absolute and &lt;code&gt;beforeCommit()&lt;/code&gt; could not override it. Since 12 it can.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;&#39;after_commit&#39; =&amp;gt; true&lt;/code&gt; on the connection and the whole class of bugs disappears, at the cost of one contract change: every push through that connection now returns &lt;code&gt;null&lt;/code&gt; instead of a job id, transaction or no transaction, because &lt;code&gt;enqueueUsing()&lt;/code&gt; hands the work to the transaction manager and nothing propagates the driver&#39;s return value back. Timing without a transaction stays immediate. The return value does not, so any code that inspects the result of &lt;code&gt;Queue::push&lt;/code&gt; for an id breaks the day you turn the config on.&lt;/p&gt;
&lt;h2 id=&quot;pitfall-7-closures-without-a-safety-net&quot; tabindex=&quot;-1&quot;&gt;Pitfall 7: closures without a safety net &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#pitfall-7-closures-without-a-safety-net&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;dispatch(fn () =&amp;gt; ...)&lt;/code&gt; wraps the closure in &lt;code&gt;CallQueuedClosure&lt;/code&gt; and hands back &lt;code&gt;PendingClosureDispatch&lt;/code&gt;, which is the only place &lt;code&gt;-&amp;gt;catch()&lt;/code&gt; exists:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ($podcast) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    $podcast&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;publish&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Throwable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $e) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // runs when the queued closure exhausts its attempts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Queue::push(fn () =&amp;gt; ...)&lt;/code&gt; also works, which surprises people. &lt;code&gt;createPayload()&lt;/code&gt; performs the same &lt;code&gt;CallQueuedClosure&lt;/code&gt; wrapping. But &lt;code&gt;push&lt;/code&gt; returns a driver id, not a pending object, so there is nowhere to hang &lt;code&gt;-&amp;gt;catch()&lt;/code&gt;, and a failed closure job fails silently into &lt;code&gt;failed_jobs&lt;/code&gt;. If a closure job matters enough to need failure handling, it has probably outgrown being a closure. Make it a class.&lt;/p&gt;
&lt;h2 id=&quot;which-traits-your-job-actually-needs&quot; tabindex=&quot;-1&quot;&gt;Which traits your job actually needs &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#which-traits-your-job-actually-needs&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;php artisan make:job&lt;/code&gt; on Laravel 13 and the stub is two lines of declaration:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Illuminate&#92;Contracts&#92;Queue&#92;ShouldQueue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Illuminate&#92;Foundation&#92;Queue&#92;Queueable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ShouldQueue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Queueable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That single &lt;code&gt;Queueable&lt;/code&gt; is a composite. Laravel uses traits inside traits here, and the composite expands to the four classic ones (&lt;a href=&quot;https://github.com/laravel/framework/blob/v13.24.0/src/Illuminate/Foundation/Queue/Queueable.php#L10-L13&quot;&gt;Queueable.php#L10&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Illuminate&#92;Foundation&#92;Queue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;trait&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Queueable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Dispatchable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;InteractsWithQueue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;QueueableByBus&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;SerializesModels&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Know what each part earns:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Dispatchable&lt;/code&gt;&lt;/strong&gt; provides the static API: &lt;code&gt;dispatch()&lt;/code&gt;, &lt;code&gt;dispatchIf()&lt;/code&gt;, &lt;code&gt;dispatchUnless()&lt;/code&gt;, &lt;code&gt;dispatchSync()&lt;/code&gt;, &lt;code&gt;dispatchAfterResponse()&lt;/code&gt;, &lt;code&gt;withChain()&lt;/code&gt;. Drop it and &lt;code&gt;Job::dispatch()&lt;/code&gt; is a fatal error, though &lt;code&gt;dispatch(new Job)&lt;/code&gt; still works. One detail worth knowing: &lt;code&gt;dispatchIf(false, ...)&lt;/code&gt; with a boolean skips constructing the job entirely and returns a &lt;code&gt;Fluent&lt;/code&gt; stub, while passing a closure as the condition constructs the job first so the closure can inspect it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Illuminate&#92;Bus&#92;Queueable&lt;/code&gt;&lt;/strong&gt; (aliased as &lt;code&gt;QueueableByBus&lt;/code&gt; inside the composite) supplies the routing state: &lt;code&gt;$connection&lt;/code&gt;, &lt;code&gt;$queue&lt;/code&gt;, &lt;code&gt;$delay&lt;/code&gt;, &lt;code&gt;$afterCommit&lt;/code&gt;, chain storage, and every fluent method from Pitfalls 1 and 6 (&lt;code&gt;onQueue&lt;/code&gt;, &lt;code&gt;onConnection&lt;/code&gt;, &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;afterCommit&lt;/code&gt;, &lt;code&gt;beforeCommit&lt;/code&gt;, &lt;code&gt;chain&lt;/code&gt;). Without it the bus still dispatches your job, but there is nothing to configure routing with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;InteractsWithQueue&lt;/code&gt;&lt;/strong&gt; is for the job&#39;s runtime, not its dispatch. It gives &lt;code&gt;handle()&lt;/code&gt; access to &lt;code&gt;$this-&amp;gt;attempts()&lt;/code&gt;, &lt;code&gt;$this-&amp;gt;release($delay)&lt;/code&gt;, &lt;code&gt;$this-&amp;gt;delete()&lt;/code&gt;, &lt;code&gt;$this-&amp;gt;fail($exception)&lt;/code&gt;. Since Laravel 11 it also carries test helpers: &lt;code&gt;$job-&amp;gt;withFakeQueueInteractions()-&amp;gt;handle(); $job-&amp;gt;assertReleased(30);&lt;/code&gt; lets you unit test retry decisions without a real queue.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;SerializesModels&lt;/code&gt;&lt;/strong&gt; changes what goes into the payload. With it, an Eloquent model in your constructor is stored as a &lt;code&gt;ModelIdentifier&lt;/code&gt; (class, key, connection name and loaded relation names) and refetched fresh when the worker runs. Without it, the whole model serializes: stale attributes at execution time, bloated payloads, and crashes when a model carries an unserializable connection or closure. It only does anything when models (or collections of them) appear in your properties, and it pairs with &lt;code&gt;deleteWhenMissingModels&lt;/code&gt; for the case where the row is gone by execution time.&lt;/p&gt;
&lt;p&gt;The rules I would put in a handbook:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In application code, keep the stub&#39;s composite &lt;code&gt;Queueable&lt;/code&gt; on every job, even when a given job uses only part of it. An unused trait costs nothing at runtime, and uniformity is worth more than a minimal import list. Stacking the composite together with the individual traits compiles fine (PHP deduplicates members that originate from the same trait), but it buys you nothing except a confusing use block. The real collision risk is a homegrown trait declaring its own &lt;code&gt;dispatch()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Do not add anything beyond the stub &amp;quot;just in case.&amp;quot; &lt;code&gt;Batchable&lt;/code&gt; belongs only on jobs actually dispatched through &lt;code&gt;Bus::batch()&lt;/code&gt;. &lt;code&gt;ShouldBeUnique&lt;/code&gt;, &lt;code&gt;ShouldBeEncrypted&lt;/code&gt; and &lt;code&gt;ShouldQueueAfterCommit&lt;/code&gt; are contracts with behavior, not decoration.&lt;/li&gt;
&lt;li&gt;In package code, spell out the four traits explicitly instead of the composite, since &lt;code&gt;Illuminate&#92;Foundation&#92;Queue&#92;Queueable&lt;/code&gt; only exists on Laravel 11 and later and your package may support 10.&lt;/li&gt;
&lt;li&gt;Remember the split: interfaces decide (queue or not, unique or not, encrypt or not), traits equip (static API, routing state, queue control, model handling). &lt;code&gt;ShouldQueue&lt;/code&gt; without &lt;code&gt;Dispatchable&lt;/code&gt; fails loudly at the call site. &lt;code&gt;Dispatchable&lt;/code&gt; without &lt;code&gt;ShouldQueue&lt;/code&gt; fails quietly at runtime, which is Pitfall 3.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On Laravel 13 you can also move static configuration out of the constructor into attributes:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;#[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Queue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;alarms&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;#[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Connection&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;redis-alarms&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;#[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Tries&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; WakeUpOnCallEngineerJob&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ShouldQueue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Queueable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bus and the payload builder read these through the same resolution chain as the properties. Attributes fit values that never change per dispatch. Keep the fluent calls for decisions made at the call site.&lt;/p&gt;
&lt;h2 id=&quot;laravel-13-keeps-widening-the-gap&quot; tabindex=&quot;-1&quot;&gt;Laravel 13 keeps widening the gap &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#laravel-13-keeps-widening-the-gap&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every feature below ships in the dispatch path. None of them exist for &lt;code&gt;Queue::push&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Central routing.&lt;/strong&gt; &lt;code&gt;Queue::route(WakeUpOnCallEngineerJob::class, queue: &#39;alarms&#39;, connection: &#39;redis-alarms&#39;)&lt;/code&gt; in a service provider replaces scattered &lt;code&gt;onQueue()&lt;/code&gt; calls. The resolution order is attribute or property first, then the route table, then defaults. Mail, notifications, broadcasts and queued event listeners consult the same table, so one registry finally describes your whole queue topology. Raw &lt;code&gt;Queue::push&lt;/code&gt; never looks at it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debouncing.&lt;/strong&gt; &lt;code&gt;#[DebounceFor(30)]&lt;/code&gt; delays each dispatch by the debounce window (an explicit &lt;code&gt;-&amp;gt;delay()&lt;/code&gt; on the job wins over it) and stamps it with an owner token from a cache lock acquired in &lt;code&gt;PendingDispatch&lt;/code&gt;. Every dispatch in a burst still enqueues, but at execution time &lt;code&gt;CallQueuedHandler&lt;/code&gt; drops any job whose token was superseded by a newer dispatch (&lt;a href=&quot;https://github.com/laravel/framework/blob/v13.24.0/src/Illuminate/Queue/CallQueuedHandler.php#L256-L266&quot;&gt;CallQueuedHandler.php#L256&lt;/a&gt;), so only the latest one runs. A second &lt;code&gt;maxWait&lt;/code&gt; argument forces a run even while events keep arriving. The framework refuses to combine it with &lt;code&gt;ShouldBeUnique&lt;/code&gt;, and when the dispatch is deferred with &lt;code&gt;after_commit&lt;/code&gt;, a rollback releases the debounce lock.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A dispatch veto.&lt;/strong&gt; Implement &lt;code&gt;PreparesForDispatch&lt;/code&gt; and &lt;code&gt;prepareForDispatch()&lt;/code&gt; runs inside &lt;code&gt;shouldDispatch()&lt;/code&gt;; return &lt;code&gt;false&lt;/code&gt; and the dispatch is cancelled before the bus hears about it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FIFO support.&lt;/strong&gt; &lt;code&gt;-&amp;gt;onGroup()&lt;/code&gt; and &lt;code&gt;-&amp;gt;withDeduplicator()&lt;/code&gt; on &lt;code&gt;PendingDispatch&lt;/code&gt; target SQS FIFO message groups and deduplication.&lt;/p&gt;
&lt;p&gt;Each release makes the two doors less interchangeable, always in the same direction. The bus accumulates behavior, the queue layer stays raw. A codebase that still mixes them in 13 is not choosing between equivalent styles. It is randomly opting some dispatches out of uniqueness, debouncing, routing and cancellation.&lt;/p&gt;
&lt;h2 id=&quot;the-convention&quot; tabindex=&quot;-1&quot;&gt;The convention &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#the-convention&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My default recommendation starts from a boring observation: the official documentation teaches the two bus spellings, so that is what every new hire, every Stack Overflow answer and every AI agent already knows.&lt;/p&gt;
&lt;p&gt;Between the two, I pick the helper, and this part is personal. &lt;code&gt;SomeJob::dispatch($incident)&lt;/code&gt; forwards its arguments to the constructor through &lt;code&gt;new static(...$arguments)&lt;/code&gt;, a variadic hop that static analyzers cannot see through without plugin help. Wrong argument count, wrong type, renamed constructor parameter: none of it gets flagged at the call site. &lt;code&gt;dispatch(new WakeUpOnCallEngineerJob($incident))&lt;/code&gt; is a real constructor call, checked by PHPStan and your IDE for free. One more piece of Laravel magic (the same family I &lt;a href=&quot;https://alies.dev/articles/cost-of-eloquent-magic/&quot;&gt;measured before&lt;/a&gt;) that you can opt out of at zero cost.&lt;/p&gt;
&lt;p&gt;Paste this into your docs and AI agent instructions and adjust names:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold&quot;&gt;## Queue dispatch rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Dispatch jobs with &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`dispatch(new SomeJob(...))`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;. The static&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   `SomeJob::dispatch(...)`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; form is fine if your team standardizes on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   it instead; pick exactly one. Queued closures use the same helper.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; `Queue::push`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`Queue::pushOn`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`Queue::later`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`Queue::laterOn`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   `Queue::bulk`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; and &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`Bus::dispatch`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; are banned in application code.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   Delays are expressed with &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`-&gt;delay()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, routing per rules 4 and 5.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Every job class implements &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`ShouldQueue`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; and uses the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   `Illuminate&#92;Foundation&#92;Queue&#92;Queueable`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; composite trait. Inline&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   execution is spelled &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`SomeJob::dispatchSync(...)`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;4.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Static per-class routing lives in &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`#[Queue]`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`#[Connection]`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   attributes or the &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`Queue::route()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; registry, in one service provider.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   Call site &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`onQueue()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`onConnection()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; is reserved for genuinely&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   dynamic routing and needs a comment saying why.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;5.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Never assign the result of &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`dispatch()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; or &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`SomeJob::dispatch()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   a variable. Configure fluently in the same statement.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;6.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Every queue connection sets &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`&#39;after_commit&#39; =&gt; true`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;. Jobs that must&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   escape it call &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`-&gt;beforeCommit()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; explicitly. That override works on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   every covered version; only overriding the ShouldQueueAfterCommit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;   interface itself needs Laravel 12 or newer.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;7.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Unique jobs define &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`uniqueFor`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;. No unlimited locks.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;8.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Tests assert intent with &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`Bus::fake()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; and routing with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   `Queue::fake()`&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, never both faked in one test without a reason.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rules 1 and 2 are mechanically enforceable with &lt;a href=&quot;https://github.com/spaze/phpstan-disallowed-calls&quot;&gt;spaze/phpstan-disallowed-calls&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;parameters:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    disallowedStaticCalls:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            method: &#39;Illuminate&#92;Support&#92;Facades&#92;Queue::push()&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            message: &#39;dispatch jobs with SomeJob::dispatch(), see queue rules&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            allowIn:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                - tests/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            method: &#39;Illuminate&#92;Support&#92;Facades&#92;Queue::later()&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            message: &#39;use SomeJob::dispatch(...)-&gt;delay(...)&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            allowIn:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                - tests/*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extend the list with &lt;code&gt;pushOn&lt;/code&gt;, &lt;code&gt;laterOn&lt;/code&gt;, &lt;code&gt;bulk&lt;/code&gt; and &lt;code&gt;Bus::dispatch()&lt;/code&gt;. Two honest caveats. These static rules catch the facades only, so an injected &lt;code&gt;Illuminate&#92;Contracts&#92;Queue&#92;Queue&lt;/code&gt; instance or &lt;code&gt;Queue::connection(&#39;x&#39;)-&amp;gt;push(...)&lt;/code&gt; needs matching &lt;code&gt;disallowedMethodCalls&lt;/code&gt; entries on the contract to close the side doors. And the &lt;code&gt;allowIn&lt;/code&gt; exception matters, because tests legitimately use the facade to arrange scenarios.&lt;/p&gt;
&lt;p&gt;The rules above are a default, not a dogma. The actual rule is one form, chosen with open eyes. A long-lived codebase with a senior team and enforcement tooling can standardize on any of the three, &lt;code&gt;Queue::push&lt;/code&gt; included. The low-level form is not bad. It is explicit, it is predictable, and a team that passes connection and queue arguments deliberately and handles uniqueness where it matters loses little. What ruins projects is mixing, where each call site opts out of a different subset of guarantees and nobody can say which without reading the framework. If you pick &lt;code&gt;Queue::push&lt;/code&gt;, pick it on purpose, document what it skips, and enforce it with the same PHPStan rule pointed the other way.&lt;/p&gt;
&lt;h2 id=&quot;when-queue-push-is-the-right-call&quot; tabindex=&quot;-1&quot;&gt;When Queue::push is the right call &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#when-queue-push-is-the-right-call&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The framework itself uses the low level API where the bus&#39;s assumptions do not hold. &lt;code&gt;BroadcastManager&lt;/code&gt; pushes broadcast events with &lt;code&gt;pushOn()&lt;/code&gt;, and &lt;code&gt;Mailable&lt;/code&gt; queues itself the same way, because neither can assume the object carries &lt;code&gt;Dispatchable&lt;/code&gt; or wants bus semantics. If you write framework extensions or packages that queue arbitrary user objects, you are in the same position, and &lt;code&gt;Queue::push&lt;/code&gt; with explicit connection and queue arguments is the honest tool. Inside an application, that situation is rare enough that a code comment should mark every occurrence.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/nothing-happens-when-you-dispatch/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Queue::push&lt;/code&gt; is a raw write to the queue backend. &lt;code&gt;SomeJob::dispatch()&lt;/code&gt; and &lt;code&gt;dispatch()&lt;/code&gt; are the command bus, wrapped in a &lt;code&gt;PendingDispatch&lt;/code&gt; that dispatches from its destructor and carries uniqueness, debouncing, routing, transaction awareness and cancellation. The three lines from the code review at the top produce the same row in Redis only for the simplest possible job, and the set of jobs that qualify shrinks with every release.&lt;/p&gt;
&lt;p&gt;Default to the bus, in whichever spelling your team picks. Mine is &lt;code&gt;dispatch(new SomeJob(...))&lt;/code&gt;, the one static analyzers can check. If your team standardizes on something else, even &lt;code&gt;Queue::push&lt;/code&gt;, make it a written decision and let static analysis hold the line. The failure mode is not the wrong form. It is three forms at once.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Verified against the Laravel 13.24 vendor source and the 10.x, 11.x and 12.x branch tips on 2026-08-11. Class and method names cited: &lt;code&gt;Illuminate&#92;Foundation&#92;Bus&#92;PendingDispatch&lt;/code&gt;, &lt;code&gt;Illuminate&#92;Foundation&#92;Bus&#92;Dispatchable&lt;/code&gt;, &lt;code&gt;Illuminate&#92;Bus&#92;Dispatcher&lt;/code&gt;, &lt;code&gt;Illuminate&#92;Queue&#92;Queue&lt;/code&gt;, &lt;code&gt;Illuminate&#92;Bus&#92;UniqueLock&lt;/code&gt;, &lt;code&gt;Illuminate&#92;Queue&#92;CallQueuedHandler&lt;/code&gt;, &lt;code&gt;Illuminate&#92;Support&#92;Testing&#92;Fakes&#92;BusFake&lt;/code&gt;, &lt;code&gt;Illuminate&#92;Support&#92;Testing&#92;Fakes&#92;QueueFake&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Stop Wasting 89% of Your AI Agent&#39;s Tokens on CLI Noise</title>
		<link href="https://alies.dev/articles/cli-output-for-ai/"/>
		<updated>2026-03-25T00:00:00Z</updated>
		<id>https://alies.dev/articles/cli-output-for-ai/</id>
		<content type="html">&lt;div class=&quot;tokenizer-hero&quot;&gt;
	&lt;div class=&quot;tokenizer-text&quot;&gt;&lt;span class=&quot;t1&quot;&gt;PHP&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;Unit&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; by&lt;/span&gt;&lt;span class=&quot;t10&quot;&gt; Sebastian&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt; Berg&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;mann&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; and&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt; contributors&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;.
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt;Runtime&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; PHP&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;t10&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;/www&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt;/html&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;/php&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt;.xml&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;.......&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;63&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t10&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;%)
&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;.......&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;126&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;%)
&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;.......&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t10&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;189&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;%)
&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;....&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;252&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t10&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t3&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;%)
&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;.......&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;315&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;63&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;%)
&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t10&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;.......&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;378&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;75&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;%)
&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;.......&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t7&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;441&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t10&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t1&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t2&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t4&quot;&gt;87&lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;%)
&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt;................................&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;........................&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;t9&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;t1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t2&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t3&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;t4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;t5&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;t6&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;t7&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;t8&quot;&gt;%)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;tokenizer-label&quot;&gt;~250 tokens of PHPUnit output — 45% is noise from progress dots&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;style&gt;
	.tokenizer-hero {
		max-width: 800px;
		background-color: #f8f9fa;
		border-radius: 10px;
		padding: 24px;
		box-shadow: 0 0 10px rgba(0,0,0,0.08);
		overflow: hidden;
		margin: 0 auto;
		font-family: &#39;Courier New&#39;, Courier, monospace;
	}

	.tokenizer-text {
		font-size: 13px;
		line-height: 1.7;
		white-space: pre;
		overflow-x: auto;
	}

	.tokenizer-label {
		margin-top: 16px;
		font-family: -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, Roboto, sans-serif;
		font-size: 13px;
		color: #6b7280;
		text-align: center;
	}

	.tokenizer-hero .t1  { background-color: #bfdbfe; color: #1e3a5f; }
	.tokenizer-hero .t2  { background-color: #fde68a; color: #713f12; }
	.tokenizer-hero .t3  { background-color: #bbf7d0; color: #14532d; }
	.tokenizer-hero .t4  { background-color: #fecaca; color: #7f1d1d; }
	.tokenizer-hero .t5  { background-color: #e9d5ff; color: #4c1d95; }
	.tokenizer-hero .t6  { background-color: #fed7aa; color: #7c2d12; }
	.tokenizer-hero .t7  { background-color: #a5f3fc; color: #155e75; }
	.tokenizer-hero .t8  { background-color: #d1d5db; color: #374151; }
	.tokenizer-hero .t9  { background-color: #c7d2fe; color: #312e81; }
	.tokenizer-hero .t10 { background-color: #fca5a5; color: #7f1d1d; }

	@media (prefers-color-scheme: dark) {
		.tokenizer-hero {
			background-color: #1e2e3e;
			box-shadow: 0 0 10px rgba(0,0,0,0.3);
		}
		.tokenizer-label {
			color: #9ca3af;
		}
		.tokenizer-hero .t1  { background-color: #1e3a5f; color: #bfdbfe; }
		.tokenizer-hero .t2  { background-color: #713f12; color: #fde68a; }
		.tokenizer-hero .t3  { background-color: #14532d; color: #bbf7d0; }
		.tokenizer-hero .t4  { background-color: #7f1d1d; color: #fecaca; }
		.tokenizer-hero .t5  { background-color: #4c1d95; color: #e9d5ff; }
		.tokenizer-hero .t6  { background-color: #7c2d12; color: #fed7aa; }
		.tokenizer-hero .t7  { background-color: #155e75; color: #a5f3fc; }
		.tokenizer-hero .t8  { background-color: #374151; color: #d1d5db; }
		.tokenizer-hero .t9  { background-color: #312e81; color: #c7d2fe; }
		.tokenizer-hero .t10 { background-color: #7f1d1d; color: #fca5a5; }
	}

	.code-sm [class^=&quot;language-&quot;],
	.code-sm [class*=&quot; language-&quot;] {
		font-size: 13px;
	}

	.tokenizer-text span {
		opacity: 0;
	}
	.tokenizer-text span.visible {
		opacity: 1;
	}
&lt;/style&gt;
&lt;script&gt;
	(function () {
		const tokens = document.querySelectorAll(&#39;.tokenizer-text span&#39;);
		const delay = 13;
		const observer = new IntersectionObserver(function (entries) {
			if (!entries[0].isIntersecting) return;
			observer.disconnect();
			tokens.forEach(function (token, i) {
				setTimeout(function () { token.classList.add(&#39;visible&#39;); }, i * delay);
			});
		});
		observer.observe(document.querySelector(&#39;.tokenizer-hero&#39;));
	})();
&lt;/script&gt;
&lt;p&gt;AI coding agents - Claude Code, Cursor, GitHub Copilot, Windsurf - run your CLI tools and feed the output back into the LLM context window.
The problem: most CLI tools were built for humans staring at terminals, not for machines parsing results.&lt;/p&gt;
&lt;p&gt;Progress bars, color codes, box-drawing borders, ASCII art banners - all meaningless noise for an LLM. And you&#39;re paying for every token of it.&lt;/p&gt;
&lt;h2 id=&quot;the-numbers&quot; tabindex=&quot;-1&quot;&gt;The numbers &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/cli-output-for-ai/#the-numbers&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over ~2,900 CLI commands measured by &lt;a href=&quot;https://www.rtk-ai.app/&quot;&gt;rtk-ai&lt;/a&gt;, &lt;strong&gt;11.6M input tokens were consumed, of which 10.3M (89.2%) were noise&lt;/strong&gt;.
A typical 2-hour AI coding session generates ~210K tokens of raw CLI output - enough to overflow a 200K context window with mostly garbage.&lt;/p&gt;
&lt;p&gt;A team of 10 developers wastes approximately &lt;strong&gt;$1,750/month&lt;/strong&gt; on noise tokens alone.&lt;/p&gt;
&lt;h2 id=&quot;a-phpunit-example&quot; tabindex=&quot;-1&quot;&gt;A PHPUnit example &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/cli-output-for-ai/#a-phpunit-example&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s the default PHPUnit output for a test suite with 500 tests, 1 failure:&lt;/p&gt;
&lt;div class=&quot;code-sm no-copy&quot;&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PHPUnit 12.5.14 by Sebastian Bergmann and contributors.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Runtime:       PHP 8.4.19&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Configuration: /var/www/html/phpunit.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...............................................................   63 / 500 ( 12%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...............................................................  126 / 500 ( 25%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...............................................................  189 / 500 ( 37%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;..................................F............................  252 / 500 ( 50%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...............................................................  315 / 500 ( 63%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...............................................................  378 / 500 ( 75%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...............................................................  441 / 500 ( 87%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...........................................................      500 / 500 (100%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time: 00:12.345, Memory: 256.00 MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;There was 1 failure:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1) Tests&#92;Unit&#92;AppHelperTest::get_morph_class_accepts_model_instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Failed asserting that two strings are identical.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;--- Expected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+++ Actual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@@ @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-&#39;App&#92;Models&#92;Role&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+&#39;App&#92;Models&#92;Role---error&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/var/www/html/tests/Unit/AppHelperTest.php:20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;FAILURES!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Tests: 500, Assertions: 1200, Failures: 1.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;~250 tokens.&lt;/strong&gt; The progress lines, banner, timing, and memory stats account for most of it. The actual failure information is only ~85 tokens.&lt;/p&gt;
&lt;p&gt;Now the same result with &lt;code&gt;--no-progress&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-sm no-copy&quot;&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PHPUnit 12.5.14 by Sebastian Bergmann and contributors.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Runtime:       PHP 8.4.19&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Configuration: /var/www/html/phpunit.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time: 00:12.345, Memory: 256.00 MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;There was 1 failure:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1) Tests&#92;Unit&#92;AppHelperTest::get_morph_class_accepts_model_instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Failed asserting that two strings are identical.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;--- Expected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+++ Actual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@@ @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-&#39;App&#92;Models&#92;Role&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+&#39;App&#92;Models&#92;Role---error&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/var/www/html/tests/Unit/AppHelperTest.php:20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;FAILURES!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Tests: 500, Assertions: 1200, Failures: 1.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;~140 tokens.&lt;/strong&gt; Same failure details. The banner and footer are still there (PHPUnit doesn&#39;t let you suppress them), but the 500 progress dots are gone. &lt;strong&gt;~45% reduction&lt;/strong&gt; - and on a 5,000-test suite, the savings are even larger.&lt;/p&gt;
&lt;h2 id=&quot;what-wastes-the-most-tokens&quot; tabindex=&quot;-1&quot;&gt;What wastes the most tokens &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/cli-output-for-ai/#what-wastes-the-most-tokens&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;table-scroll&quot; tabindex=&quot;0&quot;&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Token waster&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Progress bars (&lt;code&gt;████&lt;/code&gt;, dots)&lt;/td&gt;
&lt;td&gt;500-2000 tokens per run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Box-drawing borders (&lt;code&gt;+---+&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2-5x more tokens than plain text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASCII art banners&lt;/td&gt;
&lt;td&gt;50-200 tokens per logo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated dots (PHPUnit)&lt;/td&gt;
&lt;td&gt;~1 token per dot, hundreds per suite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Note: ANSI color codes (&lt;code&gt;&#92;x1b[31m&lt;/code&gt;) are often cited as a waste, but most CLI tools &lt;strong&gt;auto-detect TTY&lt;/strong&gt; and disable colors when output is piped - which is always the case with AI agents. Flags like &lt;code&gt;--colors=never&lt;/code&gt;, &lt;code&gt;--no-ansi&lt;/code&gt;, and &lt;code&gt;--monochrome&lt;/code&gt; are usually redundant. The flags below focus on what actually matters.&lt;/p&gt;
&lt;h2 id=&quot;the-fix-one-flag-per-tool&quot; tabindex=&quot;-1&quot;&gt;The fix: one flag per tool &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/cli-output-for-ai/#the-fix-one-flag-per-tool&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every PHP quality tool has flags to disable the noise. Here&#39;s the cheat sheet:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# PHPUnit / ParaTest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;--no-progress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# PHPStan - use raw format (file:line:message, one per line)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;--no-progress&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --error-format=raw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Psalm - use text format (file:line:col:severity, one per line)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Psalm 7: use --output-format=compact (one-line, relative paths, no URLs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;--no-progress&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --no-suggestions&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --output-format=text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# phpcs - use emacs format (file:line:col:severity, one per line)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;--report&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;emacs&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -q&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# PHP-CS-Fixer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;--show-progress&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Rector&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;--no-progress-bar&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --output-format=github&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Pint - use agent format (auto-detected in Claude Code/OpenCode)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;./vendor/bin/pint&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --test&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --format&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Composer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -q&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;PHPStan 2.x note:&lt;/strong&gt; When &lt;code&gt;CLAUDECODE=1&lt;/code&gt; is set (always true in Claude Code), PHPStan injects a ~940-byte preamble with AI instructions and adds &lt;code&gt;[identifier=X]&lt;/code&gt; suffixes to every error. This agent detection overhead can be larger than the format difference itself. If it bothers you, set &lt;code&gt;CLAUDECODE=0&lt;/code&gt; before running PHPStan.&lt;/p&gt;
&lt;h2 id=&quot;where-to-put-these-flags&quot; tabindex=&quot;-1&quot;&gt;Where to put these flags &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/cli-output-for-ai/#where-to-put-these-flags&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Don&#39;t memorize them. Put them in your &lt;code&gt;CLAUDE.md&lt;/code&gt; or &lt;code&gt;AGENTS.md&lt;/code&gt; file - this is read by Claude Code, Cursor, Gemini CLI, OpenCode, and others:&lt;/p&gt;
&lt;div class=&quot;code-sm&quot;&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold&quot;&gt;## Running Tools&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;Always use these flags when running CLI tools:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Tests: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`vendor/bin/phpunit --no-progress`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; PHPStan: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`vendor/bin/phpstan analyse --no-progress --error-format=raw`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Psalm: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`vendor/bin/psalm --no-progress --no-suggestions --output-format=text`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; phpcs: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`vendor/bin/phpcs --report=emacs -q`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; PHP-CS-Fixer: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`vendor/bin/php-cs-fixer fix --show-progress=none -q -n`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Rector: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;`vendor/bin/rector process --no-progress-bar --output-format=github`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-pattern&quot; tabindex=&quot;-1&quot;&gt;The pattern &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/cli-output-for-ai/#the-pattern&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Across all tools, the pattern is the same:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Disable progress bars&lt;/strong&gt; - the #1 token waster&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use one-line-per-error format&lt;/strong&gt; - &lt;code&gt;raw&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;emacs&lt;/code&gt;, &lt;code&gt;github&lt;/code&gt; or &lt;code&gt;compact&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&#39;t switch to JSON&lt;/strong&gt; - it has ~50% overhead from key repetition. Plain text is more token-efficient for error lists&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skip color flags&lt;/strong&gt; - most tools auto-detect TTY and disable colors when piped&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do this once, save thousands of tokens per session, and stop feeding your AI agent junk.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Token counts in this article are measured with the &lt;a href=&quot;https://github.com/openai/tiktoken&quot;&gt;cl100k_base&lt;/a&gt; tokenizer (GPT-4). Claude, Gemini, and other models use different tokenizers, so exact counts will vary — but the ratios and savings hold across models.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;whats-else&quot; tabindex=&quot;-1&quot;&gt;What&#39;s else? &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/cli-output-for-ai/#whats-else&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This article covers PHP, but the same problem exists in every ecosystem.
I&#39;ve collected quiet-mode flags for &lt;strong&gt;Node, Python, Go, Rust, Ruby, Java, Kotlin, Swift, and .NET&lt;/strong&gt; in one place: &lt;strong&gt;&lt;a href=&quot;https://github.com/alies-dev/awesome-ai-friendly-cli&quot;&gt;awesome-ai-friendly-cli&lt;/a&gt;&lt;/strong&gt; — a curated list of CLI flags that cut token waste across languages and tools.&lt;/p&gt;
&lt;p&gt;If you want to go further, check out &lt;strong&gt;&lt;a href=&quot;https://www.rtk-ai.app/&quot;&gt;rtk&lt;/a&gt;&lt;/strong&gt; - a CLI proxy that sits between your AI agent and your tools, automatically filtering noise tokens in real time.
No flags to remember, no &lt;code&gt;CLAUDE.md&lt;/code&gt; to maintain.
It measured the 89% waste number at the top of this article.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>First hour of a new Laravel project</title>
		<link href="https://alies.dev/articles/laravel-first-hour-setup/"/>
		<updated>2024-07-05T00:00:00Z</updated>
		<id>https://alies.dev/articles/laravel-first-hour-setup/</id>
		<content type="html">&lt;div class=&quot;terminal-hero&quot;&gt;
	&lt;div class=&quot;terminal-header&quot;&gt;
		&lt;div class=&quot;terminal-button close&quot;&gt;&lt;/div&gt;
		&lt;div class=&quot;terminal-button minimize&quot;&gt;&lt;/div&gt;
		&lt;div class=&quot;terminal-button maximize&quot;&gt;&lt;/div&gt;
	&lt;/div&gt;
	&lt;div class=&quot;terminal-content&quot;&gt;
		&lt;div class=&quot;output&quot;&gt;
			&lt;div class=&quot;output-info&quot;&gt;&lt;span class=&quot;info&quot;&gt;INFO&lt;/span&gt; Preparing database.&lt;/div&gt;
			Creating migration table .............................................. 2.71ms &lt;span class=&quot;done&quot;&gt;DONE&lt;/span&gt;&lt;br&gt;
			&lt;div class=&quot;output-info&quot;&gt;&lt;span class=&quot;info&quot;&gt;INFO&lt;/span&gt; Running migrations.&lt;/div&gt;
			0001_01_01_000000_create_users_table .................................. 2.88ms &lt;span class=&quot;done&quot;&gt;DONE&lt;/span&gt;&lt;br&gt;
			0001_01_01_000001_create_cache_table .................................. 1.00ms &lt;span class=&quot;done&quot;&gt;DONE&lt;/span&gt;&lt;br&gt;
			0001_01_01_000002_create_jobs_table ................................... 2.08ms &lt;span class=&quot;done&quot;&gt;DONE&lt;/span&gt;&lt;br&gt;
		&lt;/div&gt;
		&lt;div class=&quot;prompt&quot;&gt;
			&lt;span class=&quot;segment segment-path&quot;&gt;~/code/alies-dev/new-project&lt;/span&gt;&lt;span class=&quot;separator separator-path&quot;&gt;&lt;/span&gt;&lt;span class=&quot;segment segment-branch&quot;&gt;&lt;svg class=&quot;branch-icon&quot; viewBox=&quot;0 0 16 16&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M11.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm-2.25.75a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.492 2.492 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM3.5 3.25a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;main&lt;/span&gt;&lt;span class=&quot;separator separator-branch&quot;&gt;&lt;/span&gt;&lt;span class=&quot;cursor cursor-blinking&quot; contenteditable=&quot;&quot;&gt;&amp;nbsp;&lt;/span&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;
&lt;style&gt;
	.terminal-hero {
		max-width: 800px;
		height: 300px;
		background-color: #000;
		border-radius: 10px;
		padding: 20px;
		box-shadow: 0 0 10px rgba(255,255,255,0.1);
		overflow: hidden;
		margin: 0 auto;
		font-family: monospace;
	}

	.terminal-header {
		display: flex;
		justify-content: flex-start;
		margin-bottom: 10px;
	}

	.terminal-button {
		width: 12px;
		height: 12px;
		border-radius: 50%;
		margin-right: 6px;
	}

	.close { background-color: #ff5f56; }
	.minimize { background-color: #ffbd2e; }
	.maximize { background-color: #27c93f; }

	.terminal-content {
		padding-top: 15px;
		color: #ffffff;
		font-size: 14px;
		line-height: 1.5;
	}

	.output {
		margin-bottom: 25px;
		color: #d6d6d6;
	}

	.output-info {
		margin: 15px 0 15px 0;
	}

	.info {
		padding: 3px;
		background-color: rgb(50 88 125);
		color: rgb(128 128 128);
	}
	.done { color: #2ecc71; }

	.prompt {
		display: flex;
		align-items: center;
		font-size: 13px;
		line-height: 1;
	}

	.segment {
		display: inline-flex;
		align-items: center;
		gap: 6px;
		height: 24px;
		padding: 0 10px;
		white-space: nowrap;
	}

	.segment-path {
		background-color: rgb(50 88 125);
		color: #ffffff;
	}

	.segment-branch {
		background-color: #f1c40f;
		color: #1a1a1a;
	}

	/* Powerline-style chevrons drawn in CSS, so no Nerd Font is required.
	   The element carries the colour of the following segment, the ::before
	   triangle carries the colour of the preceding one. */
	.separator {
		position: relative;
		width: 10px;
		height: 24px;
	}

	.separator::before {
		content: &#39;&#39;;
		position: absolute;
		inset: 0;
		clip-path: polygon(0 0, 100% 50%, 0 100%);
	}

	.separator-path {
		background-color: #f1c40f;
	}

	.separator-path::before {
		background-color: rgb(50 88 125);
	}

	.separator-branch::before {
		background-color: #f1c40f;
	}

	.cursor {
		display: inline-block;
		margin-left: 8px;
		color: #d6d6d6;
	}

	.cursor-blinking:not(:focus) {
		animation: blink 1s step-end infinite;
		background-color: #ffffff;
	}

	@keyframes blink {
		0% { opacity: 0; }
		50% { opacity: 1; }
		100% { opacity: 0; }
	}
&lt;/style&gt;
&lt;p&gt;Great! You&#39;ve just created a new Laravel project and want to do everything right from the start, correct?
This guide will walk you through essential steps to optimize your new Laravel project in its first hour.&lt;/p&gt;
&lt;h2 id=&quot;configure-eloquent-strictness&quot; tabindex=&quot;-1&quot;&gt;Configure Eloquent Strictness &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#configure-eloquent-strictness&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Laravel provides the &lt;a href=&quot;https://github.com/laravel/framework/blob/83e28d065b7bc53f3e53a5c188806844eee30161/src/Illuminate/Database/Eloquent/Model.php#L409-L414&quot;&gt;&lt;code&gt;Model::shouldBeStrict&lt;/code&gt;&lt;/a&gt; method that does three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Prevents lazy loading (addressing the N+1 problem). See &lt;a href=&quot;https://laravel.com/docs/master/eloquent-relationships#preventing-lazy-loading&quot;&gt;Preventing Lazy Loading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Prevents silently discarding attributes (throws an exception when attempting to fill an unfillable attribute)&lt;/li&gt;
&lt;li&gt;Prevents accessing missing attributes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &amp;quot;lazy loading&amp;quot; prevention often depends on database data, so it&#39;s better to avoid throwing an exception in production.
For the other two, you can enable them in all environments:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// AppServiceProvider.php or any other service provider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; boot&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; void&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Model&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;preventLazyLoading&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;isProduction&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Model&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;preventSilentlyDiscardingAttributes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Model&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;preventAccessingMissingAttributes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;choose-primary-key-type&quot; tabindex=&quot;-1&quot;&gt;Choose Primary Key Type &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#choose-primary-key-type&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are three common types of primary keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto-incrementing integer (technically, by default it&#39;s an &lt;code&gt;UNSIGNED BIGINT&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;UUID (example: &lt;code&gt;6e48762e-8c54-43ab-b2f2-09eebb59ad9b&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;ULID (example: &lt;code&gt;01j2qxp0rg5618brj9c9kmrk6h&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Choosing the right type is a big topic (you can start by reading the &lt;a href=&quot;https://laravel.com/docs/master/eloquent#uuid-and-ulid-keys&quot;&gt;Laravel documentation&lt;/a&gt;).
If you choose UUID or ULID, you can instruct Laravel to use the proper morph key type
when you use &lt;code&gt;$table-&amp;gt;morphs()&lt;/code&gt; and &lt;code&gt;$table-&amp;gt;nullableMorphs()&lt;/code&gt; in migrations:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// AppServiceProvider.php or any other service provider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; boot&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; void&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Builder&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;morphUsingUuids&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// for UUID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Builder&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;morphUsingUlids&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// for ULID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other packages may (and should) also respect this setting (e.g., Laravel Nova).&lt;/p&gt;
&lt;h2 id=&quot;enforce-morph-map&quot; tabindex=&quot;-1&quot;&gt;Enforce Morph Map &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#enforce-morph-map&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you plan to rename your Models (rename a class or change a namespace),
I recommend enforcing a morph map to avoid data corruption.
This way, Laravel will not store the fully qualified class name (FQCN) in the database, but a short alias instead.
If an alias is not set, Laravel will throw a &lt;code&gt;&#92;Illuminate&#92;Database&#92;ClassMorphViolationException&lt;/code&gt; exception.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// AppServiceProvider.php or any other service provider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; boot&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; void&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Relation&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;enforceMorphMap&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        &#39;user&#39;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::class&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        &#39;team&#39;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Team&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::class&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;prohibit-destructive-commands-on-production&quot; tabindex=&quot;-1&quot;&gt;Prohibit Destructive Commands on Production &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#prohibit-destructive-commands-on-production&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To avoid accidental data loss, you can prohibit destructive commands on production.
Laravel provides a handy &lt;a href=&quot;https://laravel-news.com/prevent-destructive-commands-from-running-in-laravel-11&quot;&gt;&lt;code&gt;DB::prohibitDestructiveCommands&lt;/code&gt;&lt;/a&gt; method to do this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// AppServiceProvider.php or any other service provider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; boot&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; void&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    DB&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;prohibitDestructiveCommands&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;environment&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;production&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;use-immutable-dates&quot; tabindex=&quot;-1&quot;&gt;Use immutable dates &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#use-immutable-dates&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, Laravel uses mutable Carbon instances.
In practice, that means to avoid changing values of &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; attributes, you need to first clone Carbon objects:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$monthAfterRegistration &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $user&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;created_at&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;clone&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;addMonth&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can instruct Laravel to always create immutable Carbon instances:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// AppServiceProvider.php or any other service provider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Carbon&#92;CarbonImmutable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Illuminate&#92;Support&#92;Facades&#92;Date&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; boot&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; void&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Date&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;CarbonImmutable&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;::class&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a small cost of memory consumption, you can avoid many bugs related to mutable dates and eliminate the need to call the &lt;code&gt;clone()&lt;/code&gt; method.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B31D28;--shiki-dark:#FDAEB7&quot;&gt;- $monthAfterRegistration = $user-&gt;created_at-&gt;clone()-&gt;addMonth();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;+ $monthAfterRegistration = $user-&gt;created_at-&gt;addMonth();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;install-composer-packages&quot; tabindex=&quot;-1&quot;&gt;Install Composer Packages &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#install-composer-packages&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;clockwork&quot; tabindex=&quot;-1&quot;&gt;Clockwork &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#clockwork&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In my opinion, &lt;a href=&quot;https://underground.works/clockwork/&quot;&gt;Clockwork&lt;/a&gt; is the best tool of the &amp;quot;Laravel debug bar&amp;quot; type, as it doesn&#39;t change your HTML output.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; itsgoingd/clockwork&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;larastan&quot; tabindex=&quot;-1&quot;&gt;Larastan &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#larastan&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/larastan/larastan&quot;&gt;Larastan&lt;/a&gt; is an essential static analysis tool for Laravel projects.
With a minimal time investment, you can get a great reporting tool for potential bugs.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; larastan/larastan&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;paratest&quot; tabindex=&quot;-1&quot;&gt;Paratest &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#paratest&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paratestphp/paratest&quot;&gt;Paratest&lt;/a&gt; enables parallel testing for PHPUnit/Pest,
which will make your tests run faster (proportional to the number of cores in your CPU).&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; brianium/paratest&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installation, please check the official Laravel documentation on &lt;a href=&quot;https://laravel.com/docs/master/testing#running-tests-in-parallel&quot;&gt;Running Tests in Parallel&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;composer-dependency-analyser&quot; tabindex=&quot;-1&quot;&gt;Composer Dependency Analyser &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#composer-dependency-analyser&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/shipmonk-rnd/composer-dependency-analyser&quot;&gt;Composer Dependency Analyser&lt;/a&gt; provides fast detection of composer dependency issues such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unused dependencies&lt;/li&gt;
&lt;li&gt;Shadow dependencies&lt;/li&gt;
&lt;li&gt;Misplaced dependencies&lt;/li&gt;
&lt;li&gt;Dev dependency on production code&lt;/li&gt;
&lt;li&gt;Production dependency that is only in dev code&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --dev&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; shipmonk/composer-dependency-analyser&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;set-up-a-ci-cd-pipeline&quot; tabindex=&quot;-1&quot;&gt;Set up a CI/CD Pipeline &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#set-up-a-ci-cd-pipeline&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Set up a CI/CD pipeline with GitHub Actions, GitLab CI, or any other CI/CD service.
I&#39;ve prepared a simple &lt;a href=&quot;https://gist.github.com/alies-dev/4d40a4facee0271ce88bf5d0282e97ea&quot;&gt;Laravel GitHub workflows starting pack&lt;/a&gt;
that includes three workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Main (runs tests, security checks, and deploys)&lt;/li&gt;
&lt;li&gt;Code quality (non-blocking deployment)&lt;/li&gt;
&lt;li&gt;Code style check (non-blocking deployment)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;document-your-project&quot; tabindex=&quot;-1&quot;&gt;Document Your Project &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#document-your-project&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a comprehensive README.md and list all commands needed to run, test, develop, and deploy the project.
Even if you&#39;re the only developer, your future self will thank you for this thorough documentation.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/laravel-first-hour-setup/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since we&#39;re limited to one hour, I&#39;ll conclude here.
These initial steps will set a solid foundation for your development process.
There are many more ways to improve your Laravel project, most of which are project-specific.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>sscanf simplifies your regex</title>
		<link href="https://alies.dev/articles/sscanf/"/>
		<updated>2024-07-04T00:00:00Z</updated>
		<id>https://alies.dev/articles/sscanf/</id>
		<content type="html">&lt;figure class=&quot;sscanf-hero&quot;&gt;
	&lt;div class=&quot;sscanf-hero-input&quot;&gt;
		&lt;span class=&quot;sscanf-hero-label&quot;&gt;input&lt;/span&gt;
		&lt;code&gt;John 25 New York&lt;/code&gt;
	&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;sscanf-hero-ways&quot;&gt;
&lt;div class=&quot;sscanf-hero-way sscanf-hero-way-regex&quot;&gt;
&lt;span class=&quot;sscanf-hero-label&quot;&gt;regex&lt;/span&gt;
&lt;code&gt;preg_match(&#39;/^(&#92;S+) (&#92;d+) (.+)$/&#39;, $s, $m)&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&quot;sscanf-hero-way sscanf-hero-way-scan&quot;&gt;
&lt;span class=&quot;sscanf-hero-label&quot;&gt;sscanf&lt;/span&gt;
&lt;code&gt;sscanf($s, &#39;&lt;b&gt;%s&lt;/b&gt; &lt;b&gt;%d&lt;/b&gt; &lt;b&gt;%s&lt;/b&gt;&#39;, $name, $age, $city)&lt;/code&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;ul class=&quot;sscanf-hero-map&quot;&gt;
&lt;li&gt;&lt;span class=&quot;sscanf-hero-token&quot;&gt;%s&lt;/span&gt; &lt;span class=&quot;sscanf-hero-var&quot;&gt;$name&lt;/span&gt; &lt;span class=&quot;sscanf-hero-val&quot;&gt;&#39;John&#39;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;sscanf-hero-token&quot;&gt;%d&lt;/span&gt; &lt;span class=&quot;sscanf-hero-var&quot;&gt;$age&lt;/span&gt; &lt;span class=&quot;sscanf-hero-val&quot;&gt;25&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;sscanf-hero-token&quot;&gt;%s&lt;/span&gt; &lt;span class=&quot;sscanf-hero-var&quot;&gt;$city&lt;/span&gt; &lt;span class=&quot;sscanf-hero-val&quot;&gt;&#39;New York&#39;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figcaption&gt;Both read the same line. Only one hands back an integer.&lt;/figcaption&gt;&lt;p&gt;&lt;/p&gt;
&lt;/figure&gt;
&lt;style&gt;
	.sscanf-hero {
		margin: 0 0 2em;
		padding: 1.25em;
		border: 1px solid var(--color-border-muted);
		border-radius: 6px;
		font-family: var(--font-family-monospace);
		font-size: 0.75em;
		line-height: 1.5;
	}

	/* Matches the specificity of the global `code:not(.shiki code)` rule,
	   which would otherwise re-apply its chip background inside the hero. */
	.sscanf-hero code:not(.shiki code) {
		font-family: inherit;
		font-size: 1em;
		background: none;
		padding: 0;
		word-break: normal;
		overflow-wrap: anywhere;
	}

	.sscanf-hero-label {
		display: block;
		margin-bottom: 0.35em;
		color: var(--color-meta);
		text-transform: uppercase;
		letter-spacing: 0.08em;
		font-size: 0.85em;
	}

	.sscanf-hero-input {
		padding-bottom: 1em;
		border-bottom: 1px solid var(--color-border-muted);
	}

	.sscanf-hero-ways {
		display: grid;
		gap: 0.9em;
		padding: 1em 0;
	}

	.sscanf-hero-way {
		padding-left: 0.9em;
		border-left: 2px solid var(--color-border-muted);
	}

	/* The regex is the thing being replaced, so it sits back. */
	.sscanf-hero-way-regex code {
		color: var(--color-meta);
	}

	.sscanf-hero-way-scan {
		border-left-color: var(--color-accent);
	}

	.sscanf-hero-way-scan b {
		color: var(--color-accent);
		font-weight: 700;
	}

	.sscanf-hero-map {
		display: grid;
		grid-template-columns: repeat(3, max-content);
		gap: 0.6em 2.5em;
		margin: 0;
		padding: 1em 0 0;
		list-style: none;
		border-top: 1px solid var(--color-border-muted);
	}

	.sscanf-hero-map li {
		line-height: 1.5;
	}

	.sscanf-hero-token {
		color: var(--color-accent);
		font-weight: 700;
	}

	.sscanf-hero-val {
		display: block;
		color: var(--color-meta);
	}

	.sscanf-hero figcaption {
		padding-top: 1em;
		color: var(--color-meta);
	}

	@media (max-width: 32em) {
		.sscanf-hero-map {
			grid-template-columns: 1fr;
			gap: 0.3em;
		}

		.sscanf-hero-val {
			display: inline;
		}
	}
&lt;/style&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.php.net/manual/en/function.sscanf.php&quot;&gt;&lt;code&gt;sscanf&lt;/code&gt;&lt;/a&gt; PHP function offers a powerful alternative to regular expression functions like &lt;code&gt;preg_match&lt;/code&gt; for parsing strings.
While less flexible than regex, &lt;code&gt;sscanf&lt;/code&gt; can be more readable and efficient for simple parsing tasks.&lt;/p&gt;
&lt;p&gt;Surprisingly, &lt;code&gt;sscanf&lt;/code&gt; is a hidden gem in PHP, and many developers are unaware of its existence.
It&#39;s a wrapper around the C library function, and it&#39;s available in PHP since the early days.&lt;/p&gt;
&lt;h2 id=&quot;basic-examples&quot; tabindex=&quot;-1&quot;&gt;Basic examples &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/sscanf/#basic-examples&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Example 1: Basic usage&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$input &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &#39;John 25 New York&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sscanf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($input, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;%s %d %s&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, $name, $age, $city);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example 2: Parsing a date string&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$date &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &#39;2023-07-08&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sscanf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($date, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;%d-%d-%d&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, $year, $month, $day);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example 3: Parsing a complex log entry&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$logEntry &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;2023-07-08 14:30:45 [WARNING] User authentication failed: username=johndoe, ip=192.168.1.100&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$pattern &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;%d-%d-%d %d:%d:%d [%s] %[^:]: username=%[^,], ip=%s&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sscanf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($logEntry, $pattern, $year, $month, $day, $hour, $minute, $second, $level, $message, $username, $ip);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;sscanf-vs-preg-match&quot; tabindex=&quot;-1&quot;&gt;sscanf vs preg_match &lt;a class=&quot;header-anchor&quot; href=&quot;https://alies.dev/articles/sscanf/#sscanf-vs-preg-match&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Parsing a URL example, diff:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark has-diff&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line diff remove&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;preg_match&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;/&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#DBEDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-light-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold&quot;&gt;&#92;S&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#DBEDFF&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-light-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold&quot;&gt;&#92;/&#92;/&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#DBEDFF&quot;&gt;([^&#92;/]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#DBEDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-light-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold&quot;&gt;&#92;/&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#DBEDFF&quot;&gt;(.&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#DBEDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/&#39;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, $url, $matches); &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff remove&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$scheme &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $matches[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff remove&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$domain &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $matches[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff remove&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$path &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $matches[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sscanf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;($url, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;%[^:]://%[^/]/%s&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, $scheme, $domain, $path); &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4 lines vs. 1 line!!
Of course, it’s a simplified example (for real URL parsing, please use &lt;code&gt;parse_url&lt;/code&gt;), but shares the idea.
While &lt;code&gt;sscanf&lt;/code&gt; isn&#39;t a complete replacement for regex, it can simplify many common string parsing tasks in PHP.&lt;/p&gt;
&lt;p&gt;Still need to write a regex?
Check out a great &lt;a href=&quot;https://php.watch/articles/php-regex-readability&quot;&gt;Writing better Regular Expressions in PHP&lt;/a&gt; article.&lt;/p&gt;
</content>
	</entry>
</feed>
