<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="https://riceball.com/wp-content/plugins/pretty-rss-feeds/xslt/pretty-feed.xsl" type="text/xsl" media="screen" ?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PHP - 🍙</title>
	<atom:link href="https://riceball.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>https://riceball.com</link>
	<description></description>
	<lastBuildDate>Sat, 31 Oct 2026 02:29:07 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>

<image>
	<url>https://riceball.com/wp-content/uploads/sites/2/2025/10/onigiri-150x150.png</url>
	<title>PHP - 🍙</title>
	<link>https://riceball.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 5</title>
		<link>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/</link>
					<comments>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 02:24:19 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31271</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" fetchpriority="high" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p><p>Code profiling tools are everything now. When I was staring at Thaura writing code, it was doing some wild tricks with python and grep and other unix tools that I&#8217;d never seen before. So I told it to write tools to do simple kinds of code analysis, to help map out and index the code. [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 5</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Code profiling tools are everything now.</p>



<p class="wp-block-paragraph">When I was staring at Thaura writing code, it was doing some wild tricks with python and grep and other unix tools that I&#8217;d never seen before.</p>



<p class="wp-block-paragraph">So I told it to write tools to do simple kinds of code analysis, to help map out and index the code. I also wrote scoreboard database tools, to keep track of work to do, and work completed. I had it put the code analysis info into the database, too.</p>



<p class="wp-block-paragraph">I also asked it to tell me about all the PHP static analysis tools, and enlisted them all into the programming process: linters, code stylers, static type analysis.</p>



<p class="wp-block-paragraph">The LLM can use these tools the way we use them, to understand the code, and to demonstrate that code conforms to some idea of &#8220;order&#8221;.</p>



<p class="wp-block-paragraph">The LLM also uses them as a kind of debugging aid, or a pre-run tester.</p>



<p class="wp-block-paragraph">I also leaned on Playwright and the old reliable PHPUnit.</p>



<h2 class="wp-block-heading">Illusions of Complete Coverage, and &#8220;AI Psychosis&#8221;</h2>



<p class="wp-block-paragraph">The problem with these code analysis tools is: they don&#8217;t enforce writing good code as much as assist with it. They mainly help when the code is big enough to forget parts of it.</p>



<p class="wp-block-paragraph">They give you the illusion of total control, when you&#8217;re just keeping things together.</p>



<p class="wp-block-paragraph">Likewise, the LLM will appear to be making great, sweeping changes over the code, <em>but touching only a fraction of it</em>, leaving lots of code untouched, and <em>report back with a chat message that it did a lot of work</em>.</p>



<p class="wp-block-paragraph"><strong>The LLM straight up bullshitted the boss!</strong></p>



<p class="wp-block-paragraph">I totally fell for it.</p>



<p class="wp-block-paragraph">The problems would trigger errors and warnings, and then the LLM would look at the errant code, and go fix it, with some chatter about how <strong>it was still doing the old thing</strong>, when it should be doing the <strong>new thing</strong>.</p>



<p class="wp-block-paragraph">Then it was fixed, passed the test, looks good in the analysis tools, and the LLM moved on, and I moved on.</p><p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 5</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 4</title>
		<link>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/</link>
					<comments>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 00:31:01 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31246</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p><p>Continuing the series, more info about altering project internals. I think of this like a caterpillar going into a cocoon, having enzymes totally disintegrate its guts, and then produce a butterfly, which will go out and mate with other butterfiles. It&#8217;s a metamorphosis. Except, with this software, you don&#8217;t see any visible changes once it&#8217;s [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 4</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Continuing <a href="https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/">the series</a>, more info about altering project internals.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">I think of this like a caterpillar going into a cocoon, having enzymes totally disintegrate its guts, and then produce a butterfly, which will go out and mate with other butterfiles. It&#8217;s a metamorphosis. Except, with this software, you don&#8217;t see any visible changes once it&#8217;s changed.</p>



<p class="wp-block-paragraph">So that&#8217;s not a good analogy.</p>



<p class="wp-block-paragraph">Maybe it&#8217;s more like an electric car, which looks as ugly as the gasoline cars, or even worse, but has completely different insides. It&#8217;s better on the inside.</p>



<p class="wp-block-paragraph">Another bad analogy.</p>



<p class="wp-block-paragraph">It&#8217;s like you shoved a seed into a pile of manure, and it&#8217;s started to grow, but you still can&#8217;t see the plant. It just looks like a pile of shit. But there&#8217;s good stuff in there.</p>



<p class="wp-block-paragraph">Yes, that&#8217;s it.</p>
</blockquote>



<p class="wp-block-paragraph">I&#8217;m going to do another release of software.</p>



<p class="wp-block-paragraph">I&#8217;ll just call it r2 or release 2&#8230;.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Here&#8217;s what happened. It took all day. The reasons were noted in the email I sent out, but the actual delays were as follows:</p>



<p class="wp-block-paragraph">The instructions that the LLM wrote were not easy to understand. In retrospect, I should have just hand-written them.</p>



<p class="wp-block-paragraph">(Then, those notes could have become part of the LLMs knowledge, and could have influenced it to write better documents.)</p>



<p class="wp-block-paragraph">Cloning the database was smooth, but getting the live database container updated to a newer version of MariaDB took extra time.</p>



<p class="wp-block-paragraph">Cloning the release from Git was quick. Moving it into place was quick. (Name the new clone directory blahblah.new, then mv blahblah to blahbla.old, then mv blahblah.new blahblah. Restart Nginx, restart the php container.)</p>



<p class="wp-block-paragraph"><strong>Configuring the Nginx proxy took a LOT of effort, because I did it too soon. The examples the LLM created were wrong, as well, but had enough info that I could make it work</strong>.</p>



<p class="wp-block-paragraph">Reconfiguring the containers to run the app was pretty simple, but I had forgotten that I changed the paths where I wanted the files mounted. This sent me down some rabbitholes related to Nginx config. (I should have held back on changing Nginx.)</p>



<p class="wp-block-paragraph">Overall, it wasn&#8217;t that bad, except for the Nginx configuration.</p>



<h3 class="wp-block-heading">A New, Nonfunctional API</h3>



