<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Joseph Scott</title>
		<link>https://josephscott.org/</link>
		<description></description>
		<atom:link href="https://josephscott.org/feed.xml" rel="self" type="application/rss+xml" />
		<lastBuildDate>Sun, 13 Sep 2026 01:57:03 +0000</lastBuildDate>
		<item>
			<title>Type Casting and Null Coalescing Precedence in PHP</title>
			<link>https://josephscott.org/blog/2026/09/type-casting-and-null-coalescing-precedence-in-php/</link>
			<guid isPermaLink="true">https://josephscott.org/blog/2026/09/type-casting-and-null-coalescing-precedence-in-php/</guid>
			<pubDate>Wed, 02 Sep 2026 02:09:28 +0000</pubDate>
			<description>Take a quick glance at this PHP code: $stuff = (string) $things ?? &#039;nothing&#039;; var_dump( $stuff ); If this is all the code you have, then $things does not exist,…</description>
			<content:encoded><![CDATA[<p>Take a quick glance at this PHP code:</p>
<pre class="phiki language-php github-dark-default" data-language="php" style="background-color: #0d1117;color: #e6edf3;"><code><span class="line"><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">stuff</span><span class="token"> </span><span class="token" style="color: #ff7b72;">=</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #ff7b72;">string</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">things</span><span class="token"> </span><span class="token" style="color: #ff7b72;">??</span><span class="token"> </span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token" style="color: #a5d6ff;">nothing</span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #79c0ff;">var_dump</span><span class="token">(</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">stuff</span><span class="token"> </span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<p>If this is all the code you have, then <code>$things</code> does not exist, so you expect <code>$stuff</code> to be set to the string <code>nothing</code>. But that is not what happens. The output is <code>string(0) &quot;&quot;</code>. On top of that, it will generate a warning.</p>
<pre class="phiki language-php github-dark-default" data-language="php" style="background-color: #0d1117;color: #e6edf3;"><code><span class="line"><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">stuff</span><span class="token"> </span><span class="token" style="color: #ff7b72;">=</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #ff7b72;">string</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">things</span><span class="token"> </span><span class="token" style="color: #ff7b72;">??</span><span class="token"> </span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token" style="color: #a5d6ff;">nothing</span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #79c0ff;">var_dump</span><span class="token">(</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">stuff</span><span class="token"> </span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token"> 
</span></span><span class="line"><span class="token" style="color: #8b949e;">#</span><span class="token" style="color: #8b949e;"> OUTPUT:</span><span class="token" style="color: #8b949e;">
</span></span><span class="line"><span class="token" style="color: #8b949e;">#</span><span class="token" style="color: #8b949e;"> Warning: Undefined variable $things in ...</span><span class="token" style="color: #8b949e;">
</span></span><span class="line"><span class="token" style="color: #8b949e;">#</span><span class="token" style="color: #8b949e;"> string(0) &quot;&quot;</span><span class="token" style="color: #8b949e;">
</span></span></code></pre>
<p>I did this myself a few times before I realized what was going on. The type casting to a <code>(string)</code> takes precedence over the <a href="https://www.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.coalesce">null coalescing operator</a> ( <code>??</code> ). It is as if you wrote this code:</p>
<pre class="phiki language-php github-dark-default" data-language="php" style="background-color: #0d1117;color: #e6edf3;"><code><span class="line"><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">stuff</span><span class="token"> </span><span class="token" style="color: #ff7b72;">=</span><span class="token"> </span><span class="token">(</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #ff7b72;">string</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">things</span><span class="token"> </span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #ff7b72;">??</span><span class="token"> </span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token" style="color: #a5d6ff;">nothing</span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<p>It turns out that <code>??</code> has very <a href="https://www.php.net/manual/en/language.operators.precedence.php">low precedence in PHP</a>, just above <code>?:</code> ( ternary ). The type casts are at the other end of the table, just below <code>clone</code>, <code>new</code>, and <code>**</code>.</p>
<p>You also end up with <code>?? 'nothing'</code> being dead code. Casting to <code>(string)</code> always gives you back a string; it can never be <code>null</code>. The right side of the <code>??</code> is unreachable no matter what <code>$things</code> holds. Static analysis tools will call this out for you: <a href="https://phpstan.org/">PHPStan</a> <a href="https://phpstan.org/r/889b6484-daa1-4eeb-954d-83ea86a54a5e">reports</a> ( at level 4+ ) <code>Expression on left side of ?? is not nullable</code>.</p>
<p>Normally <code>??</code> takes care of undefined variable warnings, which is part of what makes it so useful. But that only works when the variable is sitting directly to the left of it. Here the cast gets to <code>$things</code> first, and the warning happens right there, before <code>??</code> ever comes into play.</p>
<pre class="phiki language-php github-dark-default" data-language="php" style="background-color: #0d1117;color: #e6edf3;"><code><span class="line"><span class="token" style="color: #79c0ff;">var_dump</span><span class="token">(</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">nope</span><span class="token"> </span><span class="token" style="color: #ff7b72;">??</span><span class="token"> </span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token" style="color: #a5d6ff;">nothing</span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token"> </span><span class="token">)</span><span class="token">;</span><span class="token">          </span><span class="token" style="color: #8b949e;">#</span><span class="token" style="color: #8b949e;"> string(7) &quot;nothing&quot;, no warning</span><span class="token" style="color: #8b949e;">
</span></span><span class="line"><span class="token" style="color: #79c0ff;">var_dump</span><span class="token">(</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #ff7b72;">string</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">nope</span><span class="token"> </span><span class="token" style="color: #ff7b72;">??</span><span class="token"> </span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token" style="color: #a5d6ff;">nothing</span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token"> </span><span class="token">)</span><span class="token">;</span><span class="token"> </span><span class="token" style="color: #8b949e;">#</span><span class="token" style="color: #8b949e;"> Warning: Undefined variable $nope, then string(0) &quot;&quot;</span><span class="token" style="color: #8b949e;">
</span></span></code></pre>
<p>Going back to the original example, to keep both the cast and the null coalescing, wrap the null coalescing in parentheses.</p>
<pre class="phiki language-php github-dark-default" data-language="php" style="background-color: #0d1117;color: #e6edf3;"><code><span class="line"><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">stuff</span><span class="token"> </span><span class="token" style="color: #ff7b72;">=</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #ff7b72;">string</span><span class="token">)</span><span class="token"> </span><span class="token">(</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">things</span><span class="token"> </span><span class="token" style="color: #ff7b72;">??</span><span class="token"> </span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token" style="color: #a5d6ff;">nothing</span><span class="token" style="color: #a5d6ff;">&#039;</span><span class="token"> </span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #79c0ff;">var_dump</span><span class="token">(</span><span class="token"> </span><span class="token" style="color: #e6edf3;">$</span><span class="token" style="color: #e6edf3;">stuff</span><span class="token"> </span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token"> 
</span></span><span class="line"><span class="token" style="color: #8b949e;">#</span><span class="token" style="color: #8b949e;"> OUTPUT:</span><span class="token" style="color: #8b949e;">
</span></span><span class="line"><span class="token" style="color: #8b949e;">#</span><span class="token" style="color: #8b949e;"> string(7) &quot;nothing&quot;</span><span class="token" style="color: #8b949e;">
</span></span></code></pre>
<p>You can see both versions in action at <a href="https://3v4l.org/mInAG">https://3v4l.org/mInAG</a>.</p>
<p>I've seen multiple devs with lots of PHP experience get hit by this recently, so I figured it was worth writing a note about it. The writing process also helps me remember it :)</p>
<p>I think this is one of those things that isn't immediately obvious just glancing at the code, unless you've run into it already.</p>
]]></content:encoded>
		</item>
		<item>
			<title>A Trip to Infinity</title>
			<link>https://josephscott.org/blog/2026/08/a-trip-to-infinity/</link>
			<guid isPermaLink="true">https://josephscott.org/blog/2026/08/a-trip-to-infinity/</guid>
			<pubDate>Thu, 13 Aug 2026 04:04:28 +0000</pubDate>
			<description>Netflix has an interesting show about the concept of infinity: A Trip to Infinity ( 2022 ). Worth it for the Infinite Hotel section alone.</description>
			<content:encoded><![CDATA[<p>Netflix has an interesting show about the concept of infinity:  <a href="https://www.netflix.com/watch/81273453">A Trip to Infinity</a> ( 2022 ).  Worth it for the <a href="https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel">Infinite Hotel</a> section alone.</p>
<div class="youtube-embed" data-youtube-id="CNFm_DzHDaE"><a class="youtube-embed__cover" href="https://www.youtube.com/watch?v=CNFm_DzHDaE" aria-label="Play video"><img src="https://i.ytimg.com/vi/CNFm_DzHDaE/hqdefault.jpg" alt="" loading="lazy"><span class="youtube-embed__play" aria-hidden="true"><svg viewBox="0 0 68 48"><path fill="#f00" d="M66.5 7.7a8.6 8.6 0 0 0-6-6C55.2.5 34 .5 34 .5s-21.2 0-26.5 1.2a8.6 8.6 0 0 0-6 6C.3 13 .3 24 .3 24s0 11 1.2 16.3a8.6 8.6 0 0 0 6 6C12.8 47.5 34 47.5 34 47.5s21.2 0 26.5-1.2a8.6 8.6 0 0 0 6-6C67.7 35 67.7 24 67.7 24s0-11-1.2-16.3z"/><path fill="#fff" d="M27 34l18-10-18-10z"/></svg></span></a></div>

]]></content:encoded>
		</item>
	</channel>
</rss>