<p class="wp-block-paragraph">I made an API to feed the mobile app, and it didn&#8217;t work. Digging into the code, was a minor horror. The LLM wrote code well, but the overall &#8220;separation of concerns&#8221; and keeping the code in the right places, wasn&#8217;t so great.</p>



<p class="wp-block-paragraph">I forget what the fix was, but it eventually worked. It was a combination of fixing some obsolete SQL code, and making an Nginx config.</p>



<h2 class="wp-block-heading">PHP Attack Scripts</h2>



<p class="wp-block-paragraph">The PHP security hole drama has led to a bit more attack against the sites, particularly <a href="https://riceball.com/2026/10/29/hackscripts-patterns/">scans for remote shells written in PHP</a>.</p>



<p class="wp-block-paragraph">That just overloads the server, even when the scripts aren&#8217;t there.</p>



<p class="wp-block-paragraph">So I had to do some tricks to detect these requests, and block them. This took a few hours.</p>



<h3 class="wp-block-heading">Get Rid of phpinfo()</h3>



<p class="wp-block-paragraph">If  you&#8217;re running PHP in a container, and use .env to pass passwords into your container, it&#8217;s critical to find and remove all instances of scripts that use the phpinfo() function.</p>



<p class="wp-block-paragraph">That function dumps the environment variables to the page, leaking credentials. This command will recursively find the string &#8220;phpinfo&#8221; in all your files.</p>


<pre class="wp-block-code"><span><code class="hljs">grep -r phpinfo *</code></span></pre>


<h2 class="wp-block-heading">Archives</h2>



<p class="wp-block-paragraph">One of my big goals was to get the site into shape for archving. This entails being able to easily download the entire site, using tools like wget.</p>



<p class="wp-block-paragraph">Generating HTML files as final output is one step toward this goal. While archivers handle .php file endings, they like .html more, and with .html, you can view archives with a plain web browser.</p>



<p class="wp-block-paragraph">With .html files, you can &#8220;archive&#8221; by copying over all the files. You won&#8217;t need all this software to operate the archived site.</p>



<h3 class="wp-block-heading">Indexes</h3>



<p class="wp-block-paragraph">Generating complete indexes to the news articles and events allows webcrawlers to get at everything.</p>



<p class="wp-block-paragraph">This is also a risk, because lots of bots are out there scraping the site, and a complete index will potentially increase their downloading, and risk overloading the site.</p>



<p class="wp-block-paragraph">Page generation helps with this, because serving up a generated HTML page takes a tiny fraction of the resources of running a PHP file. (Example: on an older computer, a very heavy site like WordPress can top out at 30 requests per second, while a similar HTML site can reach into the 10k requests per second.)</p>



<p class="wp-block-paragraph">Bots I&#8217;ve seen scraping the site: Google, Bing, Claude, Baidu, OpenAI, Ahrefs, Yandex.</p>



<h3 class="wp-block-heading">Twig Templates</h3>



<p class="wp-block-paragraph">To this end, instead of trying to change the page generation within the existing code, I had the LLM add Twig. It seemed to know more about Twig than Blade, so I went with Twig.</p>



<p class="wp-block-paragraph">The LLM set up a parallel template structure that copied parts of the existing templates, and then ported the entire site to use it, but didn&#8217;t actually remove all of it, because some of the templates we had were full of PHP code.</p>



<p class="wp-block-paragraph">The Twig templates mixed with the old template system are a mess; they&#8217;re completely enmeshed, to replicate the old site. </p>



<p class="wp-block-paragraph">Eventually, almost the entire site will be generated with Twig.</p>



<p class="wp-block-paragraph">Eventually, this will be replaced with new layouts that aren&#8217;t mixed with the old code.</p>



<p class="wp-block-paragraph">I suspect I&#8217;m going to need to start the process by hand, writing my own templates.</p>



<h3 class="wp-block-heading">Order and Memory Capacity</h3>



<p class="wp-block-paragraph">This did get me thinking about the issue of why we think some code is well organized, and some code is not.</p>



<p class="wp-block-paragraph">Part of it is our limited capacity to comprehend large, complicated systems.</p>



<p class="wp-block-paragraph">To handle big systems, we use structures, like lists, hierarchies, &#8220;black boxing&#8221;, making things modular, and using repetitive patterns.</p>



<p class="wp-block-paragraph">The LLM, unlike people, has a different kind of &#8220;memory&#8221; or &#8220;attention&#8221; or capacity to deal with large amounts of information. So, while the code looks like a mess to me, it still makes sense to the LLM.</p>



<p class="wp-block-paragraph">Here&#8217;s some computer code that vibe coding produced:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#F8F8F2;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>function rotated(p){ // rotate cells 90deg clockwise, re-normalize to 0
  const maxX = Math.max(...p.cells.map(c=>c.x));
  const cells = p.cells.map(c=>({x:c.y, y:maxX-c.x, ch:c.ch}));
  const minX = Math.min(...cells.map(c=>c.x)), minY = Math.min(...cells.map(c=>c.y));
  return cells.map(c=>({x:c.x-minX, y:c.y-minY, ch:c.ch}));
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">rotated</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">p</span><span style="color: #F8F8F2">){ </span><span style="color: #6272A4">// rotate cells 90deg clockwise, re-normalize to 0</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> maxX </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Math.</span><span style="color: #50FA7B">max</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">...</span><span style="color: #F8F8F2">p.cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">c.x));</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> cells </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> p.cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">({x</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.y, y</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">maxX</span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2">c.x, ch</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.ch}));</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> minX </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Math.</span><span style="color: #50FA7B">min</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">...</span><span style="color: #F8F8F2">cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">c.x)), minY </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Math.</span><span style="color: #50FA7B">min</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">...</span><span style="color: #F8F8F2">cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">c.y));</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">return</span><span style="color: #F8F8F2"> cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">({x</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.x</span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2">minX, y</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.y</span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2">minY, ch</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.ch}));</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Almost any programmer has written code like that, but how many enjoy <em>reading</em> code like that.</p>



<p class="wp-block-paragraph">Conversely, computer code is extremely brittle. A single character out of place, and parts may break. The LLM can write code, but more importantly, it can transform vague instructions and turn them into concrete goals, like people can. So it&#8217;s like a programming language that&#8217;s a human language.</p>



<p class="wp-block-paragraph">The challenge is to get the LLM to conform to (the declining) human need to keep code organized, for human comprehension.</p><p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 4</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 3</title>
		<link>https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/</link>
					<comments>https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 28 Oct 2026 04:12:07 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31239</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p>Continuing the series, more info about altering project internals. I got so tired that I stopped blogging. A note to myself read: The main big issues I&#8217;ve hit this time are refactoring introducing bugs bug repairs introducing bugs incomplete testing of outputs database export and import problems. Refactoring Introducing Bugs Initially, I wasn&#8217;t that aggressive [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 3</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Continuing <a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">the series</a>, more info about altering project internals.</p>



<p class="wp-block-paragraph">I got so tired that I stopped blogging. A note to myself read:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">The main big issues I&#8217;ve hit this time are refactoring introducing bugs bug repairs introducing bugs incomplete testing of outputs database export and import problems.</p>
</blockquote>



<h2 class="wp-block-heading">Refactoring Introducing Bugs</h2>



<p class="wp-block-paragraph">Initially, I wasn&#8217;t that aggressive about testing. I just used URLs and GET to test a list of pages, and told the bot to read the logs. It would find errors and warnings, and fix them.</p>



<p class="wp-block-paragraph">Then, I got hit with a bunch of uncaught bugs.</p>



<p class="wp-block-paragraph">One of them was a bug that I knew we corrected before.</p>



<p class="wp-block-paragraph">So I decided that whenever I found a bug, I wanted a test generated that would prevent that bug from reappearing.</p>



<p class="wp-block-paragraph">I&#8217;m guessing that a bug reappeared because the code was being <a href="https://en.wikipedia.org/wiki/Code_refactoring" target="_blank" rel="noopener">refactored</a>.</p>



<p class="wp-block-paragraph">Refactoring is basically building a new code structure, and then copying your old code into it. When it copied the code, it wrote the bug back into existence.</p>



<h2 class="wp-block-heading">Bug Fixing Revealing Bugs or Introducing Bugs</h2>



<p class="wp-block-paragraph">This isn&#8217;t an LLM issue per-se, but in dynamic languages, fixing a bug might reveal other bugs that, until then, were not found, because the first bug killed the program.</p>



<p class="wp-block-paragraph">An automated test case helps with these.</p>



<h2 class="wp-block-heading">Incomplete Testing of Outputs</h2>



<p class="wp-block-paragraph">I wish I could remember the situation, but Thaura did a big batch of changes, but it wasn&#8217;t testing the output. It just did the modifications.</p>



<p class="wp-block-paragraph">Some early modifications had automated tests, and it used those to fine tune it&#8217;s behavior, but then, it just abandoned testing.</p>



<p class="wp-block-paragraph">It seemed to be working so fast, so I asked if it was checking outputs. It wasn&#8217;t.</p>



<p class="wp-block-paragraph">So, it&#8217;s good to ask the bot what it did. You can read it, and determine if the bot failed to do something. You can find tune its behavior.</p>



<h2 class="wp-block-heading">Database Import and Export Problems</h2>



<p class="wp-block-paragraph">Initially, I tried to do <strong>a mysqldump from MySQL 5.7 and load it into MariaDB 11</strong>. It didn&#8217;t work, but I expected that. Not only that, but the data needed a lot of manual cleanup.</p>



<p class="wp-block-paragraph">So I used an intermediate format, JSON, to dump the data, and load it in. That worked extremely well.</p>



<p class="wp-block-paragraph">Then, I thought I could dump from the dev database and load it into the production database, like this:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="342" height="509" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-01-14.png?wsr" alt="" class="wp-image-31242" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-01-14.png 342w, https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-01-14-202x300.png 202w" sizes="auto, (max-width: 342px) 100vw, 342px" /></figure>



<p class="wp-block-paragraph">No such luck. </p>



<p class="wp-block-paragraph">They were both MariaDB 11, and the same point version, but different releases, and in slightly different operating systems (Alpine Linux vs. whatever MariaDB&#8217;s Docker package uses).</p>



<p class="wp-block-paragraph">So I had Thaura write a filter to allow the dump to work, mainly by stripping some comments, like this:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="386" height="647" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-04-59.png?wsr" alt="" class="wp-image-31243" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-04-59.png 386w, https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-04-59-179x300.png 179w" sizes="auto, (max-width: 386px) 100vw, 386px" /></figure>



<p class="wp-block-paragraph">(Claude screwed up the diagram. The first dump is a MySQL dump.)</p>



<p class="wp-block-paragraph">Obviously, I should have focused on defining an intermediate data dump format that would work for us.</p>



<p class="wp-block-paragraph">This isn&#8217;t a PHP porting issue, but it could come up.</p><p>The post <a href="https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 3</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 2</title>
		<link>https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/</link>
					<comments>https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 24 Oct 2026 03:39:22 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31223</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p>Last time it was about updating code. Now it&#8217;s about altering project internals. Mid-Project Legacy A long time ago, I decided that the old style include(&#8216;foo_class.inc&#8217;) was annoying, and the new style autoloader classes with use \Foo; were nicer. So I did a simple thing: copy them all into a namespace, and then convert them [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 2</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Last time it was about <a href="https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/">updating code</a>. Now it&#8217;s about altering project internals.</p>



<h2 class="wp-block-heading">Mid-Project Legacy</h2>



<p class="wp-block-paragraph">A long time ago, I decided that the old style include(&#8216;foo_class.inc&#8217;) was annoying, and the new style autoloader classes with use \Foo; were nicer.</p>



<p class="wp-block-paragraph">So I did a simple thing: copy them all into a namespace, and then convert them to PSR-4 compatible classes (aka, autoloading classes).</p>



<p class="wp-block-paragraph">I left the old files around, just in case they were still being used. The project never completed, and maybe around 10 classes were converted, and many were not.</p>



<p class="wp-block-paragraph">I told the LLM to fix this, and make everything into a PSR-4 compatible class. It decided which version was good, and which was not and possible merges.</p>



<p class="wp-block-paragraph">This is mind-blowing to me, that the program can do this.</p>



<p class="wp-block-paragraph">The process took a day, due to pauses and usage limits, and I&#8217;m still not sure it&#8217;s OK.</p>



<p class="wp-block-paragraph">The goal here was to allow static code checking tools like Psalm to do better code analysis.</p>



<h3 class="wp-block-heading">So far, no real new code</h3>



<p class="wp-block-paragraph">I&#8217;m just writing this to make a weird point: I haven&#8217;t asked the LLM to write new code. It&#8217;s refactoring.</p>



<p class="wp-block-paragraph">It&#8217;s making old code conform to newer programming standards.</p>



<p class="wp-block-paragraph">It&#8217;s removing code, too.</p>



<h3 class="wp-block-heading">Some Removals</h3>



<p class="wp-block-paragraph"><strong>Reporting bad posts</strong> &#8211; a system similar to Digg, where the community can moderate. It stopped being useful when people gamed it or it didn&#8217;t instantly mod someone down.</p>



<p class="wp-block-paragraph"><strong>Spam trapping</strong> &#8211; I had a bunch of filters, some quite nice, but it was out of date.</p>



<p class="wp-block-paragraph"><strong>IP logging and redirecting</strong> &#8211; this is still important, but the site&#8217;s implementation was pretty annoying, so it goes.</p>



<p class="wp-block-paragraph"><strong>DIY captcha</strong> &#8211; I wrote it because there weren&#8217;t many options I liked. Now, it&#8217;s not that relevant because there are packages for captchas.</p>



<p class="wp-block-paragraph"><strong>Themes</strong> &#8211; again, not super popular, and it was done in a annoying way, with GET parameters.</p>



<p class="wp-block-paragraph">These removals aren&#8217;t all because the feature was bad, but it was just out of date, or should be replaced. Removing them helped reduce the code size.</p>



<h2 class="wp-block-heading">Improving Debugging</h2>



<p class="wp-block-paragraph">After telling Thaura to do something a certain way, over and over, it starts to do it, automatically, and even expand on it.</p>



<p class="wp-block-paragraph">I told it to use the static analysis and dependency databases a couple times, and it figured out how to use them.</p>



<p class="wp-block-paragraph">I told it to always do static analysis and check dependencies, and it would do both, with the tools, and on its own.</p>



<p class="wp-block-paragraph">So every change is checked with these tools, and also with the Playwright integration tests against some URLs. These can trigger warnings in the logs, so I have it read the logs and debug error and warning messages.</p><p>The post <a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 2</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 1</title>
		<link>https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/</link>
					<comments>https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 22:21:35 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31203</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p>This document describes how I&#8217;m porting a legacy PHP codebase to PHP8.5. The security crisis of October 2026 required porting everything on a legacy website to PHP8, the only version that&#8217;s getting updated now. This document is in flux and will change as the port progresses. The legacy code was running on two containers, behind [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 1</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">This document describes how I&#8217;m porting a legacy PHP codebase to PHP8.5. The security crisis of October 2026 required porting everything on a legacy website to PHP8, the only version that&#8217;s getting updated now. This document is in flux and will change as the port progresses.</p>



<p class="wp-block-paragraph">The legacy code was running on two containers, behind a nginx reverse proxy, that directed most of the traffic to he PHP7 version of the code, but ran some very old code in PHP5.</p>



<p class="wp-block-paragraph">The goal was to port code to PHP8, and implement a new app stack that&#8217;s nginx + php-fpm + php8.5.</p>



<p class="wp-block-paragraph">The TL;DR:</p>



<ul class="wp-block-list">
<li>Lean on code linters first.</li>



<li>Create infrastructure to organize the process of fixing individual files, to get them to compile. Don&#8217;t bother to fix the logic at this time.</li>



<li>Tell the LLM to log changes.</li>



<li>Build up the new codebase from the old (the LLM made this decision), linting the old PHP7 code mostly.</li>



<li>Build up the new deployment environment by using the old config files.</li>
</ul>



<p class="wp-block-paragraph">The general progression of the work:</p>



<ol class="wp-block-list">
<li>Download all the old code into a project.
<ol class="wp-block-list">
<li>Make a git repo, and add lines to README to use it. (Helps the LLM undo things and see history.)</li>



<li>Include relevant config files. (Teaches context. LLM should know all the parts, rather than assume anything.)</li>



<li>Create careful database dumps, by table rather than the entire db. I had an old archiving tool for this, and used it. Download into repo.</li>



<li>Write notes about the current architecture, project folder layout, db version.</li>



<li>Tell the LLM to log changes to a changelog.</li>
</ol>
</li>



<li>Update the code so it compiles.
<ol class="wp-block-list">
<li>Use static code linters, stylers, deprecated code scanners, etc. to test the code. (Do not rely on the LLM&#8217;s reasoning. Ask it to recommend tools, and install them. Then, you need to configure them to work with your file layout, include paths, etc.)</li>



<li>Let the LLM plan and make the code changes.</li>



<li>Let the LLM guess about which files, and which versions, would need to be ported.</li>



<li>The LLM had trouble running a batch script to do the tool calls, so I told it to make another batcher script to run the script over around 20 files. The LLM tells me to run it when it&#8217;s changed.</li>



<li>Made mid-project decision to use a SQLite scoreboard to track the state of each file. Updated scripts to update the scoreboard. This makes the batching partially obsolete.</li>
</ol>
</li>



<li>Make a Docker dev environment similar to the deployment goal. Use this to do the runtime integration tests.
<ol class="wp-block-list">
<li>Playwright for integration testing.</li>



<li>PHPUnit or similar for unit or function testing.</li>
</ol>
</li>
</ol>



<h2 class="wp-block-heading">The llm</h2>



<p class="wp-block-paragraph">I&#8217;m using Thaura Pro. The pro is that it&#8217;s pretty cheap at $15 a month. The problem is that you can use it only 5 hours at a time, and then you have to take a break. I really don&#8217;t mind this.</p>



<p class="wp-block-paragraph">The tool execution limit will trigger every 15 minutes or so, and require a button click.</p>



<h2 class="wp-block-heading">Static Checkers</h2>



<p class="wp-block-paragraph">Linters and static code checkers run on the desktop computer to produce reports about code problems. <strong>These help you analyze lots of code without burning tokens (or dealing with the indeterminacy of LLMs</strong>).</p>



<p class="wp-block-paragraph">The LLM should write the config files for these tools, so it can adjust them as it runs.</p>



<p class="wp-block-paragraph">I started with report text files, and a batch file to produce them, but eventually added a sqlite based scoreboard to track work progress. The linting can happen in parallel with the LLM coding.</p>



<p class="wp-block-paragraph">Coding is &#8220;slow&#8221;, at maybe 1 minute per file. That&#8217;s many multiples of how fast I code, but there is still some waiting. The LLM works in batches of 5-10 files.</p>



<p class="wp-block-paragraph">A batch checker script, over time, became a kind of scratchpad for the next 10 to 20 files to test. Due to a security issue, I had to run this manually.</p>



<p class="wp-block-paragraph">What&#8217;s nice about the scoreboard and the report.txt sidecars is that I can work in parallel with the LLM. I just write tools (by hand, or by LLM), use other LLMs to set up Docker, edit the README and other notes.</p>



<p class="wp-block-paragraph">Even this static analysis phase is full of constant changes and improvements.</p>



<h2 class="wp-block-heading">The Port Environment</h2>



<p class="wp-block-paragraph">The initial environment is a directory that looks like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">src/
     db/ -- legacy data
     apache/ -- legacy config
     nginx/ -- legacy config
     php5/ -- legacy code
     php7/ -- legacy code
     php8/ -- ported code, goes into git repo
         sitename/ -- not the actual sitename
             local/ -- caches and local code
             public/ -- website root
             shared/ -- project-wide code libraries
bin/ -- scripts and tools to help <span class="hljs-keyword">with</span> coding, goes <span class="hljs-keyword">in</span> repo
docker/ -- configs and tools <span class="hljs-keyword">for</span> docker containers, goes <span class="hljs-keyword">in</span> repo
legacy-data/ -- not the actual name, but things like generated files, temp files, uploads, were downloaded into here, <span class="hljs-keyword">as</span> samples. The entire site was not copied.
</code></span></pre>


<p class="wp-block-paragraph">The main tools (at thist time) are syntax checkers, linters, like &#8216;php -l&#8217;, phpstan, psalm, phpcs. Helper scripts run the tools, load configs, query the scoreboard, etc.</p>



<p class="wp-block-paragraph">Thaura can also run these tools individually.</p>



<p class="wp-block-paragraph">Changes are logged in these places: CHANGELOG.txt, somescript.php.report.txt sidecars that record the output of the syntax checkers (so the LLM doesn&#8217;t need to run them individually), the git commits, and I write some changes into README.txt and then tell Thaura to read it. I think Thara also keeps a todo file on its server.</p>



<p class="wp-block-paragraph">Legacy configs help a lot, explaining how the actual live app works. Porting proceeds breadth-first, and based on what&#8217;s exposed through these configs, particularly the nginx reverse proxy, which forwards traffic to two different PHP containers, depending on the URI.</p>



<p class="wp-block-paragraph">The new config is much simpler, because it&#8217;s a single codebase. The old configs help the port avoid porting stray PHP files here and there, by identifying what is exposed to the world.</p>



<p class="wp-block-paragraph">Early on, the LLM is just guessing which files are dependencies. This will come out in the wash and rinse as the code is executed.</p>



<h2 class="wp-block-heading">Code Fixing</h2>



<p class="wp-block-paragraph">The first goal was to get all the code compiling. I didn&#8217;t care if it had some warnings, and <strong>I didn&#8217;t care if it even ran correctly</strong>.</p>



<p class="wp-block-paragraph">This took over a day, but eventually finished.</p>



<p class="wp-block-paragraph">Initially, I thought the next step would be to write tests, like TDD, but, instead, the LLM was going into actual debugging, so I went along.</p>



<p class="wp-block-paragraph">This is almost like the opposite of TDD, and more like interactive programming with an interpreter.</p>



<p class="wp-block-paragraph">I&#8217;d give it a URL, and tell it to fix it, by figuring out which files get loaded, and checking the work from the URL down to the libraries. It required checking dependencies.</p>



<h3 class="wp-block-heading">Tests</h3>



<p class="wp-block-paragraph">So I did around 10 or 15 of these debugging excursions, and it got better at it over time.</p>



<p class="wp-block-paragraph">Next, I told it to create Playwright tests for a bunch of the URLs, and some new ones.</p>



<p class="wp-block-paragraph">More on this later.</p>



<h2 class="wp-block-heading">Database Tables</h2>



<p class="wp-block-paragraph">During debugging, it would sometimes hit missing database tables. This could cause the LLM to go on a pointless debugging excursion, or try to recreate the table.</p>



<p class="wp-block-paragraph">I&#8217;d have to stop it, ssh into the server, alter the table dumping script, exit ssh, and then do an rsync to copy the new table dumps.</p>



<p class="wp-block-paragraph">The LLM created a couple utilities to upload the tables into the local DB.</p>



<h3 class="wp-block-heading">MySQL 5.7 to MariaDB Migration</h3>



<p class="wp-block-paragraph">Initially, I thought it would work to use the db dumps to load MariaDB. It seemed like some python scripts could fix them up, since they use roughly the same SQL.</p>



<p class="wp-block-paragraph">I hadn&#8217;t thought about the long term nightmare of migrating from latin1 to utf8, which the site underwent over many years. By and large, the data was ASCII or UTF-8, but many columns were typed as latin1.</p>



<p class="wp-block-paragraph">So, instead, the LLM offered to fix some of the bad data, and I asked for tools to dump the data to JSON, and load the data from JSON.</p>



<p class="wp-block-paragraph">The new tables and columns will, eventually, be utf8mb4, or whatever is best for the near future.</p>



<p class="wp-block-paragraph">The data repair was pretty amazing. It didn&#8217;t just fix our internal migration mistakes &#8211; it also fixed dirty user input.</p>



<p class="wp-block-paragraph">I could tell it had the accumulated experience of decades of annoyances people had when migrating to Unicode and UTF8.</p>



<h2 class="wp-block-heading">Testing URLs</h2>



<p class="wp-block-paragraph">The LLM seemed to be really good at figuring out how a URL maps to a PHP file, and all the PHP files that get involved in producing that URL.</p>



<p class="wp-block-paragraph">I also taught it how to go into the /admin/ area, with a username and password, and run the page generation code.</p>



<p class="wp-block-paragraph">The code wasn&#8217;t really working, so during this &#8220;training&#8221;, it was also looking at the code and fixing it until it worked. Mostly, it was configuration issues.</p>



<p class="wp-block-paragraph">So, now, I could tell it to fix something that involved page generation, and it could &#8220;drive&#8221; the site to regenerate the page during its debugging.</p>



<p class="wp-block-paragraph">I settled into using this prompt pattern:</p>


<pre class="wp-block-code"><span><code class="hljs">/path/to/url.php -- this page does this, but it's not doing it correctly. Debug it.
</code></span></pre>


<p class="wp-block-paragraph">I repeated this for all the parts of the admin, including the parts I was hoping to remove.</p>



<p class="wp-block-paragraph">Then I repeated it for world-facing pages.</p>



<p class="wp-block-paragraph">I didn&#8217;t test if the site could upload files, etc. When I was creating the Playwright tests, it went ahead and wrote tests to do some of that.</p>



<p class="wp-block-paragraph">So, with this interactive debugging, I suspect I primed the LLM to know how to make the Playwright tests.</p>



<h2 class="wp-block-heading">Simplification by Replacing Variables with Constants</h2>



<p class="wp-block-paragraph">The site had two config files, and many of the configs were global variables.</p>



<p class="wp-block-paragraph">Most of these were used like constants. They never changed.</p>



<p class="wp-block-paragraph">So I told two LLMS to go, one by one, and replace the variable with a constant, if the variable wasn&#8217;t ever assigned a value elsewhere in the code.</p>



<p class="wp-block-paragraph">Every variable is a potential decision point: an if statement, or switch statement, or concatenation in a string that&#8217;s a file path, etc.</p>



<p class="wp-block-paragraph">Replacing variables with constants, when possible, should make debugging easier.</p>



<p class="wp-block-paragraph">To test it, I used the big test suite in playwright, and told the LLM to run each test individually, and read the logs, fixing any errors or warnings.</p>



<h2 class="wp-block-heading">Enabling Xdebug</h2>



<p class="wp-block-paragraph">I should have done this from the start, but better late than never. I had it produce dumps about what functions got called, and it also allows the LLM to do debugging.</p>



<h2 class="wp-block-heading">Scoreboards and Dependencies</h2>



<p class="wp-block-paragraph">I had it create a scoreboard system to see how the code porting and conversion were progressing &#8212; the pass/fail status was determined by running static checkers on the code.</p>



<p class="wp-block-paragraph">Then I created commands to query the scoreboard.</p>



<p class="wp-block-paragraph">It eventually seemed to use it a little bit. I think doing the scoreboard from the start, could have helped, but, if anything, I got more use out of it than the LLM.</p>



<p class="wp-block-paragraph">I also had it create a database of dependencies, of what files get included (and what files include a given file).</p>



<p class="wp-block-paragraph">Tools for OOP in PHP will produce this info, but this codebase is mostly PHP4 style require() and include() based.</p>



<p class="wp-block-paragraph">Again, I don&#8217;t know if the LLM used it, but it would have helped debugging go faster.</p>



<p class="wp-block-paragraph">This is all debugging infrastructure, ultimately, and it&#8217;s good not only for the LLM but for the programmer as well.</p>



<h2 class="wp-block-heading">Removing Features</h2>



<p class="wp-block-paragraph">The old software had a bunch of features that nobody seems to use anymore.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#F8F8F2;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>going forward, i want to do a commit before, and a dev release after, a site feature is removed, so it's easy to go back and undo a bad batch of work. for example, for this round, I'd like to remove code related to themes, theme.php and anything related to it, like CSS files, any gui related to the theme, and logic to switch the theme. Only the default theme should be left. analyze the code, plan the removal, and then remove, and test. then, remove any playwright tests for themes. when it's all good, do a dev release.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F8F8F2">going forward, i want to do a commit before, and a dev release after, a site feature is removed, so it&#39;s easy to go back and undo a bad batch of work. for example, for this round, I&#39;d like to remove code related to themes, theme.php and anything related to it, like CSS files, any gui related to the theme, and logic to switch the theme. Only the default theme should be left. analyze the code, plan the removal, and then remove, and test. then, remove any playwright tests for themes. when it&#39;s all good, do a dev release.</span></span></code></pre></div>



<p class="wp-block-paragraph">I know the codebase pretty well, so I knew this was a pretty simple change.</p>



<p class="wp-block-paragraph">Removing features removes files, and removing files reduces the amount of context required to edit the code.</p>



<p class="wp-block-paragraph">Code that would use the theme variable was also rewritten to simply use the default theme.</p>



<p class="wp-block-paragraph">(My plan is to re-add features by using external libraries when appropriate.)</p>



<p class="wp-block-paragraph"><a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">Continued in part 2</a>.</p><p>The post <a href="https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 1</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP Traits</title>
		<link>https://riceball.com/2026/10/12/php-traits/</link>
					<comments>https://riceball.com/2026/10/12/php-traits/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 13 Oct 2026 02:27:58 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31041</guid>

					<description><![CDATA[<p>Just read this. Nice take: https://generalistprogrammer.com/tutorials/php-traits-complete-guide Thinking out loud&#8230; tell me if I&#8217;m wrong. I&#8217;m mulling the idea of using Traits to compose static classes with no state. The static class would act as a Facade. It could implement an Interface. The static class would be paired with a state object, which could contain all [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/12/php-traits/">PHP Traits</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Just read this. Nice take:</p>



<p class="wp-block-paragraph"><a href="https://generalistprogrammer.com/tutorials/php-traits-complete-guide">https://generalistprogrammer.com/tutorials/php-traits-complete-guide</a></p>



<h3 class="wp-block-heading">Thinking out loud&#8230; tell me if I&#8217;m wrong.</h3>



<p class="wp-block-paragraph">I&#8217;m mulling the idea of using Traits to compose static classes with no state.</p>



<p class="wp-block-paragraph">The static class would act as a Facade. It could implement an Interface.</p>



<p class="wp-block-paragraph">The static class would be paired with a state object, which could contain all the state. This pairing would allow a clean separation of data from algorithms.</p>



<p class="wp-block-paragraph">The Traits would contain no state. State, or portions of state, are passed in as parameters to methods.</p>



<p class="wp-block-paragraph">Maybe it would be possible to create no-state objects, to allow for class-based dispatch (a kind of polymorphism).</p>



<h3 class="wp-block-heading">Notebooking</h3>



<p class="wp-block-paragraph">This is the first draft. It worked, but it it <strong>useful</strong>?</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#F8F8F2;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;?php

interface AnimalInterface {
    static function sayHello(Animal $a);
    static function doPoo(Animal $a);
    static function doEat(Animal $a);
}

class Animal implements AnimalInterface {
  use Speak;
  use Poop;
  use Eat;
}

trait Speak {
    static function sayHello(Animal $a) 
    {
        echo 'Says: ' . $a->speech . "\n";
    }
}

trait Poop {
    static function doPoo(Animal $a)
    {
        echo 'Defecates: ' . $a->defecate . "\n";
    }
}

trait Eat {
    static function doEat(Animal $a)
    {
        echo 'Eats: ' . $a->food . "\n";
    }
}

class AnimalState {
    public $state = [];

    function init() 
    {
        $this->state&#91;'dog'&#93; = new Dog();
        $this->state&#91;'cat'&#93; = new Cat();
        $this->state&#91;'bird'&#93; = new Bird();
    }
}

class Dog extends Animal {
    public readonly string $speech;
    public readonly string $defecate;
    public readonly string $food;
    public readonly int $age;

    function __construct($age = 1) 
    {
        $this->speech = 'woof';
        $this->defecate = 'dog loaf';
        $this->food = 'kibble';
        $this->age = $age;
    }
}

class Cat extends Animal {
    public readonly string $speech;
    public readonly string $defecate;
    public readonly string $food;
    public readonly int $age;

    function __construct($age = 1) 
    {
        $this->speech = 'mew';
        $this->defecate = 'hairpoo';
        $this->food = 'tuna';
        $this->age = $age;
    }
}

class Bird extends Animal {
    public readonly string $speech;
    public readonly string $defecate;
    public readonly string $food;
    public readonly int $age;

    function __construct($age = 1) 
    {
        $this->speech = 'chirp';
        $this->defecate = 'birdstool';
        $this->food = 'millet';
        $this->age = $age;
    }
}

$s = new AnimalState();
$s->init();

echo "\ndog\n";
Animal::sayHello( $s->state&#91;'dog'&#93; );
Animal::doPoo( $s->state&#91;'dog'&#93; );
Animal::doEat( $s->state&#91;'dog'&#93; );
echo "\ncat\n";
Animal::sayHello( $s->state&#91;'cat'&#93; );
Animal::doPoo( $s->state&#91;'cat'&#93; );
Animal::doEat( $s->state&#91;'cat'&#93; );
echo "\nbird\n";
Animal::sayHello( $s->state&#91;'bird'&#93; );
Animal::doPoo( $s->state&#91;'bird'&#93; );
Animal::doEat( $s->state&#91;'bird'&#93; );

// we create a new bird to replace the old one
$s->state&#91;'bird'&#93; = new Bird(5);

echo "\nthe new bird has age: " . $s->state&#91;'bird'&#93;->age . "\n\n";

var_dump($s);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;?</span><span style="color: #BD93F9">php</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">interface</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">AnimalInterface</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a);</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a);</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a);</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Animal</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">implements</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">AnimalInterface</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">use</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Speak</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">use</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Poop</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">use</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Eat</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">trait</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Speak</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Says: </span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $a</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">trait</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Poop</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a)</span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Defecates: </span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $a</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">trait</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Eat</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a)</span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Eats: </span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $a</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">AnimalState</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> $state </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [];</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">init</span><span style="color: #F8F8F2">() </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Dog</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Cat</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Bird</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Dog</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">extends</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $speech;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $defecate;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $food;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">int</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">__construct</span><span style="color: #F8F8F2">($age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">woof</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog loaf</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">kibble</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Cat</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">extends</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $speech;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $defecate;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $food;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">int</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">__construct</span><span style="color: #F8F8F2">($age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">mew</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">hairpoo</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">tuna</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Bird</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">extends</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $speech;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $defecate;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $food;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">int</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">__construct</span><span style="color: #F8F8F2">($age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">chirp</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">birdstool</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">millet</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">$s </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">AnimalState</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">$s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #50FA7B">init</span><span style="color: #F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">dog</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">cat</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">bird</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4">// we create a new bird to replace the old one</span></span>
<span class="line"><span style="color: #F8F8F2">$s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Bird</span><span style="color: #F8F8F2">(</span><span style="color: #BD93F9">5</span><span style="color: #F8F8F2">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">the new bird has age: </span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93;</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8BE9FD">var_dump</span><span style="color: #F8F8F2">($s);</span></span></code></pre></div>



<p class="wp-block-paragraph">This code has interesting qualities.</p>



<p class="wp-block-paragraph">First, the AnimalState is the only thing that holds state.</p>



<p class="wp-block-paragraph">Everything else doesn&#8217;t hold state.</p>



<p class="wp-block-paragraph">The Dog, Cat, and Bird types are stateful classes, and instantiated, but aren&#8217;t mutable. All the properties are <code>readonly</code>.</p>



<p class="wp-block-paragraph">Look at line 109. I cannot set the value of $age, because it&#8217;s readonly, but I can initialize a new Bird of 5 years old. Some languages also have this restriction, where named values are immutable.</p>



<p class="wp-block-paragraph"><strong>Method names and property names matter</strong>. For all the parts to work, they must conform. The AnimalInterface enforces the method names. <em>Nothing enforces the property names.</em></p>



<p class="wp-block-paragraph">Is it useful? I&#8217;m not sure. It&#8217;s a lot of extra boilerplate.</p>



<h4 class="wp-block-heading">What&#8217;s Missing?</h4>



<p class="wp-block-paragraph">PHP 8.3.6 doesn&#8217;t support <code>public readonly protected(set)</code>. If it did, I think I could move the variable declarations up into Animal, and it would act like a contract for the subclasses.</p>



<p class="wp-block-paragraph">I tried moving the properties like $speech into the Trait (rather than in the Class like it is above). It linted with php -l, failed with phpstan, and didn&#8217;t run. It refused to initialize the $speech property from the Trait because it was out of the Dog scope.</p>



<p class="wp-block-paragraph">Here&#8217;s the <code>json_encode($s)</code> output:</p>


<pre class="wp-block-code"><span><code class="hljs language-json shcb-wrap-lines">{
    \<span class="hljs-attr">"state\": {
        \"dog\": {
            \"speech\": \"woof\",
            \"defecate\": \"dog loaf\",
            \"food\": \"kibble\",
            \"age\": 1
        },
        \"cat\": {
            \"speech\": \"mew\",
            \"defecate\": \"hairpoo\",
            \"food\": \"tuna\",
            \"age\": 1
        },
        \"bird\": {
            \"speech\": \"chirp\",
            \"defecate\": \"birdstool\",
            \"food\": \"millet\",
            \"age\": 5
        }
    }
}</span></code></span></pre>


<p class="wp-block-paragraph">It&#8217;s OK, but it needs a _class property so it can rehydrate correctly (which is easy to add).</p>



<p class="wp-block-paragraph"><code>$s->state['bird']->age = 100;</code> // this code passes php&#8217;s lint, but it&#8217;s a bug.</p>



<p class="wp-block-paragraph">Ideally, this bug would be caught at compile time, because assigning a value to a readonly property throws an error when run.</p>



<p class="wp-block-paragraph">I found this <a href="https://guven.atbakan.com/blog/php-linters-i-cant-live-without-them/">good post about PHP linters</a>.</p>



<p class="wp-block-paragraph"><strong><a href="https://phpstan.org/user-guide/getting-started">phpstan</a> found the bug with &#8211;level 3.</strong></p>



<p class="wp-block-paragraph">(I tried installing <a href="https://packagist.org/packages/vimeo/psalm#dev-master">psalm</a>, but my PHP version was too low.)</p>



<h3 class="wp-block-heading">More Thinking</h3>



<p class="wp-block-paragraph">In a real-world scenario, you would probably have a more elaborate state structure of nested arrays, terminating in these read-only objects, or arrays of read-only objects.</p>



<p class="wp-block-paragraph">Your application would be a bunch of Interfaces and implementation, read-only objects, and some logic to make the app happen.</p>



<p class="wp-block-paragraph">I think you&#8217;d have lots of code like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-php shcb-wrap-lines">$s-&gt;state&#91;<span class="hljs-string">'x'</span>]&#91;<span class="hljs-string">'y'</span>]&#91;<span class="hljs-string">'z'</span>] = 
    SomeService::doAThingTo( $s-&gt;state&#91;<span class="hljs-string">'x'</span>]&#91;<span class="hljs-string">'y'</span>]&#91;<span class="hljs-string">'z'</span>] );</code></span></pre>


<p class="wp-block-paragraph">You&#8217;d have that mixed in with a lot of traditional logic.</p>



<p class="wp-block-paragraph">You&#8217;d write functions to manipulate the state yourself.</p>



<p class="wp-block-paragraph">Some things could get easy, like saving the app state with each request: use a flatter namespace, and save it to Redis. (Examples: &#8216;config&#8217;, &#8216;app&#8217;, &#8216;user&#8217;, &#8216;documents&#8217;.)</p>



<p class="wp-block-paragraph">Retrieve the state from Redis. Add a feature to lazy-load the data, and write subsets of the state.</p>



<p class="wp-block-paragraph">AnimalState doesn&#8217;t need to be initialized with objects. It&#8217;s just an array. It should probably use magic methods to allow $s->dog to return the Dog object.</p>



<p class="wp-block-paragraph">Setter magic methods could verify that the new value is of the same class as the old value; so a Dog object must be replaced with another Dog object.</p>



<p class="wp-block-paragraph">DocBlocks might be able to add a type annotation, but I don&#8217;t know if it would be honored.</p>



<p class="wp-block-paragraph">Magic getters could map a key like &#8216;dog&#8217; to a property named &#8216;_dog&#8217;, which has a type signature that phpstan might recognize. The magic getter should be coded up with a switch statement rather than doing string mangling and isset().</p>



<p class="wp-block-paragraph">Example:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-keyword">public</span> readonly Dog $_dog;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__get</span><span class="hljs-params">($key)</span>: <span class="hljs-title">Animal</span>
</span>{
    <span class="hljs-keyword">switch</span>($key) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">'dog'</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;_dog;
        <span class="hljs-keyword">default</span>: <span class="hljs-comment">// some error situation, die nicely</span>
    }
}</code></span></pre>


<p class="wp-block-paragraph">The robot overlords can understand that code path, and won&#8217;t need to &#8220;reason&#8221; about some string mangling code like this (code not checked):</p>


<pre class="wp-block-code"><span><code class="hljs language-php shcb-wrap-lines"><span class="hljs-keyword">public</span> $state;
...
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__get</span><span class="hljs-params">($key)</span>: <span class="hljs-title">object</span> 
</span>{
    $kkey = <span class="hljs-string">"_$key"</span>;
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">isset</span>(<span class="hljs-keyword">$this</span>-&gt;state&#91;$kkey])) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;state&#91;$kkey];
    } <span class="hljs-keyword">else</span> {
       <span class="hljs-comment">// die politely</span>
    }
}</code></span></pre>


<p class="wp-block-paragraph">I realize the latter is more general, but that begs the question: should everything be generalized and flexible at runtime, even if it&#8217;s the thing holding the application state?</p>



<p class="wp-block-paragraph">The answer in 2026 is &#8220;no&#8221;.</p><p>The post <a href="https://riceball.com/2026/10/12/php-traits/">PHP Traits</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/12/php-traits/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
