<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://www.stitcher.io/rss</id>
    <link href="https://www.stitcher.io/rss"/>
    <title><![CDATA[ stitcher.io ]]></title>
    <updated>2024-09-06T05:00:13+00:00</updated>
                        <entry>
                <title><![CDATA[ A simple approach to static site generation ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-simple-approach-to-static-generation"/>

                <id>https://www.stitcher.io/blog/a-simple-approach-to-static-generation</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>This blog is over 7 years old now, and I'm still writing on it! Not bad! It has always been a statically generated site, backed by my own static generator. In fact, the name "stitcher" comes from that generator. It's called that way because it "stitches" content together. My goal was to make a super fast website, and I think I succeeded in doing so: it has a score of 100 on lighthouse, both mobile and web, so yeah. I did something right.</p>
<p>Now, my static generator has gone through three complete rewrites over the years. When I started out I dreamt of open sourcing it and it becoming something "big", but now I hope <strong>no one will ever use it</strong>! Over the years I've come to realise I made a lot of things very complicated for no real reason. For example: I wanted to manage everything with YAML — <strong>big mistake</strong>. You can take a look at it yourself, this is part of my site's configuration:</p>
<pre>/:
    <span class="hl-keyword">template</span><span class="hl-property">:</span> blog/overview.twig
    <span class="hl-keyword">variables</span><span class="hl-property">:</span>
        <span class="hl-keyword">title</span><span class="hl-property">:</span> Blog
        <span class="hl-keyword">overviewTitle</span><span class="hl-property">:</span> programming
        <span class="hl-keyword">posts</span><span class="hl-property">:</span> src/content/blog.yaml
        <span class="hl-keyword">meta</span><span class="hl-property">:</span>
            <span class="hl-keyword">description</span><span class="hl-property">:</span> &quot;<span class="hl-value">A blog about modern PHP, the web, and programming in general. Follow my newsletter and YouTube channel as well.</span>&quot;
    <span class="hl-keyword">config</span><span class="hl-property">:</span>
        <span class="hl-keyword">order</span><span class="hl-property">:</span>
            <span class="hl-keyword">variable</span><span class="hl-property">:</span> posts
            <span class="hl-keyword">field</span><span class="hl-property">:</span> date
            <span class="hl-keyword">direction</span><span class="hl-property">:</span> desc

/blog/<span class="hl-property">{</span>id<span class="hl-property">}</span>:
  <span class="hl-keyword">template</span><span class="hl-property">:</span> blog/detail.twig
  <span class="hl-keyword">variables</span><span class="hl-property">:</span>
    <span class="hl-keyword">overviewTitle</span><span class="hl-property">:</span> programming
    <span class="hl-keyword">post</span><span class="hl-property">:</span> src/content/blog.yaml
    <span class="hl-keyword">meta</span><span class="hl-property">:</span>
      <span class="hl-keyword">description</span><span class="hl-property">:</span> &quot;<span class="hl-value">A blog about modern PHP, the web, and programming in general. Follow my newsletter and YouTube channel as well.</span>&quot;
  <span class="hl-keyword">config</span><span class="hl-property">:</span>
    <span class="hl-keyword">collection</span><span class="hl-property">:</span>
      <span class="hl-keyword">variable</span><span class="hl-property">:</span> post
      <span class="hl-keyword">parameter</span><span class="hl-property">:</span> id
    <span class="hl-keyword">next</span><span class="hl-property">:</span> true
    <span class="hl-keyword">meta</span><span class="hl-property">:</span> true
</pre>
<p>And this is how I add blog posts (in another YAML file):</p>
<pre><span class="hl-keyword">a-simple-approach-to-static-generation</span><span class="hl-property">:</span>
  <span class="hl-keyword">date</span><span class="hl-property">:</span> 2024-08-30
  <span class="hl-keyword">title</span><span class="hl-property">:</span> A simple approach to static site generation
  <span class="hl-keyword">content</span><span class="hl-property">:</span> src/content/blog/2024-08-30-a-simple-approach-to-static-generation.md
  <span class="hl-keyword">disableAds</span><span class="hl-property">:</span> true

<span class="hl-keyword">timeline-taxi-chapter-07</span><span class="hl-property">:</span>
  <span class="hl-keyword">date</span><span class="hl-property">:</span> 2024-08-24
  <span class="hl-keyword">title</span><span class="hl-property">:</span> &quot;<span class="hl-value">Timeline Taxi: chapter 7</span>&quot;
  <span class="hl-keyword">content</span><span class="hl-property">:</span> src/content/taxi/taxi-07.md
  <span class="hl-keyword">next</span><span class="hl-property">:</span> timeline-taxi-chapter-01
  <span class="hl-keyword">disableAds</span><span class="hl-property">:</span> true

<span class="hl-keyword">extends-vs-implements</span><span class="hl-property">:</span>
  <span class="hl-keyword">date</span><span class="hl-property">:</span> 2024-08-21
  <span class="hl-keyword">title</span><span class="hl-property">:</span> Extend or implement
  <span class="hl-keyword">content</span><span class="hl-property">:</span> src/content/blog/2024-08-18-extends-vs-implements.md
  <span class="hl-keyword">disableAds</span><span class="hl-property">:</span> true
</pre>
<p>There's so much overhead converting YAML config into something that generates a website, and it's really not worth it. Especially when you realise I need a non-static version for local development. So I actually parse this YAML into a routable application as well 🤢.</p>
<p>Three years ago, I realised that this approach was doing more harm than good, and I tried refactoring stitcher to Laravel: instead of a YAML file, I'd make simple controllers, and somehow generate static pages from those. In other words, I'd use my controllers as "configuration", which had the benefit my content being accessible within a non-static context as well for local development — the controllers were already there.</p>
<p>I actually got pretty far twice, but gave up on it twice as well. It was never a high-stakes project since the original still worked, and I guess other things got in the way.</p>
<p>However, yesterday, I was working on the <a href="https://tempest.stitcher.io">Tempest docs website</a>, and realised it could use a static version as well. Why would I need to boot the framework everytime when all I need is an HTML page? So I did some hacking and… well. I got it working within an hour 😅</p>
<p>Granted, Tempest does most of the heavy lifting, but I dare to say that my experience writing a static generator from scratch three times might have helped as well. Here's what I did.</p>
<p>Tempest already has controller actions — obviously — they look like this:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">HomeController</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">home</span>(): <span class="hl-type">View</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">home</span>');
    }
}
</pre>
<p>Now, what if we want to generate a static version of this page? We need a way of letting Tempest know it should generate an HTML page from a controller action. That's easy enough using an attribute:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">HomeController</span>
{
    <span class="hl-attribute">#[<span class="hl-type">StaticPage</span>]</span>
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">home</span>(): <span class="hl-type">View</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">home</span>');
    }
}
</pre>
<p>Now, Tempest has a concept called <a href="https://tempest.stitcher.io/internals/02-discovery">discovery</a>, so finding the actions that should be compiled into static pages isn't all that difficult:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">StaticPageDiscovery</span> <span class="hl-keyword">implements</span><span class="hl-type"> Discovery
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">StaticPageConfig</span> <span class="hl-property">$staticPageConfig</span>,
    </span>) {
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">discover</span>(<span class="hl-injection"><span class="hl-type">ClassReflector</span> $class</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// Loop over all public methods</span>
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$class</span>-&gt;<span class="hl-property">getPublicMethods</span>() <span class="hl-keyword">as</span> <span class="hl-variable">$method</span>) {
            <span class="hl-comment">// If a method has the `<span class="hl-attribute">#[StaticPage]</span>` attribute,</span>
            <span class="hl-variable">$staticPage</span> = <span class="hl-variable">$method</span>-&gt;<span class="hl-property">getAttribute</span>(<span class="hl-type">StaticPage</span>::<span class="hl-keyword">class</span>);

            <span class="hl-keyword">if</span> (! <span class="hl-variable">$staticPage</span>) {
                <span class="hl-keyword">continue</span>;
            }
            
            <span class="hl-comment">// we need to add it to our list of static pages</span>
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">staticPageConfig</span>-&gt;<span class="hl-property">addHandler</span>(<span class="hl-variable">$staticPage</span>, <span class="hl-variable">$method</span>);
        }
    }

    <span class="hl-comment">// Some more boring cache stuff</span>
}
</pre>
<p>So right away, we've got a config file with all the controller actions that should be compiled to static pages. Next, let's create the command that will generate all that content:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">StaticGenerateCommand</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">HasConsole</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">Console</span> <span class="hl-property">$console</span>,
        <span class="hl-keyword">private</span> <span class="hl-type">StaticPageConfig</span> <span class="hl-property">$staticPageConfig</span>,
    </span>) {}

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ConsoleCommand</span>('<span class="hl-value">static:generate</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(): <span class="hl-type">void</span>
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">staticPageConfig</span>-&gt;<span class="hl-property">staticPages</span> <span class="hl-keyword">as</span> <span class="hl-variable">$staticPage</span>) {
            <span class="hl-comment">// …</span>
        }

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">success</span>('<span class="hl-value">Done</span>');
    }
}
</pre>
<p>Right now, nothing much is going on: we inject that static page config which was populated by our discovery class, and we inject the console as well because we want to write some output to it. Now, what should we do with each static page? It holds a reference to a controller action, which we can use to generate a response with, which we can render into HTML. We'll need to inject a couple more framework dependencies to handle the heavy lifting for us, but nothing too complicated:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ConsoleCommand</span>('<span class="hl-value">static:generate</span>')]</span></span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(): <span class="hl-type">void</span>
{
    <span class="hl-variable">$publicPath</span> = <span class="hl-property">path</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">appConfig</span>-&gt;<span class="hl-property">root</span>, '<span class="hl-value">public</span>');
    
    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">staticPageConfig</span>-&gt;<span class="hl-property">staticPages</span> <span class="hl-keyword">as</span> <span class="hl-variable">$staticPage</span>) {
        <span class="hl-comment">// First, we generate the URI for this static page's controller handler</span>
        <span class="hl-variable">$uri</span> = <span class="hl-property">uri</span>(<span class="hl-variable">$staticPage</span>-&gt;<span class="hl-property">handler</span>);
       
        <span class="hl-comment">// Next, we dispatch a new GET request via Tempest's router </span>
        <span class="hl-variable">$response</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">router</span>-&gt;<span class="hl-property">dispatch</span>(
            <span class="hl-keyword">new</span> <span class="hl-type">GenericRequest</span>(
                <span class="hl-property">method</span>: <span class="hl-type">Method</span>::<span class="hl-property">GET</span>,
                <span class="hl-property">uri</span>: <span class="hl-variable">$uri</span>,
            ),
        );
        
        <span class="hl-comment">// We render the response</span>
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">viewRenderer</span>-&gt;<span class="hl-property">render</span>(<span class="hl-variable">$response</span>-&gt;<span class="hl-property">getBody</span>());

        <span class="hl-comment">// And write the HTML to a file</span>
        <span class="hl-variable">$file</span> = <span class="hl-property">path</span>(<span class="hl-variable">$publicPath</span>, <span class="hl-variable">$uri</span> . '<span class="hl-value">.html</span>');
        <span class="hl-property">file_put_contents</span>(<span class="hl-variable">$file</span>, <span class="hl-variable">$content</span>);
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">writeln</span>(&quot;<span class="hl-value">- &lt;em&gt;{$uri}&lt;/em&gt; &gt; &lt;u&gt;{$file}&lt;/u&gt;</span>&quot;);
    }

    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">success</span>('<span class="hl-value">Done</span>');
}
</pre>
<p>So that's all good, but there's an important thing missing: this approach won't work for routes that have dynamic parameters. Take for example Tempest's docs controller action:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">DocsController</span>
{
    <span class="hl-attribute">#[<span class="hl-type">StaticPage</span>]</span>
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/{category}/{slug}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">string</span> $category, <span class="hl-type">string</span> $slug, <span class="hl-type">ChapterRepository</span> $chapterRepository</span>): <span class="hl-type">View</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">DocsView</span>(
            <span class="hl-property">chapterRepository</span>: <span class="hl-variable">$chapterRepository</span>,
            <span class="hl-property">currentChapter</span>: <span class="hl-variable">$chapterRepository</span>-&gt;<span class="hl-property">find</span>(<span class="hl-variable">$category</span>, <span class="hl-variable">$slug</span>),
        );
    }
}
</pre>
<p>Yeah, this won't work, since we don't need to render one page, we need to render a page for <em>every</em> <code>$category</code> and <code>$slug</code> variant. In other words: we need to render a page for every chapter in the docs. It might seem like a difficult problem to solve — it used to be the most difficult thing to get right when I built stitcher — but it's actually pretty trivial. Whenever we have a dynamic route, we'll need a way to specify all variations of that route — something to provide data to fill in the gaps. How about… a data provider?</p>
<p>So, let's make a small change: let's add an interface called <code><span class="hl-type">DataProvider</span></code>, which has one task… provide data. It's the same concept as PHPUnit's data providers, by the way, it's not too complicated. So let's refactor our docs controller like so:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">DocsController</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">StaticPage</span>(<span class="hl-type">DocsDataProvider</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/{category}/{slug}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">string</span> $category, <span class="hl-type">string</span> $slug, <span class="hl-type">ChapterRepository</span> $chapterRepository</span>): <span class="hl-type">View</span>
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>And implement that <code><span class="hl-type">DocsDataProvider</span></code> class next:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">DocsDataProvider</span> <span class="hl-keyword">implements</span><span class="hl-type"> DataProvider
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">ChapterRepository</span> <span class="hl-property">$chapterRepository</span>
    </span>) {}

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">provide</span>(): <span class="hl-type">Generator</span>
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">chapterRepository</span>-&gt;<span class="hl-property">all</span>() <span class="hl-keyword">as</span> <span class="hl-variable">$chapter</span>) {
            <span class="hl-keyword">yield</span> [
                '<span class="hl-value">category</span>' =&gt; <span class="hl-variable">$chapter</span>-&gt;<span class="hl-property">category</span>,
                '<span class="hl-value">slug</span>' =&gt; <span class="hl-variable">$chapter</span>-&gt;<span class="hl-property">slug</span>,
            ];
        }
    }
}
</pre>
<p>As you can see, it's not too complicated: we already have a <code><span class="hl-type">ChapterRepository</span></code> that lists all available chapters, now it's just a matter of providing the right data for every page. So with that in place, we need to make one final change to our generate command, as it needs to take this data provider into account:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ConsoleCommand</span>('<span class="hl-value">static:generate</span>')]</span></span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(): <span class="hl-type">void</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">staticPageConfig</span>-&gt;<span class="hl-property">staticPages</span> <span class="hl-keyword">as</span> <span class="hl-variable">$staticPage</span>) {
        <span class="hl-comment">// Retrieve the data provider via the container</span>
        <span class="hl-variable">$dataProvider</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">container</span>-&gt;<span class="hl-property">get</span>(
            <span class="hl-variable">$staticPage</span>-&gt;<span class="hl-property">dataProviderClass</span> 
            ?? <span class="hl-type">GenericDataProvider</span>::<span class="hl-keyword">class</span>
        );

        <span class="hl-comment">// Loop over all its iterations</span>
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$dataProvider</span>-&gt;<span class="hl-property">provide</span>() <span class="hl-keyword">as</span> <span class="hl-variable">$params</span>) {
            <span class="hl-comment">// Generate the URI for this static page's controller handler</span>
            <span class="hl-comment">// WITH the dynamic parameters</span>
            <span class="hl-variable">$uri</span> = <span class="hl-property">uri</span>(<span class="hl-variable">$staticPage</span>-&gt;<span class="hl-property">handler</span>, ...<span class="hl-variable">$params</span>);
            
            <span class="hl-comment">// … The rest stays the same</span>
        }
    }
}
</pre>
<p>And we're done! Now we have one controller action that generates a dynamic amount of pages, all with just a couple of lines of code. I added some null checks and prevented some edge cases — you can check out the <a href="https://github.com/tempestphp/tempest-framework/blob/main/src/Tempest/Http/Static/StaticGenerateCommand.php">full code here</a> if you want to.</p>
<hr />
<p>In hindsight, I'm really struggling to understand my train of thought for when I built stitcher: why did I make things so complicated, when all I needed was just a couple lines of code? Wisdom comes with age, right? Well, I'm happy with the results, and I believe I'm now able to finally port my blog to something that works a lot easier. All the building blocks are in place, I just need to do the refactor.</p>
 ]]></summary>

                <updated>2024-08-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Timeline Taxi: chapter 7 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/timeline-taxi-chapter-07"/>

                <id>https://www.stitcher.io/blog/timeline-taxi-chapter-07</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
<p><a href="/blog/timeline-taxi-chapter-06">Read the previous chapter.</a></p>
<p>“Big Bertha, Hyperion-C, seize all powerup activities and hand over remote control to us, you have one minute to comply or we will shoot you down.”</p>
<p>The radio voice makes it pretty clear: when it comes to unauthorized launches, the USN on Mars takes things more seriously than the UN on Earth.</p>
<p>“Powerup 85%”</p>
<p>“Just a couple more minutes.” I mumble.</p>
<p>“Pathing complete”</p>
<p>“Big Bertha, Hyperion-C,” the voice comes in once again, “this is your last warning. You have 30 seconds to comply.”</p>
<p>“Ok doc,” I say, my eyes fixed on the dashboard, “it’s gonna be close. We can take a couple of hits, but I don’t know how long we’ll last.”</p>
<p>“Powerup 90%”</p>
<p>“Big Bertha, 10 seconds.” I ignore them.</p>
<p>It feels longer than ten seconds, but finally the first shot is fired. It misses — that might have been on purpose, or maybe because the ships are still pretty far out.</p>
<p>I open my mic channel, “USN, this is Hyperion-C, beware of full-powerup, clear the engine zone or you will be vaporized!”</p>
<p>Two more shots, one hits us, but there’s no other reply. The dashboard reports no critical damage.</p>
<p>“Powerup 95%”</p>
<p>“Doc, hold on tight! Remember those couple of g’s I told you about? They will be here soon.”</p>
<p>Another two shots, both of them hit. An alarm goes off, the shuttle has been breached. It’s sealed off from the ship so there’s no need to worry. Too bad for the shuttle though.</p>
<p>Another shot. The ship rumbles.</p>
<p>“Engine failure, continue powerup?”</p>
<p>“What is that?” The doctor asks — he’s glancing at the dashboard himself.</p>
<p>“One of the engines has been hit.” I say, not looking up as I’m frantically pressing buttons to reconfigure my engine setup.</p>
<p>“Now what?” He asks with a slight tone of panic in his voice.</p>
<p>“Don’t worry,” I say, “We can still use the other engine.” Meanwhile I’ve made the necessary changes so that we can continue powerup with one engine alone.</p>
<p>“Get ready, doc!”</p>
<p>“Powerup 100%. Initiate acceleration?”</p>
<p>The dashboard reports one more shot approaching, but it never hits. In an instant, I’m pressed into my seat and I find it difficult to move. I usually find the pressure that comes with full-powerup acceleration rather uncomfortable, but now feels like a relief. It’ll take an hour to reach near-lightspeed, but the USN ships are already far behind. Space in front of us is turning more and more blue, the common blueshift at ultra-high speeds. I keep close track of the engine status, if this second one fails, we’re in big trouble.</p>
<p>It doesn’t fail though. An hour later we’ve reached 99.995% c, and we’re back to zero g’s now that the engine has powered down.</p>
<p>“You ok?”, I ask as I turn away from the dashboard to the doctor.</p>
<p>“I think so. That was tense.”</p>
<p>“It’s not done yet, unfortunately,” I sigh. I waited to tell him the news until acceleration was done. We have a damaged engine, but we can accelerate to near-lightspeed and slow back down from it just fine with one. The problem is that our one working engine doesn’t have enough fuel anymore. Usually the load is balanced between two engines, and so also their fuel usage. Now that we’ve accelerated with one engine alone, it has used almost all the fuel it had. A quick checkup on fuel status tells me I need at least three injections from the damaged engine before we can slow down again.</p>
<p>“I hope,” I tell the doctor, “there are still three working injections in the damaged engine. Otherwise…”</p>
<p>“What? Otherwise what?” The doctor asks, the same panic creeping into his voice once again.</p>
<p>“Look, if we don’t have enough fuel, we can’t slow down.” I let those words sink in for a moment before I continue. “If we can’t slow down… Well that's the end of the story for us.” There’s no need to sugarcoat our situation.</p>
<p>“You mean you accelerated to near-lightspeed, without knowing whether we could ever stop again?”</p>
<p>“It was that or being shot by the USN, remember?” The doctor’s panic isn’t helping, it’s not like I’m at fault here. He insisted on powering up, even though I suggested taking another route. Granted, that was before one of my engines was toast, but still. “Besides,” I continue, “let’s not make a big deal out of it before we’re truly in trouble. For all we know, the damaged engine’s injections are fine. I just need to move them to the other side —”</p>
<p>“Hang on,” the doctor interrupts, “are you going on an EVA at near-lightspeed?” The panic in his voice has made room for skepticism.</p>
<p>“Yeah. Well. It’s not impossible,” I snap. “I’ve got an EVA suit made especially for it. Ok… I’ve never done it before. If I fall off… Well, I don’t need to explain to you how the ship works, because you’ll be screwed anyway if I don’t manage to transfer those injections. Maybe I should explain how deep sleep works and how to rig the system so that you could die a painless death if something were to happen.”</p>
<p>But the doctor shoves it aside. “Just… Fix it,” he says. The mood now definitely changed for the worse. Maybe it’ll be good not to be in each other's hair for a moment. So I sigh without saying anything else, and head downstairs.</p>
<p>Half an hour later I’m in my EVA suit in the frontal airlock. I know this won’t be easy. The most difficult part about doing an EVA at near-lightspeed is that space is almost empty — almost. At this speed, miniscule dust and radiation particles accumulate into what would feel like a sand storm on Earth. My suit only guarantees protection for up to 15 consecutive minutes, so as soon as the airlock door opens, I’m on the clock to inspect the damaged engine, find and detach three working injections, move them to the left outrigger of the ship, into the engine, and get back to the airlock.</p>
<p>I press the button. The airlock opens.</p>
<p>I’m immediately pushed backwards, but my boots are magnetically attached to the floor and it only takes a couple of seconds to regain my balance. I gasp when I look up and see the sparkling stripes and flashes of light. These are miniscule dust particles flying by at nearly the speed of light. Each of them leaves a light trail as thin as a hair. They aren’t visible from within the cockpit with its filtered glass, but from outside, they resemble an infinite sea of fireflies in space.</p>
<p>I stand in awe, but I know I’m on the clock, so I force myself forward, turn, and grab the handle on the right side of the airlock. My muscles ache pretty quickly as I pull myself forward while I’m fighting the invisible storm around me, but I manage to hold on tight and crawl towards the right outrigger. I hoist myself on top of it, turn backwards, and once again I’m stunned by an amazing view: the redshifted space behind us glows like the most magnificent sunset without any visible horizon.</p>
<p>I reach the broken engine and see how the injectors are directly exposed, the cover plate nowhere to be found. Most likely it ripped off after our somewhat hasty departure from Mars.Luckily all injections seem fine, it’s only the engine that was damaged, not the injectors in front of it. I sigh. We’re in luck. Granted, my ship is in bad condition with a missing cover plate and a damaged shuttle, but none of those issues are life-threatening. I grab the first injection rod, turn it clockwise and lift it out of the injector. It instantly slips out of my fingers and flies off into infinity. Ok so, just holding it doesn’t work. I only now think of magnetizing my glove. I’m lucky that that injection didn’t hit the ship. I lift up the second one, and this one holds. I magnetically attach it to my leg. Now the third, and the fourth. I’ve got three full injections and ten more minutes. Let’s go.</p>
<p>The magnificent light spectacle around me reflects faint stripes of light on the hull as I crawl my way onto the left outrigger. I’m sweating, my muscles burn, but we’re on the right track. This engine’s injectors are exposed as well, their cover plate ripped off. I immediately spot the ones that need to be replaced: full injection rods emit a soft dark glow, empty ones don’t. I pull out five depleted ones in total, that leaves 2 full ones. If I add the three I have with me, we’ll have just enough fuel for slowdown on one engine. One by one, I strap the empty ones to my leg and back, and replace them with new rods. I do a final check, all are firm in place. Four more minutes, time to get back.</p>
<p>Once again awestruck, I take a minute to stare into space when I’m back into the airlock — I did have a minute to spare after all. I should probably be happy about the successful repair, but the only thing I think of is the magnificent view I’m witnessing. I don’t want this moment to end.</p>
<p>Full of sweat, I strap into my seat half an hour later. “Ok doc, we’re good,” I say when I see the dashboard reporting 5 full injections in the left engine. “Maybe we should have a proper talk?”</p>
 ]]></summary>

                <updated>2024-08-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Extend or implement ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/extends-vs-implements"/>

                <id>https://www.stitcher.io/blog/extends-vs-implements</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm probably part of a small group that actually cares about this: the difference between extending an abstract class and implementing an interface (ideally with a trait to provide part of the default implementation). I don't expect many people to follow my reasoning, but hey, it's my blog, I can write whatever thoughts are coming to my mind 😅</p>
<p>I also made a video about it, by the way:</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/HK9W5A-Doxc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<hr />
<p>I've been wrestling with code that <em>abuses inheritance</em> for a couple of years now. Granted: I don't really like the word <em>abuse</em> because it sounds very heavy, and code that <em>abuses</em> inheritance can still work perfectly well. But I also struggle to find a better word for it. Maybe "code that doesn't fit <em>my</em> expectations of what inheritance should be used for". I'm frustrated with myself because I can't seem to put into words exactly <em>why</em> I dislike code that's intentionally designed to be extended. It happens a lot in Laravel, but I'm sure it happens in Symfony and other places as well.</p>
<p>"Extend from a base class", "override a method" — all in the name of "flexibility" and "configurability". It's a common pattern, but it feels so… icky to me. The practice is so common that a whole community of developers is vocally against using <code><span class="hl-keyword">final</span></code>, because it blocks them from accessing that flexibility inheritance is giving them.</p>
<p>All the while, I'm thinking "this isn't the way inheritance was meant to be used…"</p>
<p>Like I said, it's difficult to put into words, but I think the problem for me started when I watched <a href="https://youtu.be/oKg1hTOQXoY?si=wAIxjBuzmwWiR6Ml&amp;t=811">Alan Kay's talk about his vision for OOP</a>. Alan is the inventor of object-oriented programming, by the way. He describes how you can build a dog house using only a hammer, nails, planks, and just a little bit of skill. Once you've built it, you've earned the skills and know-how, and you can apply that knowledge to other projects. Next, you want to build a cathedral, using the same approach with your hammer, nails, and planks. It's a 100 times larger, but you've done this before — right? It'll only take a little longer.</p>
<p>This is where Alan says OOP started to derail: languages like C++ took a relatively simple concept, and started to do a bunch of things with it in a way it wasn't supposed to be used. Granted, the code works, but it's lacking in many areas. Honestly, it's a fascinating talk and I highly recommend watching it.</p>
<p>Back to modern OOP: we've taken a concept like inheritance, and made it almost equivalent to "an easy way of configuring and plugging into vendor code". Open source packages are designed deliberately to extend and overwrite different parts of their codebase, hoping all goes well. The sad part, to me, is that there are better solutions to solve these problems. Other ways than to rely on inheritance. There's a range of patterns that help us solve whatever issues we run into — including configuration and "plugability" of code that's out of our control. Alan talks about this as well, by the way: proper architecture is a thing.</p>
<p>I was thinking about inheritance, comparing it to interfaces, and I came up with a definition that somewhat makes sense to me: <strong>I want to use inheritance to reflect real-world relations; I want to use interfaces to describe technical behaviour</strong>.</p>
<p>A class that implements an interface doesn't necessarily describe the essence of that class, it only promises it can perform the tasks defined by that interface. It could do a lot more things, for all I know, but I don't care about that within a specific context. It's a "hey, I can do this" promise rather than "hey, I <em>am</em> this". Inheritance, on the other hand, conveys that a class is a <em>subcategory</em> of something else. To me, that kind of relation only makes sense when we're talking about real-world modelling. Or maybe it's the other way around: if we try to apply that kind of relation to technical properties, things get out of hand fairly quickly.</p>
<p>An example: <code><span class="hl-type">User</span> <span class="hl-keyword">extends</span> <span class="hl-type">Model</span></code>, for me, that's wrong: a <code><span class="hl-type">User</span></code> isn't a <code><span class="hl-type">Model</span></code>; instead it's a class that can act like a model. It's a class that makes a promise to whatever context it's being used in. <code><span class="hl-type">AdminUser</span></code>, on the other hand, should extend from <code><span class="hl-type">User</span></code>, because it reflects a real-world relationship: an <code><span class="hl-type">AdminUser</span></code> is everything a <code><span class="hl-type">User</span></code> is, and probably a bit more. So, in my mind it should be <code><span class="hl-type">AdminUser</span> <span class="hl-keyword">extends</span> <span class="hl-type">User</span> <span class="hl-keyword">implements</span><span class="hl-type"> Model</span></code> (although the <code><span class="hl-keyword">implements</span><span class="hl-type"> Model</span></code> already happens on the parent class and isn't necessary here).</p>
<p>Like I said, I suspect not many people caring so deeply about this, and I'm not sure why <em>I</em> care so deeply about it myself. I think this definition keeps things somewhat clear to me. It eliminates a gray zone that I find confusing to work in.</p>
<p>And sure, there are some technical arguments to make against my thought experiment within PHP: there's no multiple inheritance, there are no interface default methods, and you can't implement an interface via a trait. There are limitations to the language we're using.</p>
<p>But still, I find this mental model more comfortable than the alternative.</p>
 ]]></summary>

                <updated>2024-08-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Timeline Taxi: chapter 6 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/timeline-taxi-chapter-06"/>

                <id>https://www.stitcher.io/blog/timeline-taxi-chapter-06</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
<p><a href="/blog/timeline-taxi-chapter-05">Read the previous chapter.</a></p>
<p>I remember growing up as a kid, following the live transmission as humans set the first foot on Mars. We had been chasing the Mars dream for multiple centuries and were finally there. A handful of centuries before that historical landing, billionaires had privatized the space sector and made it into their life's mission to be the first on Mars. They longed for something money could not buy, but none of them ever got to witness the landing. An endless chain of setbacks and disappointments had defined that space age.</p>
<p>I wonder how they would react, had they known they were looking in the wrong direction. Conventional propulsion was their biggest misstep. It would have never allowed humans to colonize Mars in a reasonable timeframe. The breakthrough came with the invention of antimatter pulsar engines, which could reach speeds no one thought imaginable. Suddenly the distance between Mars and Earth could be crossed within 30 days, then 25, then 20. Soon thereafter, we managed to reach near-lightspeed velocity. If the early pioneers would have had that technology available in their time, they would have been able to spend a year or two in near-lightspeed deep sleep to wake up in a new age. Instead, they died without the accomplishment they longed for, some even driven to insanity at the end of their lives.</p>
<p>And here I am — orbiting what used to be a desolate, dusty planet. It took almost 500 years from that first step in the Martian dust to make it into what it is today. The doctor’s looking out the cockpit window in awe. I’ve seen Mars before — a couple of times, not often, and definitely not in the stage it is today. I can relate. After a minute, maybe 5, maybe 10 — who knows — it’s back to work. We need to come up with a plan to refuel this ship. My fuel reserves are now almost empty, and getting from Mars to any other planet in a reasonable amount of time has become impossible. It needs to happen here and now.</p>
<p>“I suggest a couple of things.” I tell the doctor. It’s good having someone to bounce ideas off of, even if that someone has no practical experience with space travel, let alone how things work on Mars.</p>
<p>“First, I’ve changed our call sign. It’s one of the advantages of having an older ship: I’ve had to do several software upgrades throughout the centuries, which includes patches to its identification system. I kept the old versions as a backup though. I hotpatched the system to use my very first call sign.”</p>
<p>“Won’t they recognise it as an outdated call sign?” The doctor asks.</p>
<p>“Sure, but that’s not uncommon. There still are ships arriving occasionally in this period. Pioneers who bet everything they had on one very long near-lightspeed trip. So everyone still knows how to deal with these call signs, they are just not as convenient. It might give us a chance of not being flagged immediately.”</p>
<p>“Makes sense. What else?”</p>
<p>“There’s only one other thing I can think of: we won’t be able to refuel at any USN-owned station, that’s way too risky. But there are a handful of privately-owned stations in Martian orbit still. Not as many as I remember there to be, but we only need one. They tend to ask less questions about visitors. They are obliged to report to the USN once every month or so, which would mean trouble for us, but by then we’re already far gone. That’s the plan. What do you think?”</p>
<p>“Sounds… easy?”</p>
<p>“In theory it is easy, and no, I think this is our only option. I’ve refueled here a handful of times when the Martian reactors were still abundant and antimatter was cheaper here than on Earth. But that’s a long time ago. You better have some cash at hand, because it’s going to be expensive.”</p>
<p>“Don’t worry about that, I’ve got you covered.”</p>
<p>“So, are you ok with this plan? Anything to add?”</p>
<p>“Just to be sure, are there any alternatives you can think of?”</p>
<p>“Nope, as far as I know this is our only option.”</p>
<p>“Well, then I’m good to go. You’ve done this before, let’s just act normal and it’ll be fine.”</p>
<p>“Normal,” I say to myself and chuckle half-sarcastically. If all goes well, we should be on our way to the Oort cloud in three hours; we escaped Earth a little over a week ago because I became a wanted criminal; I’m here with a doctor who apparently discovered time travel, and I don’t even know where we’re going. So yeah, let’s act normal.</p>
<p>“That reminds me”, I say, “I will need those coordinates before we can engage in a full powerup. And a full powerup takes half an hour. So, whatever timing fits you best, but I’m just letting you know.”</p>
<p>The doctor nods. “I’ll give them when refueling is done.”</p>
<p>Ok, here goes.</p>
<p>“Mars Station Alpha 2, this is Big Bertha calling out, do you copy?”</p>
<p>The doctor turns to me barely holding it together. “Big Bertha?” he mouths.</p>
<p>“I know. I found it funny back then, I was young. Shut up.”</p>
<p>“Big Bertha, this is Mars Station Alpha 2, how are you today?” The reply sounds a little more cheery than usual.</p>
<p>“Mars Station, we’re all good here, just arrived from a pretty long trip and we’re looking for refuelment, can you help us with that?”</p>
<p>“Big Bertha, that shouldn’t be a problem, what kind of engine are you running?”</p>
<p>“Mars Station, I’ve got two separate antimatter pulsar engines, both need full refuelment.”</p>
<p>“Big Bertha, please proceed to gate 8, we’ll have the injections ready for you there. Please be advised that each injection will cost 50MD”</p>
<p>50 Mars Dollars, with a current conversion rate of one to five; it’s gonna be expensive indeed.</p>
<p>“Mars Station, all fine. Big Bertha proceeding to gate 8. Thank you.”</p>
<p>I have to do some exotic maneuvering to be able to dock at gate 8, this station is so packed that the ship needs to be spinned sideways and extend the outriggers into their near-lightspeed flight configuration, just so that we can dock without crashing into anything. The ship has become as flat as possible, meaning we now just barely fit. We need to attach with our frontal dock — the rear dock is occupied by the shuttle — which makes things more difficult as the outriggers extend most frontwards. Ideally, I’d move the shuttle to the front, but I don’t want to risk spending another half an hour maneuvering around.</p>
<p>But I know this ship as none other, and we dock without problems. Less than a minute later, the frontal airlock beeps, indicating that the valet wants to board. I float to the lower deck and open the gate.</p>
<p>“Good morning, sir. I was told you need full refuelment for both pulsar engines, correct?” He’s tapping frantically on his tablet while talking, not looking up.</p>
<p>“That’s right, I need 10 injections per engine.”</p>
<p>“Can these engines be accessed from the inside, sir?”</p>
<p>“I’m afraid not, you’ll need an EVA to reach them. I can help if you want.”</p>
<p>“Oh that’s ok sir, part of the service. This is a pretty nice ship you have!” He exclaims as he’s looking around the interior.</p>
<p>“Yeah it’s one of the few they made in my era, my grandfather designed it, called it Hyperion. This is Hyperion-C, the third one they made. They are very reliable, I think all nine of them are still operating fine after all these years.”</p>
<p>“Hyperion, good name — yet you renamed it to Big Bertha!” He says as he chuckles.</p>
<p>“I was young…”</p>
<p>“Oh believe me sir, I get you, no worries. Ok so, refuelment will take 15 minutes. I will need payment up front though.”</p>
<p>“Yeah, that’s no problem, hang on.” I call the doctor downstairs. “This is my travel companion, he’s the one paying today.”</p>
<p>“Very well, sir. That’s 20 injections in total, do you want to keep the depleted ones or can we recycle them?”</p>
<p>“Feel free to recycle them,” I reply.</p>
<p>“Perfect, that’s 1200 dollars then, you can pay here.” He holds the tablet in front of the doctor. The doctor scans his biochip, and the payment succeeds. First step done.</p>
<p>“We’ll see each other in an hour and a half then?”</p>
<p>“Perfect, see you then, sir.”</p>
<p>We move back up to the cockpit, sit in our chairs and watch for a couple of minutes as four technicians start their EVA. We can’t see the back of the outriggers from within the cockpit, which is where the engines are located, but we see them going back and forth carrying depleted injections.</p>
<p>“So, doc, a couple of pre-flight checks. After refueling, we travel to a safe takeoff position. As soon as full powerup is done, we’ll start acceleration. It’ll be fast. Really fast. The ship’s equipped with g-shields, otherwise you’d be squashed in an instant. You’ll still experience a handful of g’s though. They were barely noticeable during our acceleration to Mars, but a full powerup to near-lightspeed does carry some discomfort. Probably 3 to 4 g’s. Some people get used to it, others faint and stay unconscious during the entirety of acceleration. I could already put you in deep sleep if you want but —”</p>
<p>“Don’t worry about it,” the doctor interrupts, “I have had proper high-g training a year ago. I’ll be fine.”</p>
<p>I have to admit, the doctor doesn’t disappoint me. He is prepared. Meanwhile the technicians have already started to load the new injections, they are efficient.</p>
<p>“Like I told you, I’ll need those coordinates before powerup, ideally when we’re leaving here. We’re navigating the Oort cloud at near-lightspeed, so the autopilot will need some time to calculate the best path.”</p>
<p>“I’ll share them with you as soon as we’ve undocked.” The doctor assures me.</p>
<p>“Ok, next step is to explain the first days of our journey and deep sleep, you might not —”</p>
<p>The airlock beeps again, someone’s at the door. I float downstairs and am surprised to see the valet with two armed guards as the airlock slides open.</p>
<p>“Any problems?” I ask. They haven’t finished refueling yet.</p>
<p>“As a matter of fact, sir. There is. The payment of the gentleman traveling with you triggered a problem while processing. It turns out your client is wanted by the UN, so I’m sorry to inform you that he will have to come with us.”</p>
<p>The guards and valet are still standing in the docking tunnel, so I have no more than two seconds to make a decision before they enter the ship. I only need one second though. I reach to the upper right corner of the airlock where the emergency disconnect button is located. In an instant, the docking port slides shut and we disconnect from the station. There’s a loud bang and the doctor shouts my name. I rush upstairs.</p>
<p>“Strap in.”</p>
<p>“What happened?”</p>
<p>“Strap in!” I repeat.</p>
<p>The four technicians are floating in front of the ship, making haste to get back to the station. The right outrigger has hit the station, but doesn’t seem to have suffered any damage, at least as far as I can tell. I RCS to back out as fast as I can and turn around. I trust forward into higher orbit.</p>
<p>“What happened?” The doctor asks again when we’ve cleared the station.</p>
<p>“You’re wanted by the UN! That happened. Most likely there’s a USN patrol on their way to intercept us, and those will be more heavyweight than the shuttles that chased us on Earth. I’m going to prepare for full powerup, once we’ve cleared Mars.”</p>
<p>“Wait, they weren’t done refueling yet!”</p>
<p>“I know, we’ve got 14 out of 20 injections. I’m afraid your trip has been canceled.”</p>
<p>“No that can’t be!” The doctor exclaims, for the first time seeming to lose his calm.</p>
<p>“Look, we can’t make the trip you wanted to, but we can still skip a century. Let’s hope the UN will have lost interest in us by then.”</p>
<p>“No, you don’t understand! There’s only one chance of going to the place we’re going to, and that’s now. A hundred year delay won’t work!”</p>
<p>“Doc, I’m sorry, we tried, but it didn’t work out. Unless you want to spend probably the rest of your life in jail, you’ll have to let go of your plans.”</p>
<p>“Wait, you said we’ve had 14 injections, right? That’s enough for a one-way trip, right?”</p>
<p>“I wanna go back, doc! I’m not going to give my life for your mission!”</p>
<p>“No, you don’t understand. You can get back. Ok look, I’ll tell you where we’re going, but you can already prepare the powerup?”</p>
<p>“I’m doing that anyway, start talking!”</p>
<p>“The holotype message contained coordinates somewhere in the Oort cloud. We did as much research as we could on it from Earth, and discovered a cluster of meteorites that could potentially contain tachyonium. We sent an expedition to it three years ago: two near-lightspeed capable ships that have been setting up camp within that region of space. There’s much more to tell you about them, but I’ll tell you when we’ve got more time. My mission is to join them. Both ships have antimatter reactors on board, you can refuel when we’re there!”</p>
<p>I take a moment to let the doctor’s words sink in.</p>
<p>“You have set up camp in the Oort cloud to mine meteorites?”</p>
<p>“We’ve been doing much more, but please, let’s hurry. Will you take me there?”</p>
<p>I still haven’t figured out whether to trust the doctor with my life or not. He continues without waiting for my reply. “You haven’t had any reason to distrust me! I’ve helped you every step of the way. I have every reason to want you to succeed, because if you don’t, I don’t either. Please.”</p>
<p>“Sure but you only need me to succeed halfway!”</p>
<p>“No, because we need your ship! I promise you, I’ll explain everything to you when we’re on our way, and you will get back home, please trust me.”</p>
<p>This seems to be one of those pivotal, life-altering moments where every choice seems to be the wrong one. I glance at Mars on the dashboard. I’ve never even set foot on it, but in this moment, with the prospect of traveling half a lightyear away, it feels as close to home as Earth. My life probably won’t be the same ever again.</p>
<p>I curse.</p>
<p>“Ok, doc, give me the coordinates.”</p>
 ]]></summary>

                <updated>2024-08-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.4 at least ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-84-at-least"/>

                <id>https://www.stitcher.io/blog/php-84-at-least</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>When I open sourced <a href="https://github.com/tempestphp/highlight">tempest/highlight</a>, people asked me why PHP 8.3 was the minimum required version. I tend to be pretty strict in only supporting the latest PHP versions, and I'm gonna do it again for Tempest itself: I've published the <a href="https://tempest.stitcher.io/intro/roadmap">framework's roadmap</a> yesterday, and made it clear that Tempest will require PHP 8.4 at the minimum.</p>
<p>I'm anticipating some questions about that decision, so I wanted to write down my thoughts. I've got three reasons for setting such a strict version requirement.</p>
<h2 id="1.-the-longer-we-wait,-the-bigger-the-break"><a href="#1.-the-longer-we-wait,-the-bigger-the-break" class="heading-anchor">#</a> 1. The longer we wait, the bigger the break</h2>
<p>Whether you're building a framework, a package, or work on any kind of open source code: you'll never be in the same unique position again as right when you're starting out. You have a clean slate, you can do whether you want without worrying about anyone being affected by it.</p>
<p>With PHP 8.4 coming, PHP will change pretty significantly, especially with <a href="/blog/new-in-php-84#property-hooks-rfc">property hooks</a>. If I ever want to include property hooks in Tempest, the best time is now, because introducing them into already established interfaces is a huge breaking change. Honestly, I'm dreading the moment where I have to go through all of Tempest's interfaces, and refactor probably half of the methods there to property hooks. Nevertheless, it's better to do it now, and to do the work myself, rather than postponing it another year or two, and impacting everyone.</p>
<p>There won't ever be a moment as good as now to embrace PHP 8.4, it will only get more difficult the longer we wait.</p>
<h2 id="2.-pushing-the-community"><a href="#2.-pushing-the-community" class="heading-anchor">#</a> 2. Pushing the community</h2>
<p>I've made this argument before: open source PHP maintainers have a collective responsibility to <a href="/blog/a-storm-in-a-glass-of-water">push the community forward</a>. Upgrades aren't as scary as they used to be, and we're missing out on performance improvements, security fixes, and new syntax, all because of the fear of upgrades.</p>
<p>In my opinion, staying up to date with modern PHP versions is part of the job. Everyone should charge their clients for it, and do the work.</p>
<h2 id="3.-a-natural-filter"><a href="#3.-a-natural-filter" class="heading-anchor">#</a> 3. A natural filter</h2>
<p>My last reason might seem counterintuitive at first: I'm pushing PHP 8.4 for Tempest (and 8.3 when <code>tempest/highlight</code> was released) to deliberately slow the adoption rate. Don't I want these projects to be successful? Sure. But I'm also limited on time. Imagine tagging the first Tempest release with 8.3 or even 8.2 support; there would probably be a lot more people trying it out, and there likely would be a much bigger inflow of bug reports. That in itself isn't bad, but I reckon a lot of people would play around with it for five minutes, run into edge cases, and then throw it away.</p>
<p>I'm limiting the initial audience to a smaller group, a group that — in general — makes more effort to upgrade PHP sooner and doesn't necessarily expect everything to work flawlessly in v1.</p>
<hr />
<p>So yeah, those are my reasons. You might not agree with them, in which case I'd love to hear your thoughts! Send me <a href="mailto:brendt@stitcher.io">an email</a> or join <a href="https://discord.gg/pPhpTGUMPQ">the Tempest Discord</a>!</p>
 ]]></summary>

                <updated>2024-08-13T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Timeline Taxi: chapter 5 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/timeline-taxi-chapter-05"/>

                <id>https://www.stitcher.io/blog/timeline-taxi-chapter-05</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
<p><a href="/blog/timeline-taxi-chapter-04">Read the previous chapter.</a></p>
<p>“Maybe we should have a proper talk then?” The doctor suggests after we’ve settled in the cockpit where I told him the trip to Mars will take around 10 days. He did remarkably well during our escape, but it seems he got through it on pure adrenaline and needs to decompress now. His hands are shaking, but he’s holding up. He could probably use the distraction of a talk. Fair enough.</p>
<p>“Ah,” he says after I tell him everything that happened over the past 24 hours, “I didn’t know they had their eyes on you. Otherwise I would have warned you when we met.”</p>
<p>“That might have spared me a very embarrassing hour or two…” I reply.</p>
<p>“Ok so, I reckon you’re totally clueless about what happened these past years on Earth, right?”</p>
<p>“I guess so, between spending seven years away from Earth and being dragged naked into a police station, I haven’t had much time to catch up… What happened?”</p>
<p>“Well, ISTRA, of course. But that’s only the result of a much bigger movement. I should probably tell you a bit about my field of study first.”</p>
<p>“Definitely.” I lean back in my seat and stare outside into the darkness. “Go ahead.”</p>
<p>“12 years ago, a small anomaly was observed at night in the UK, near Sheffield. A super bright flash of light in the sky, most people assumed it was a comet of some sorts. And indeed it was: a small comet the size of a melon. It was recovered by scientists shortly after it fell. Maybe you know, maybe you don’t, but comets these days aren’t all that uncommon. We recover close to a hundred sizable ones every year in the UK alone. Most of them are tested for rare materials, and processed accordingly. The same happened with this particular comet.”</p>
<p>“Yeah I’ve heard of more and more comet strikes during the past couple of decades. Is it really worth the effort?”</p>
<p>“In some cases it is. Most comets only contain common materials, but some can be processed for gold, cobalt, platinum, and silver — in significant amounts. With today’s processing technologies, the yield is worth the effort. Now, this particular comet was different though. Long story short, it contained an unknown element, and that’s where the Sheffield Institute of Space Travel finds its origin — specifically to research this one comet.</p>
<p>At first, I was recruited together with a team of two other scientists to do testing on this newly found material. Interestingly enough, the more tests we did on it, the more we realized it didn’t adhere to the laws of physics as we know them. As an experiment, we heated a small sample of the comet to observe how it behaved under high temperatures. Nothing happened. The next day, we wanted to conduct the same experiment again so we recalibrated our measuring equipment and prepared for another test run. During that calibration, the equipment picked up all sorts of particle activity around the sample. We assumed this was a very delayed reaction to our previous experiment, so we noted the time and delay, reheated the sample, and came back the day after. Nothing happened. We were puzzled about this and brainstormed possible theories for these inconsistent observations. Eventually we decided to retry the same experiment later that day, with two different sets of equipment. However, when setting up the new tools, they again picked up activity from yesterday’s experiment, now with what seemed to be a longer delay. Throughout the next few days, we kept running experiments and taking measurements. The timings never lined up and for days we weren’t able to find an answer for this odd behavior.</p>
<p>That is, of course, until we noticed a pattern. Our measurements seemed to always occur at a random time after each experiment, but they did occur on a fixed time before the next experiment. Always one hour before we heated the sample again.</p>
<p>Now, this of course makes no sense. How could an experiment we were going to do, influence the measurements of a past experiment? We did more test runs, but each time we moved the sample so that we had a more accurate understanding of which observation belonged to which experiment. It turned out that the past experiment had nothing to do with it. Each observation was consistent with the position of where the sample would be next. To make sure there weren’t any biases, we’d have one team observe the readouts, while another team, those who hadn’t seen the readouts, would move the sample. Next we experimented with changing the temperature. Slight changes to it seemed to influence the delay. The more we heated the sample, the earlier its readout could be observed. Again we had a blind team moving the sample at a random point in time to prevent any biases.</p>
<p>All of this experimentation led to a conclusion: we believed we had discovered tachyons.”</p>
<p>I know enough physics to raise my eyebrows. I have heard of tachyons before— particles that travel faster than the speed of light. “So the result of each experiment was measured before the experiment was done?” I repeat, just to let those words sink in.</p>
<p>“Exactly.”</p>
<p>“So you mean the experiment went… back in time?”</p>
<p>“I wouldn’t put it like that, no; but we can say the experiment’s results were observed without being constrained by the natural flow of time.”</p>
<p>“But, I believe tachyons were proven not to exist, weren’t they?”</p>
<p>“Well, it was never proven they don’t exist. However, their existence would lead to paradoxes, and their behavior would be inconsistent with our current laws of physics. However, no one managed to prove without a doubt they don’t exist.”</p>
<p>“So we’re talking time travel stuff?”</p>
<p>“I would be hesitant applying the term time travel because it has so many nuances and paradoxes that would distract from proper research. Here’s an example. One experiment was about making an observation, and then deliberately placing the sample in the wrong spot, so that the observation could not have taken place — to create a paradox.”</p>
<p>“What happened?”</p>
<p>“Nothing. We weren’t able to pick up any reading. It makes sense, since we never actually put the sample in the right place. If we relied on a blind placement team once again, the readings only worked if they placed it in the spot we were observing. It seemed to be consistent.”</p>
<p>“So then what?”</p>
<p>“Well eventually we concluded that we didn’t discover tachyons.”</p>
<p>“Huh?”</p>
<p>“Tachyons were theorized centuries ago as some kind of particle that travels faster than light. In theory that could mean they would be able to send information back in time, which is what we were observing.</p>
<p>However, we discovered three distinct kinds of particles, all exhibiting the same behavior, albeit with subtle differences between them. So tachyons isn’t an accurate term. We’re also not sure whether the material we discovered is the source of these particles, or merely a carrier for them. On top of that, we can’t be certain whether they travel faster than the speed of light or not, because we simply cannot observe that. We can only observe a side effect that is theorized to be consistent with tachyon behavior. We did call the host material tachyonium, though. It seemed fitting.”</p>
<p>“What happened next?”</p>
<p>“Well after months of experimentation, we noticed something peculiar. We observed one of our tachyonium samples to emit what seemed to be controlled flashes of particles. What struck us the most, was that this particular sample was the so-called holotype sample: it was the first sample extracted from the meteorite that was used to determine that this was in fact an unknown element. We never touched it afterwards, let alone experiment on it. Now, all our samples were constantly measured, including the holotype. It was meant to be used as a baseline, since we never experimented on it, so it should never show activity. Safe to say, it doing so with a very distinct pattern — it grabbed our attention.</p>
<p>The very distinct pattern also seemed to be more deliberate than just a random occurrence, it kept repeating. It seemed as if the holotype was trying to communicate some sort of message. So we gathered the data over the course of several weeks until we noticed full repetition. We interpreted that data as binary information, and to our astonishment, it indeed included a message.”</p>
<p>“What — who…” I stumble for words.</p>
<p>“We don’t know, and we can only guess. My best guess is that future-us, or someone in the future, decided to send a message back in time via that sample. Since it’s the holotype specifically, it’s natural to assume that it was us, although we cannot confirm that.”</p>
<p>“What did the message say?”</p>
<p>“It included very helpful information about tachyonium that moved our research forward.”</p>
<p>“Hang on a second. So future you sent a message to past you, which influenced the situation of past you. Doesn’t that mean that future you would have never sent any information at all? Isn’t that something like the grandchild paradox?”</p>
<p>“The grandfather paradox, and our situation is most commonly described as the bootstrap paradox where information or an object which is needed to make time travel possible, comes into existence thanks to time travel, which causes a circular dependency, hence time travel cannot be created.</p>
<p>Now, I agree with you that this is paradoxical, but the fact is that it happened. We have no way of communicating with the future us, since tachyonium only allows one-way communication into the past. Future us also never disclosed any information about who or what they are so we can only guess about their motivations, though I assume they tried to limit the possibility of paradoxes as much as possible.”</p>
<p>“But it’s still a paradox, it cannot be.”</p>
<p>“Well, look at it from our reference point: we obtained information from an external party, all is fine, time just moves on with that newly acquired information. The paradox only impacts the future reference point. What happened to them after the paradox was created? Will they simply stop existing? Will there be an alternate version of the future, a branch, so to speak? We don’t know. And I don’t think we can ever know. The only thing we can observe is that the same message kept repeating over and over again even until today. So that’s an argument for the alternate future still existing somewhere.”</p>
<p>“Alternate — you mean like a multiverse?”</p>
<p>“Not really. For a multiverse you’d need multiple material copies of the same universe, I don’t believe that’s the case here. We’re only talking about time that’s alternating. That’s one dimension, not the other three. If we assume that time is an infinite dimension that we cannot perceive from our point of view, but one that’s there nevertheless; then we might have found a way to navigate a small part of that dimension using tachyonium. We’re not changing anything, we’re only experiencing one slice of that time dimension, and we’re moving through slices whenever a paradox is created. So don’t think of it as multiple universes, think of it as multiple timelines within the same physical universe.”</p>
<p>“Well I grant it to you doc, your story is way more interesting than mine.”</p>
<p>He smiles and stares out the window for a moment.</p>
<p>“Our stories might actually be more intertwined than you think,” he continues. “Did you notice how those shuttles after takeoff mentioned that both the ship wasn’t authorized to launch, and the pilot is a wanted criminal or something alike? Yeah I don’t think them chasing us is only about you having helped criminals with your taxi services. I believe it’s about your ship.”</p>
<p>“What about my ship?” I doubt it has much impact on all of this.</p>
<p>“See, ISTRA is what made it possible for you to be prosecuted, but ISTRA itself is one of the measurements taken to prevent our research. After three years of experimentation and research, we presented our findings to a special board of UN and USN members. They concluded that we weren’t allowed to continue it any further. On top of that, they created ISTRA to prevent us from bringing this research into the practical field.”</p>
<p>“How does ISTRA prevent you from doing so?”</p>
<p>“Simple. By discouraging or prohibiting near-lightspeed travel, we cannot get to the one place we need to be for our next breakthrough.”</p>
<p>“At a random spot in deep space?”</p>
<p>“At a very specific spot within the Oort cloud, 31000 AU away, give or take.”</p>
<p>I already knew we were traveling far, but it’s only right now that I realize how far. The Oort cloud… that’s huge. “What are you going to do there?”</p>
<p>“If you’re ok with it, I’ll keep that information to myself until we’ve left Mars and are on our way. I also won’t give you the coordinates of where we’re traveling to, until we’re ready to go for real.”</p>
<p>Once again, the doctor makes me feel uncomfortable. He’s asking to put a lot of trust in him. What is in it for me? I grimace as I’m reminded about my fate if I were to go back to Earth, which I seemed to have forgotten for a minute while the doctor was explaining all his science to me.</p>
<p>“Look,” he says, when he notices my worries, “I don’t think I’ve given you any reason to doubt my intentions. I’ve told you everything I can at this point, and I’m more than happy to provide all the financial means needed to get us refueled and on our way. Once we’re ready to go, I’ll give you access to the bank account containing your full payment — which you can check and transfer up front, if you want to. You can still abort the mission at that point if you decide you can’t trust me, but I cannot take the risk of telling you where we’re going or what I’ll do there before we’re certain we’ll get there. I hope you understand”</p>
<p>I nod. It makes sense, the doctor has a way of swaying my doubts the moment he addresses them.</p>
<p>“I’m ok doc. Thanks for being as open as you can. Give me some time to let everything sink in. I think I’ll be fine.”</p>
<p>“Good. Feel free to ask any questions you have. If I can answer them at this stage, I will.”</p>
<p>I stare out the cockpit window. The stars look fabulous. Our journey won’t even make it halfway to our nearest neighboring star. That’s how big space is. It makes me feel insignificant, but that’s not a bad thing right now. The less eyes on me, the better.</p>
 ]]></summary>

                <updated>2024-08-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ I don&#039;t write code the way I used to ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/i-dont-code-the-way-i-used-to"/>

                <id>https://www.stitcher.io/blog/i-dont-code-the-way-i-used-to</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I turned 30 last week, and it made me realise I've been coding for more than half of my life now. I took a moment to reflect on my programming skills after a decade, and realised that 20-year-old me would probably facepalm if he'd seen my write code today.</p>
<p>First, I <strong>gave up on most abstractions</strong>. Oh, how young-me loved them. For present-me, abstractions are becoming more and more of a rarity. I just find that 95% of problems don't need abstractions, they are better to be solved in place. I remember I reached for abstractions whenever a problem could <em>possibly</em> need it, instead of when I <em>actually</em> needed it. I don't do that anymore.</p>
<p>Second, I find myself liking a <strong>functional mindset</strong> more and more. It's just simpler. I find it comfortable to split data and functionality, to keep my code as flat as possible. I'm still using classes and objects and their internal state, but overall these objects are looking more and more like functions: data goes in, data comes out. That's it.</p>
<p>Something I'm less proud of: <strong>testing is still a struggle</strong>. I don't really understand why. I <em>know</em> testing makes my life easier. I <em>know</em> it's good in the long run. And still, there's always a barrier to cross. In part, I think it's because of the friction and overhead that comes with testing frameworks, the setup, mocking, faking data, … It's really a shame that testing doesn't come more natural to me. I force myself to do it — and it always pays off — but still…</p>
<p>Next, I'm using <strong>less fancy shorthands</strong>. I don't care about clever oneliners anymore. I'd prefer to write a verbose if/else statement over cramming the same functionality in one line of code. Less is not always more.</p>
<p>Another realisation: I <strong>can't live without static analysis</strong> anymore. I remember using Sublime for the first 2 or 3 years of my professional programming career, but I don't understand how I made that work. Have I become lazy? Too reliant on my tools? I don't think so. I think I've optimised my toolchain to serve me better over the years. Let the computer do the boring things for me, I'll focus on the things I like.</p>
<p>Finally, <strong>I'm still using PHP</strong>. It has its quirks, it's old, it shows, I know. And yet… it's ok, it gets the job done. In fact, I like the language much more today than a decade ago. I think the past ten years have been great for PHP.</p>
<p>Here's to the next ten 🍻!</p>
 ]]></summary>

                <updated>2024-08-07T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Timeline Taxi: chapter 4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/timeline-taxi-chapter-04"/>

                <id>https://www.stitcher.io/blog/timeline-taxi-chapter-04</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
<p><a href="/blog/timeline-taxi-chapter-03">Read the previous chapter.</a></p>
<p>My initial plan is to refuel in Lunar orbit at one of the Gateway stations. With fully loaded engine injectors, we’ll be able to make the one lightyear journey just fine. The distance doesn’t matter all that much: as soon as the ship is traveling at near-lightspeed, it only requires a marginal amount of energy to keep its momentum. It’s the speeding up and slowing down to and from near-lightspeed that requires most fuel. For our journey, we’ll have to do the procedure twice: once traveling to the coordinates specified by the doctor, and once traveling back to Earth. Most taxis aren’t equipped with enough fuel capacity to do two consecutive full powerups and slowdowns, which is one of the reasons the doctor is so keen on traveling with me specifically.</p>
<p>Unfortunately, my initial plan won’t work. If Earth spaceports are already aware of my “wanted” status, it means there’s no chance we can dock at any official Lunar Gateway station. Luckily, there are the unofficial Lunar stations, run by individual companies. Oftentimes they are involved in shady business. They now seem to be our only chance of obtaining a full refuelment. It will cost a buttload of money, and I’m not even sure we’ll be able to dock anywhere. But, we’ll have to figure it out in Lunar orbit, because right now I need to focus on docking the shuttle to my ship and prepare for powerup.</p>
<p>We’re currently half an hour away from our rendez-vous point, and another problem already poses itself. Several problems, actually, if you count each of them individually: three shuttles launched 10 minutes after our takeoff, and they left little doubt as to their intentions:</p>
<p>“Taxi LT-22 Shuttle, this is UNJ-6, we urge you to stop your ascent and return to Earth immediately. Your ship wasn’t authorized to launch, and the pilot is to be apprehended immediately. Return to Earth, or offensive measures will be taken.”</p>
<p>I don’t worry — at least not more than I already did — it isn’t a lost cause yet. These shuttles can only be class-B patrol shuttles, given how fast they were launched after our departure. At full acceleration, they can’t keep up with us. However, they might be able to intercept us when we’re docking, which takes about 15 minutes, 10 if I’m pressured on time; and believe me, I am. Still, 10 minutes might be just enough for them to reach an acceptable interception range, which means they could fire at us at will. I’m unsure what kind of weapons these patrol shuttles are equipped with specifically. We might be able to take a couple of hits, but I would rather not put that to the test.</p>
<p>So, time is of essence. If we can dock, powerup, and leave within 10 minutes, we’re good. At least until we arrive in Lunar orbit. I drive the shuttle to max speed, nearing the limit of what’s safe this close to Earth, but maybe I can gain another minute or two.</p>
<p>The doctor knows exactly what to do in a tense situation such as this one: to say nothing. He doesn’t even look at me, and I’m thankful for that; we’re coming in on the ship, I have a visual, and I need to concentrate. It has a pretty unique design: two outriggers extend from the main ship, the outriggers house the engines and fuel injections, while the main part has the cockpit and cargo hold. It also has two docking ports: one up front, and one at the back. We’re coming from behind, so we’ll dock with the rear port, making sure I’m perfectly centered between the outriggers so that I don’t damage them. The question is: how much do I slow down before docking — or, in other words: can I find the balance between “a bumpy, yet successful dock”, or “slamming into my spaceship and die”. I rather have the first option, so I err on the side of safety, albeit by a slim margin.</p>
<p>Our relative velocity is still pretty fast: 5 meters per second, but I might be able to make it work. I keep half an eye on the clock as I’m using the sticks to guide the shuttle not-so-gently towards its goal.</p>
<p>“Remote connection established” comes up on the shuttle’s main dashboard. I tap the screen three times in the right places without even looking at it. It makes the ship start the powerup procedure remotely. That’ll save us two more minutes. I slow down to 3 meters per second because this is just way too fast. I notice a slight twitch in my hands as I grab the sticks again, a side effect of the adrenaline surging through my veins. We’re 15 meters out. 12. 9. 7. 5. 4. 3. 2. 1.</p>
<p>A huge tremor. In a reflex, the doctor startles and swings his arms trying to grab hold of something. Luckily he’s strapped in tight. We didn’t dock, but bumped. Distance is 2 meters. 3. 4. I give some more power. 4. 4. 3. 2. 1. Another bump, less powerful this time.</p>
<p>“Docking success” I feel another surge of adrenaline as I see that message pop up on the dashboard. Good, but there’s no time to celebrate. I leave the doctor strapped in, and launch myself towards the airlock beneath the shuttle’s control panel. It opens and I make way into the ship. I can navigate my ship blindly, so I make it through the cargo bay to the cockpit in no time. “Powerup 89%” the dashboard shows. Just enough time to set the right course.</p>
<p>“Of course it couldn’t have been that easy,” I mumble as I check available orbital maneuvers for the Moon. The closest window requires an almost full additional orbit around Earth, which is more than enough time for the shuttles to intercept us. That won’t work. Venus would be ideal: there’s a huge community of smugglers there — Venus is a Space Pirate haven. But it’s too far. We don’t have enough fuel to make it. Mars is within reach. But Mars… I don’t want to go to Mars. There’s so much risk of getting caught by officials in Martian orbit — the United Space Nations headquarters is on Mars. There is very little room for missteps there.</p>
<p>“98%”</p>
<p>It's our only chance. Mars it is. I set the course, just in time for powerup to complete. This isn’t a full powerup, mind you. A full powerup is required for near-lightspeed travel, but we don’t need near-lightspeed to get to Mars.</p>
<p>“Autopilot engaged”</p>
<p>We’re off. Our velocity is increasing and for a moment I feel the g-forces pressuring me in my seat. It doesn’t take long before the g-shields kick in, and pressure is back to normal. We’ve escaped. Just like that. I smile, big time. I did it. At least, the first step. I look at Earth’s projection on the dashboard and can’t help but feel that familiar feeling whenever I set out on a new trip. Earth is home, but it also isn’t. From Earth’s perspective, I’ve spent way more time on this ship than over there. But from my point of view, even though she changes with every trip, and even though it’s hard to resettle time and time again; she is home.</p>
<p>“See you soon”, I say to myself as the globe grows smaller and smaller. I startle from my thoughts as I remember: I need to get the doctor.</p>
 ]]></summary>

                <updated>2024-08-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Improved lazy loading ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/improved-lazy-loading"/>

                <id>https://www.stitcher.io/blog/improved-lazy-loading</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm writing an ORM. I know, it'll probably drive me insane. Why am I doing it? In part because of the interesting challenge. In part because I've been building a <a href="https://github.com/tempestphp/tempest-framework">framework</a> for the past two years. And today, I want to share a small part of the design process. It's these kinds of details that I like most about programming: figuring out what the public API will look like, facing challenges, and fixing them.</p>
<p>Whether you plan on using Tempest or not, whether you plan on writing your own framework one day or not, I think you'll find what comes next interesting and inspiring!</p>
<h2 id="setting-the-scene"><a href="#setting-the-scene" class="heading-anchor">#</a> Setting the scene</h2>
<p>First, let's talk about the core characteristics of this ORM. It's important to understand the challenges I ran into later on. First, I find static analysis important — really important. That's why I want typed properties to be the core of Tempest's design.</p>
<p>I prefer to start with the end goal — the user-facing code — in mind, so I drafted something like this as a Tempest model class:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Book</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable|null</span> <span class="hl-property">$publishedAt</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$author</span>,
        /** <span class="hl-value">@var</span> <span class="hl-type">Chapter[]</span> <span class="hl-variable">$chapters</span> */
        <span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$chapters</span>,
    </span>) {}
}
</pre>
<p>Note how we're not doing any manual relationship configuration. In fact, it's one of the key characteristics of Tempest to be smart enough to reduce as much config as possible. The <code><span class="hl-type">Author</span></code> type of the <code><span class="hl-variable">$author</span></code> property is enough to determine that this is a <code>belongs to</code> relation, the <code><span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">Chapter[]</span> <span class="hl-variable">$chapters</span> */</span></code> docblock on <code>$chapters</code> is enough to know this is a <code>has many</code> relation. Yes, I know docblocks suck. Let's hope PHP gets typed arrays one day. Why a docblock and not an attribute? Well we need the docblock anyway if we want proper type analysis on the property — my core requirement — so it would only make people's lives more difficult if they had to add an attribute <em>on top of</em> a docblock:</p>
<pre><span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">Chapter[]</span> <span class="hl-variable">$chapters</span> */</span> <span class="hl-comment">// Meh</span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">HasMany</span>(<span class="hl-type">Chapter</span>::<span class="hl-keyword">class</span>)]</span></span> <span class="hl-comment">// Even more meh</span>
<span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$chapters</span>,
</pre>
<p>Another important design decision in Tempest is that model classes aren't directly tied to the database. You <em>can</em> load model classes from a database if you want to, but they could also be persisted to a JSON file, a Redis store, XML, whatever you can think of. Granted: your average app will persist most of its models to a database, so there is a trait in Tempest to help you with that:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Book</span> <span class="hl-keyword">implements</span><span class="hl-type"> Model
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsModel</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable|null</span> <span class="hl-property">$publishedAt</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$author</span>,
        /** <span class="hl-value">@var</span> <span class="hl-type">Chapter[]</span> <span class="hl-variable">$chapters</span> */
        <span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$chapters</span>,
    </span>) {}
}
</pre>
<p>(Note to self: I still have to rename the interface and trait to <code><span class="hl-type">DatabaseModel</span></code>)</p>
<p>Anyway, those are models. Let's talk about lazy loading next.</p>
<h2 id="lazy-loading"><a href="#lazy-loading" class="heading-anchor">#</a> Lazy loading</h2>
<p>Let's say you retrieve a book from the database (this <code><span class="hl-property">find</span>()</code> method is provided by that <code><span class="hl-type">IsDatabaseModel</span></code> trait):</p>
<pre><span class="hl-variable">$book</span> = <span class="hl-type">Book</span>::<span class="hl-property">find</span>(<span class="hl-variable">$id</span>);
</pre>
<p>By default, it won't load relations like <code>$author</code> and <code>$chapters</code>. Think about it: in this example it wouldn't be a biggy to load two relations, but what happens if each <code>$chapter</code> has a backreference to the book? And each <code>$author</code> has an array of its books as well? Or, what if an author has a relation to a <code>$publisher</code>, which has a list of all books published, … will you always load <em>all</em> relations? No, that wouldn't be very performant, and even if it would be performant enough, it would need a lot of — wasted — memory. That's why, by default, Tempest doesn't load relations. In case you <em>need</em> a relation to be loaded, you'll have to specifically say so:</p>
<pre><span class="hl-variable">$book</span> = <span class="hl-type">Book</span>::<span class="hl-property">query</span>()-&gt;<span class="hl-property">with</span>('<span class="hl-value">author</span>')-&gt;<span class="hl-property">find</span>(<span class="hl-variable">$id</span>);
</pre>
<p>This is no different from what Laravel does by the way: it also doesn't load relations up front unless you specifically tell the framework to do so (this mechanism is called "eager loading"). However, Tempest goes one step further. If you happen to access a relation that's not loaded, Tempest won't load it for you behind the scenes. Instead, it will throw an error:</p>
<pre><span class="hl-variable">$book</span> = <span class="hl-type">Book</span>::<span class="hl-property">find</span>(<span class="hl-variable">$id</span>);

<span class="hl-variable">$book</span>-&gt;<span class="hl-striped"><span class="hl-property">author</span></span>; <span class="hl-comment">// MissingRelation</span>
</pre>
<p>This is different from Laravel, and a very deliberate decision. In Laravel, Eloquent will lazily load missing relations for you by default. So if the relation isn't currently loaded, Laravel will perform an additional query on the fly to retrieve it for you. This again doesn't seem like a big deal in an isolated example, but let's say we're looping over an <em>array</em> of books instead:</p>
<pre>&lt;<span class="hl-keyword">div</span> :<span class="hl-property">foreach</span>=&quot;<span class="hl-variable">$this</span>-&gt;<span class="hl-property">books</span> <span class="hl-keyword">as</span> <span class="hl-variable">$book</span>&quot;&gt;
    {{ <span class="hl-variable">$book</span>-&gt;<span class="hl-property">title</span> }} by {{ <span class="hl-variable">$book</span>-&gt;<span class="hl-property">author</span>-&gt;<span class="hl-property">name</span> }}
&lt;/<span class="hl-keyword">div</span>&gt;
</pre>
<p>Sidenote: the syntax you're seeing here is part of my work in progress <a href="https://tempest.stitcher.io/framework/03-views">view engine for Tempest</a> — yes, I'm also writing a view engine besides an ORM.</p>
<p>Back to the problem with lazy loading: if we didn't load <code>$author</code> up front, lazy loading would perform a <em>separate</em> query for <em>every</em> book in the array. This is the infamous n+1 problem, and it's one of the most common performance issues in Laravel. I can't remember how many hours I spent chasing and fixing n+1 issues in Laravel applications. It often had impact production app performance by seconds, and often required hours of debugging and fixing. Remember that, in real life, model schemes are much more complex than a simple <code>belongs to</code> relation, which means that solving n+1 issues is often more complex than to "eagerly load everything", which would lead to serious memory issues in some cases. It really is a time sink.</p>
<p>Now, Laravel has addressed this issue in part a year or two ago: you can now <a href="https://laravel-news.com/disable-eloquent-lazy-loading-during-development">disable lazy loading manually</a>. By default, Laravel still lazily loads everything, but good for them acknowledging the issue and providing an easy way of disabling it. By doing so, you're getting forced to think about these problems up front, instead of trying to fix them when they pop up.</p>
<p>I'm not here to dis Laravel by the way; I love Laravel, and I totally understand the decision to make lazy loading the default. Starting from scratch though, I have a opportunity to rethink the pain points I experienced with Laravel, and so I decided on another approach: lazy loading is off by default, but you can turn it on manually for specific properties. It looks like this:</p>
<pre><span class="hl-attribute">#[<span class="hl-type">Lazy</span>]</span> <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$author</span>,
</pre>
<p>Personally, I like these defaults better: nothing is lazily loaded, unless you specifically say so. It does require a programmer to micromanage which relations are loaded up front — true — but let me tell you, the same happens in Laravel as soon as you have an app whose model scheme is somewhat larger than two or three <code>belongs to</code> relations. I just did a quick search in the codebase of <a href="https://github.com/brendt/rfc-vote">RFC Vote</a>, built with Laravel. It's not even a big app, and we're already manually loading relations in ten different places to prevent n+1 issues.</p>
<pre><span class="hl-keyword">return</span> <span class="hl-type">Rfc</span>::<span class="hl-property">query</span>()
    -&gt;<span class="hl-property">with</span>(['<span class="hl-value">arguments</span>', '<span class="hl-value">yesArguments</span>', '<span class="hl-value">noArguments</span>'])
    <span class="hl-comment">// …</span>
    -&gt;<span class="hl-property">get</span>();
</pre>
<p>So, that's the theory. How do you make this work in PHP? That's where things get fascinating.</p>
<h2 id="just-a-tiny-bit-of-hacking"><a href="#just-a-tiny-bit-of-hacking" class="heading-anchor">#</a> Just a tiny bit of hacking</h2>
<p>Back to our initial example, the <code><span class="hl-type">Book</span></code> model:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Book</span> <span class="hl-keyword">implements</span><span class="hl-type"> Model
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsModel</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable|null</span> <span class="hl-property">$publishedAt</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$author</span>,
        /** <span class="hl-value">@var</span> <span class="hl-type">Chapter[]</span> <span class="hl-variable">$chapters</span> */
        <span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$chapters</span>,
    </span>) {}
}
</pre>
<p>Let's say we build and perform a query to select all relevant fields (everything besides the relations). We retrieve that data as an array, and map that array onto the object. This is what such an object would look like after that mapping has been done:</p>
<pre><span class="hl-type">Book</span> {
    <span class="hl-property">title</span>: '<span class="hl-value">Timeline Taxi</span>',
    <span class="hl-property">publishedAt</span>: <span class="hl-keyword">null</span>,
    <span class="hl-property">author</span>: <span class="hl-keyword">uninitialized</span>,
    <span class="hl-property">chapters</span>: <span class="hl-keyword">uninitialized</span>, 
}
</pre>
<p>The interesting parts here are the <code>unitialized</code> properties: typed properties that haven't been initialized yet. We didn't load relations, so we didn't initialize those properties. Don't worry if you don't know how to do that in PHP — we'll come back to it.</p>
<p>Now, because of how PHP works, uninitialized properties don't throw any errors after constructing an object. In other words, you can perfectly construct an object with uninitialized properties. PHP will only check and throw errors on uninitialized properties when you try to <em>read</em> them. It's perfectly fine to build an object via reflection without calling its constructor (we'll come back to that).</p>
<p>This means we can keep the relation's type itself clean (remember that core requirement?) We don't need to make its type nullable or provide another kind of "special value" for relations. <em>If</em> PHP didn't have an uninitialized property state, we'd have to resort to doing something like this to mark relations as optional:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Book</span> <span class="hl-keyword">implements</span><span class="hl-type"> Model
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsModel</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        // Allow a union on a special &quot;missing relation&quot; type:
        <span class="hl-keyword">public</span> <span class="hl-type">Relation|Author</span> <span class="hl-property">$author</span>,

        // Making the relation nullable would be an option as well:
        /** <span class="hl-value">@var</span> <span class="hl-type">Chapter[]</span> <span class="hl-variable">$chapters</span> */
        <span class="hl-keyword">public</span> <span class="hl-type">?array</span> <span class="hl-property">$chapters</span>,
    </span>) {}
}
</pre>
<p>Now I don't know about you, but I like to write as little code as possible, especially if the framework can do the work for me. On top of that, I like to keep my type definitions clean, and not make them unions or nullable just because of a technical requirement. That's why I like embracing the uninitialized state.</p>
<p>Sidenote about that: once again I wish we had generics in PHP, in which case we could probably do something like this:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(
    <span class="hl-keyword">public</span> <span class="hl-type">BelongsTo&lt;<span class="hl-generic">Author</span>&gt;</span> <span class="hl-property">$author</span>,

    <span class="hl-keyword">public</span> <span class="hl-type">HasMany&lt;<span class="hl-generic">Chapter</span>&gt;</span> <span class="hl-property">$chapters</span>,
)
</pre>
<p>Anyway, that's just me dreaming out loud, it'll <a href="/blog/generics-in-php-3">probably never happen</a>.</p>
<p>So, what's next? We need a way to execute some checks when a user tries to access this uninitialized property. Easy enough, right? PHP has a magic method, <code><span class="hl-property">__get</span>()</code> that will trigger every time you access a non-existing property on an object. That should be easy, right?</p>
<pre><span class="hl-keyword">trait</span> <span class="hl-type">IsModel</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__get</span>(<span class="hl-injection"><span class="hl-type">string</span> $name</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-variable">$property</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionProperty</span>(<span class="hl-variable">$this</span>, <span class="hl-variable">$name</span>);

        <span class="hl-comment">// If this property is allowed to lazy load, load it </span>
        <span class="hl-keyword">if</span> (<span class="hl-property">attribute</span>(<span class="hl-type">Lazy</span>::<span class="hl-keyword">class</span>)-&gt;<span class="hl-property">in</span>(<span class="hl-variable">$property</span>)-&gt;<span class="hl-property">exists</span>()) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">load</span>(<span class="hl-variable">$name</span>);

            <span class="hl-keyword">return</span> <span class="hl-variable">$property</span>-&gt;<span class="hl-property">getValue</span>(<span class="hl-variable">$this</span>);
        }

        <span class="hl-comment">// Otherwise, throw an exception</span>
        <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">MissingRelation</span>(<span class="hl-variable">$this</span>, <span class="hl-variable">$name</span>);
    }
}
</pre>
<p>Well… nope. That doesn't work. Wanna know why? Trying to access an uninitialized property on a class <em>doesn't trigger</em> <code><span class="hl-property">__get</span>()</code>! Why — you wonder? Because the property we're trying to access <em>does</em> in fact exist, it simply isn't initialized yet. So instead of triggering <code><span class="hl-property">__get</span>()</code>, PHP will throw an error:</p>
<pre>Fatal error: Uncaught Error: Typed property Book::$author 
must not be accessed before initialization
</pre>
<p>You didn't think it was gonna be so easy, did you? This is PHP, after all 😅 Now, luckily, there is a way around this! This is PHP, after all. 😎</p>
<p>To explain the workaround though, I'll need to first explain how model objects are created. I already mentioned they are constructed without triggering the constructor. That's done via reflection. Let's assume we have this array of items — the result of our initial <code><span class="hl-keyword">SELECT</span></code> query:</p>
<pre>[
    '<span class="hl-value">title</span>' =&gt; '<span class="hl-value">Timeline Taxi</span>',
    '<span class="hl-value">publishedAt</span>' =&gt; <span class="hl-keyword">null</span>,
]
</pre>
<p>Tempest has a class <code><span class="hl-type">ArrayToObjectMapper</span></code>, which knows how to transform this data into an object (it can also do this with nested properties, etc, but let's keep it simple for this example). From the outside, it looks something like this:</p>
<pre><span class="hl-variable">$book</span> = <span class="hl-property">map</span>(<span class="hl-variable">$query</span>)-&gt;<span class="hl-property">to</span>(<span class="hl-type">Book</span>::<span class="hl-keyword">class</span>);
</pre>
<p>Now, this is what happens behind the scenes: the mapper will create an object of <code><span class="hl-type">Book</span></code>, without calling its constructor, it will then loop over all public properties, and it will set those property values to what's present in the input array (the <code>$query</code> data):</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">ArrayToObjectMapper</span> <span class="hl-keyword">implements</span><span class="hl-type"> Mapper
</span>{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">map</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $from, <span class="hl-type">mixed</span> $to</span>): <span class="hl-type">object</span>
    {
        <span class="hl-variable">$reflection</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$to</span>);
        
        <span class="hl-variable">$object</span> = <span class="hl-variable">$reflection</span>-&gt;<span class="hl-property">newInstanceWithoutConstructor</span>();
        
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$class</span>-&gt;<span class="hl-property">getProperties</span>(<span class="hl-type">ReflectionProperty</span>::<span class="hl-property">IS_PUBLIC</span>) <span class="hl-keyword">as</span> <span class="hl-variable">$property</span>) {
            <span class="hl-keyword">if</span> (! <span class="hl-property">array_key_exists</span>(<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getName</span>(), <span class="hl-variable">$from</span>)) {
                <span class="hl-keyword">continue</span>;
            }
            
            <span class="hl-variable">$property</span>-&gt;<span class="hl-property">setValue</span>(<span class="hl-variable">$object</span>, <span class="hl-variable">$from</span>[<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getName</span>()]);
        }
    }
}
</pre>
<p>Now, this is a simplification of <a href="https://github.com/tempestphp/tempest-framework/blob/main/src/Tempest/Mapper/Mappers/ArrayToObjectMapper.php">what's really happening</a>, but it's enough to understand how we're going to hack PHP &lt;insert delirious laugh here&gt;!</p>
<p>I might be overhyping it a bit though, since it's just one line of code. Remember that we want <code><span class="hl-property">__get</span>()</code> to trigger on properties that aren't initialized. In other words, we want <code><span class="hl-property">__get</span>()</code> to trigger on properties that didn't have a value present in the <code>$from</code> array.</p>
<p>Turns out you can do exactly that, even for properties that aren't initialized, by manually unsetting the property, like so:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">map</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $from, <span class="hl-type">mixed</span> $to</span>): <span class="hl-type">object</span>
{
    <span class="hl-variable">$reflection</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$to</span>);
    
    <span class="hl-variable">$object</span> = <span class="hl-variable">$reflection</span>-&gt;<span class="hl-property">newInstanceWithoutConstructor</span>();
    
    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$class</span>-&gt;<span class="hl-property">getProperties</span>(<span class="hl-type">ReflectionProperty</span>::<span class="hl-property">IS_PUBLIC</span>) <span class="hl-keyword">as</span> <span class="hl-variable">$property</span>) {
        <span class="hl-keyword">if</span> (! <span class="hl-property">array_key_exists</span>(<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getName</span>(), <span class="hl-variable">$from</span>)) {
            <span class="hl-addition"><span class="hl-keyword">unset</span>(<span class="hl-variable">$object</span>-&gt;{<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getName</span>()});</span>
            
            <span class="hl-keyword">continue</span>;
        }
        
        <span class="hl-variable">$property</span>-&gt;<span class="hl-property">setValue</span>(<span class="hl-variable">$object</span>, <span class="hl-variable">$from</span>[<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getName</span>()]);
    }
}
</pre>
<p>Indeed, by <em>unsetting</em> a property, even though it was never initialized, and even though it exists in the class definition, will make PHP think it doesn't exist, and trigger <code><span class="hl-property">__get</span>()</code>! 🎉</p>
<p>This makes it so that we can use typed properties (promoted or not, both will work), without having to make them nullable or anything else. Tempest will be able to hook into unloaded properties via <code><span class="hl-property">__get</span>()</code>, which means we can add support for lazy loading, and we can throw proper errors whenever a user accesses a property that wasn't loaded.</p>
<p>Beautiful, isn't it? Of course, it would be much easier if there was a magic method that hooked into uninitialized property access; but that, we don't have. Luckily PHP wouldn't be PHP if there wasn't some obscure workaround for it, and that's exactly what we've done!</p>
<p>That's about all I wanted to share today. Next up my list is supporting eager loads — basically <em>always</em> loading a relation, even if you didn't specify it manually. Shouldn't be difficult though.</p>
<p>By the way, I just read through the lazy objects RFC, which might make all of this much easier in PHP 8.4!</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/rwp8_eWLDv8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>Leave your thoughts in the comments down below! Oh and, if you're wondering about that book title I used in the examples, you can read about it here: <a href="https://stitcher.io/blog/timeline-taxi-chapter-01">https://stitcher.io/blog/timeline-taxi-chapter-01</a>.</p>
 ]]></summary>

                <updated>2024-07-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ It&#039;s all just text ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/its-all-just-text"/>

                <id>https://www.stitcher.io/blog/its-all-just-text</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>If you think about it, most programming challenges can be boiled down to one or two things: text processing and data mapping.</p>
<p>Let's see: I'm currently improving <a href="https://github.com/tempestphp/tempest-framework/">Tempest's ORM</a>, which means nothing more than "generating the right queries (text processing), and mapping the data unto objects".</p>
<p>I while ago, I wrote a <a href="https://github.com/tempestphp/highlight">code highlighter</a>. It's basically the definition of text processing. I also built a <a href="https://tempest.stitcher.io/console/01-getting-started">console framework</a>, which is nothing more than processing an incoming command (which is text), and generating the appropriate output (which is text). Routing? Processing an HTTP request (text), map its data to a controller, and eventually return text again. Building a template engine? Text processing.</p>
<p>Especially with programming languages like PHP, within a web context; 99% of things we're doing is processing text and moving data from one point to another. I like that realization, because it means I can boil down what seem to be the hardest problems, into relatively simple pieces. I wanted to share that with you, maybe you have some additional thoughts? You can leave a comment to let me know!</p>
 ]]></summary>

                <updated>2024-07-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Timeline Taxi: chapter 3 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/timeline-taxi-chapter-03"/>

                <id>https://www.stitcher.io/blog/timeline-taxi-chapter-03</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
<p><a href="/blog/timeline-taxi-chapter-02">Read the previous chapter.</a></p>
<p>“Jonathan Russel speaking,” the voice on the other end of the phone says.</p>
<p>“Is your offer still standing?” I ask him directly. He doesn’t need any other explanation.</p>
<p>“Of course, did you change your mind?”</p>
<p>“Can you meet me in an hour in Yokohama spaceport?”</p>
<p>“Sure can.”</p>
<p>“I’ll meet you at gate A44, that’s within the non-commercial section. I’ll see you there.”</p>
<p>I hang up. On my walk of shame back to the hotel, I decided there was no way I’d spend two years in prison. So the only option left is to do what I usually do: fix Earth problems by leaving Earth. Sure, half a lightyear back and forth is a little bit over the top, but there’s no way I can find another client on such short notice who’s willing to pay what doctor Russel pays. And I will need the money a hundred years from now. It’s not ideal, but it’s way better than two years in prison and being broke afterwards.</p>
<p>I pick up the phone again and dial the other number.</p>
<p>“This is Wakato.”</p>
<p>“Wakato, hi. There’s a change of plan, I need to leave as soon as possible, don’t ask any questions, I’ll explain later. How’s the ship?”</p>
<p>“Post-flight maintenance has been done, everything’s checked, sir. Refueling is scheduled within two days. Apart from that I’m looking into the kitchen upgrades you mentioned.”</p>
<p>“Yeah, we’ll have to scratch those upgrades I’m afraid. Can you prepare the shuttle and load it with enough rations?”</p>
<p>“I can sir, but can I ask what’s going on?”</p>
<p>“I’ll tell you when I’m at the spaceport, I’ll be there in less than an hour.”</p>
<p>“Sir, do you want me to ration the shuttle within the hour?” Wakato asks, surprised.</p>
<p>“If possible, yes.”</p>
<p>“That’ll be difficult —”</p>
<p>I interrupt him: “Can you do it?”</p>
<p>He pauses for a second.</p>
<p>“I can, sir.”</p>
<p>“I’ll see you in an hour.”</p>
<p>I hang up and make my bag. I don’t know how much freedom is involved in “having a week to get things in order”, so I’m not sure if I’ll even make it to the spaceport. I figure the faster I go, the better.</p>
<p>I rush out of the hotel, get a cab, and make it race to the spaceport. My bag in hand I run past the travel gates into the non-commercial section. I’m fifteen minutes early, so I don’t expect doctor Russel to have arrived yet, but there he stands, in front of gate A44.</p>
<p>In surprise, I blurt out “you’re fast!”</p>
<p>“I’m not fast, I’m prepared.” he replies.</p>
<p>“Hang on. Do you know what's going on?”</p>
<p>Now he looks at me, surprised. “I’m not sure what you mean? You called me, so here I am. I just meant that I didn’t need to pack anything, I had everything already in order. What happened then?”</p>
<p>I shake my head. “Later, we need to hurry.”</p>
<p>“Well I’m not that much in a hurry, I’m sorry if I gave you the impression I was. A couple of days of preparation time would have been fine.”</p>
<p>“Obviously <em>I</em> am in a hurry. I’ll tell you later. Let’s get to the shuttle. Do you have everything you need with you?”</p>
<p>He points towards two large bags in front of the gate. “Is there enough room for those?”</p>
<p>“That should work.”</p>
<p>I lead the doctor through gate A44, straight onto the shuttle fields. Wakato’s there, frantically directing two technicians who are rationing the shuttle.</p>
<p>“Sir!” he exclaims when he sees me. “Are you ok?”</p>
<p>“Wakato, I’m glad to see you! Let’s talk in a minute. This is doctor Russel, he’ll be my next client. Could you load his bags into the hold while I set him up in the shuttle?”</p>
<p>Wakato has a confused look, but smiles and takes the doctor’s bags without any questions. I lead the doctor into the shuttle, and set him up in the main passenger’s seat.</p>
<p>“Are you ok waiting here for a couple of minutes? I need to check some final things with my valet.”</p>
<p>I exit the shuttle and pull Wakato aside. I tell him what happened in the police station only a couple of hours ago. He looks at me in disbelief.</p>
<p>“I’m so sorry sir, if I had known that gentleman inquiring about you last year was a cop, I would have never told him anything!”</p>
<p>“Don’t worry about it, Wakato, even if you hadn’t told them anything, they would still know when I returned based on the public flight records. There’s nothing you could have done to prevent this. How’s the fuel situation? I know we can’t do a full powerup right now, but can I make it into Lunar orbit?”</p>
<p>“Yes, that should work perfectly. You can even reach Mars, but going any further would be too risky.”</p>
<p>I nod. Lunar orbit should do.</p>
<p>“I have to say, sir, I should have told you about ISTRA right upon your arrival, but I know you like a couple of days off before getting up to speed, and I figured it wouldn’t be this time pressing…”</p>
<p>“I don’t think it would have made a difference, Wakato. Those people knew I was here as soon as I contacted Earth upon my return. I’m surprised they weren’t here to meet me right on the spaceport. Probably because I made a last-minute change to my landing schedule.”</p>
<p>“So… you’re leaving for a hundred years then?”</p>
<p>“I’m afraid so. I’m lucky this client was here in the right place and time. No room for me to get picky, I'm afraid.”</p>
<p>“That means then…”</p>
<p>“I’m afraid so, Wakato San. I’m afraid so.”</p>
<p>We look at each other for a moment in silence. I extend my hand and shake his.</p>
<p>“Thank you for all your help these past decades. You’ve been the best valet I’ve ever worked with. You know I mean that.”</p>
<p>He bows. I bow in reply.</p>
<p>“Well, no more time to waste. I hope we manage to take off, otherwise we might see each other again in half an hour.”</p>
<p>The technicians have just finished loading the rations, and I make it back into the shuttle. Doctor Russel is waiting patiently and smiles when he sees me again.</p>
<p>“Everything ok?” he asks.</p>
<p>“Everything will be ok.” I reply. “I’ll tell you all about it once we’re on our way, but now we need to lift off.” I sit in the pilot seat, and perform all preflight checks in silence.</p>
<p>“Yokohama, Tower, this is Taxi LT-22, come in.”</p>
<p>“Taxi LT-22, this is Yokohama, Tower, we copy you.”</p>
<p>“Requesting permission for stationary departure, currently standing at gate A44, destination orbit lane A44, section D.”</p>
<p>“Copy, stand by.”</p>
<p>Silence as my heart throbs in my throat.</p>
<p>“Taxi LT-22, this is Yokohama, Tower. Permission not granted, I repeat: permission for stationary departure not granted.”</p>
<p>I curse. I usually don’t, but today I do. I look at the doctor’s puzzled face.</p>
<p>“Yokohama, Tower, copy that, permission not granted. Can you tell me the reason?”</p>
<p>“Taxi LT-22, your shuttle has been flagged for government inspection and is not allowed to leave the spaceport until further notice.”</p>
<p>I curse again. I turn to the doctor.</p>
<p>“So, doc. I need to tell you something.” I give him the short version of what happened. He listens patiently, without interruptions. When I’m done, I wait for him to reply.</p>
<p>“So, to be clear.” He replies. “My mission is absolutely crucial, not just for theoretical science, it will have a huge impact on the future of space travel in general. I came here looking for you, since you’re the only pilot we could find after two years of searching who’s able to make this journey. You noticed I came here immediately after you called me, that’s because I’ve been ready to go at any given moment for a while now.”</p>
<p>He pauses, as if he’s thinking about the best way to phrase this.</p>
<p>“Look, I’ve given everything for this research the past five years. It’s my life’s work, and I don’t care about the consequences in this current time. If I want this research to succeed, I need to gap half that lightyear. So, as far as I’m concerned, I’m fine to do whatever it takes to get there.”</p>
<p>I look at him in silence. If I’m doing this, I’m taking a huge bet on someone who’s practically a random stranger. I haven’t had the time to properly vet him as I usually do with my clients. I haven’t had the time to properly overthink the consequences of bridging a hundred Earth years. I don’t even know how he’ll be able to pay me a hundred years from now. But what’s the alternative? Prison and being broke afterwards.</p>
<p>I curse, one last time.</p>
<p>“Yokohama, Tower, be advised, proceeding with unauthorized stationary takeoff from gate A44. Please make way.”</p>
<p>“Taxi LT-22, permission not granted, I repeat, permission NOT granted.”</p>
<p>I hear a faint siren in the distance, but it’s quickly overturned by the sound of the engines.</p>
<p>“Hold on, doc.”</p>
<p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
 ]]></summary>

                <updated>2024-07-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Timeline Taxi: chapter 2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/timeline-taxi-chapter-02"/>

                <id>https://www.stitcher.io/blog/timeline-taxi-chapter-02</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
<p><a href="/blog/timeline-taxi-chapter-01">Read the previous chapter.</a></p>
<p>Doctor Jonathan Russel from the Sheffield Institute of Space Travel stands out indeed, dressed in a typical brown English raincoat, a hat, a small bag in one hand, and an umbrella — an umbrella of all things — in the other.</p>
<p>“Where did you think you’d travel to?” I ask him with a sarcastic smile.</p>
<p>“Oh it was raining in the UK when I boarded the plane, I had almost no time to prepare, so here I am.”</p>
<p>The doctor smiles and I have to admit, he seems like a genuinely pleasant person at first sight.</p>
<p>“Would you like to sit, have a drink perhaps?” He proposes as he holds a chair for me. The hotel’s lounge is crowded, noisy even. I don’t like it here.</p>
<p>But we sit down, I order my usual, the doctor orders coffee, which I find odd for an Englishman.</p>
<p>“It’s been a long flight,” he tells me when I ask about it.</p>
<p>“So, how about we skip the smalltalk?” He continues.</p>
<p>I think I like this man.</p>
<p>“On the phone I told you I’m a doctor at the Sheffield Institute of Space Travel. Have you heard of it?”</p>
<p>I shake my head.</p>
<p>“Naturally,” he continues. “The institute was founded five years ago, so it makes sense that you haven’t heard of it, I believe you were still traveling back then.”</p>
<p>I nod. This doctor seems to know a lot of things about me…</p>
<p>“We’re concerned with the theoretical and practical study of space travel and everything related to it. I particularly, am working on a study about possible ways of dealing with time dilation — a concept you’re fairly familiar with, I reckon; given that you’ve made it into your job.“</p>
<p>I nod without interrupting.</p>
<p>“Now, part of my study involves a practical test, flying to a specific point in space, and back. I’m looking for a pilot.”</p>
<p>Well that’s all still pretty vague if you ask me, I’m still not sure what the doctor actually does, and why is he talking to me? There are plenty of UK taxi pilots. No need to come to me.</p>
<p>“Look, I just came back from a trip, and plan to stay for a year or two. If you want to, we can schedule a trip two years from now, but I’m sure you’ll find other taxis that are available to leave earlier.”</p>
<p>“Well, here’s the problem. No other taxi pilot wants to take me.”</p>
<p>“Well that’s not a good way to sell yourself, doc!” I exclaim as I lay back in my chair and sip my glass.</p>
<p>“Oh it’s nothing bad though, it’s just that… See, this place I want to travel to is — well — it’s far.”</p>
<p>“How far?”</p>
<p>“Slightly more than half a lightyear away.”</p>
<p>I whistle as I sit up straight again, my glass still in my hand but I’m not sipping it anymore. “Yeah that’s not gonna happen, doc! That’s what — more than a year of travel time back and forth, so a hundred years of Earth Time. No way any pilot wants to make such an investment.”</p>
<p>“I was told you do long trips though, longer than usual trips.“</p>
<p>“I do,” I hesitate to say while I’m thinking about how to end this conversation — no way I’m going to travel that far — “but not a hundred Earth years! 30, 40 years, maybe? The longest trip I ever did was 43 years. But let me tell you: that was no fun coming back. No way I’m doing a hundred!”</p>
<p>“What if I told you that price wouldn’t be a problem? And, sure, such a big time gap is huge, but you’ve now bridged, what, 500 years in total?”</p>
<p>“453,” I correct him.</p>
<p>He’s quick with his reply: “Well in total that’s significantly more than a hundred!”</p>
<p>“How do you know so much about me? And what kind of price are we talking about when you say it isn’t a problem?” Ok, I can’t help being a little bit intrigued.</p>
<p>“Four times your normal rate. But I’m allowed to bargain up to six times, so let’s just say six.”</p>
<p>The doctor’s smart. He ignored my first question and distracted me with a huge pile of money instead. I look at him in silence for a moment.</p>
<p>“No, I won’t do it,” I conclude after a moment and intense staring from the doctor’s side. “There’s too much risk, half a light year, that’s — that’s huge, it’s too much.”</p>
<p>The doctor looks at me, disappointed, but I can also see a level of understanding in his eyes.</p>
<p>“So,” he says after having thought it over for a while, “if you find yourself doubting that decision in the coming days, would you be so kind as to give me a call? You can reach this number,” and he slips me a business card of some sorts.</p>
<p>“I’m pretty sure I won’t,” I say as I grab the card and slide it into a pocket, soon to be forgotten. I get up, shake his hand, and leave him at the bar. Time for my bath. I make it up to make room, undress — again — as I refill the bath, I slide into the hot water, and close my eyes. Bliss.</p>
<p>A while later — I’m not sure how much later — I’m woken from my slumber by a loud knock on the door. I can hear someone shout my name in the distance. I hear a loud bang as I sit up half confused, and two seconds later the bathroom door swings open. Two cops grab me from the bathtub. They don’t care about me being naked, they grab a towel, wrap it around my waste, and drag me down the hallway. In total bewilderment, I just let it happen.</p>
<p>It’s only when I’m sitting in the cop’s car that I get a chance to gather my thoughts. “Hey!” I shout towards the cops in the front of the car, “what’s going on?” My wrists hurt, I was handcuffed right before I was pushed into the car. The cops ignore me.</p>
<p>“Hey!” I shout again. No answer. I kick the seat in front of me. No answer. I kick it again, not expecting an answer but simply out of anger. I’m driven to what I suppose is the police station, though I’m not familiar enough with Yokohama to be sure. It looks boring and official. It could be a police station.</p>
<p>The cops lead me down the hallway — dressed only with a towel around my waste, mind you. Somewhere along the hallway, they stop at a random door, open it, and lead me in. They remove my handcuffs as I sit down on one of the two chairs in the room. “What is going on?” I demand once more. No answer. They both exit the room and the lock clicks shut.</p>
<p>I look around. What is this place? Is this an interrogation room? I’ve only seen them in detective series. It looks like an interrogation room. With the two chairs, the table in between, the mirror glass. Yeah, this is an interrogation room. “Hey!” I shout again, but there’s only silence. It probably takes no more than ten minutes — but it feels like an hour — when suddenly the door clicks and swings open. I look startled as a tiny man walks in. He smiles faintly, puts down a huge stack of papers on the table, and sits in front of me.</p>
<p>“Do you have any idea why you’re here?” He asks without introducing himself.</p>
<p>“No”, I snap, “who are you?”</p>
<p>“You’re a taxi pilot, is that correct?” The man continues and ignores my question.</p>
<p>“I am, who are you?”</p>
<p>“Are you aware of the International Space Travel Regulations Act of ‘91?” He continues, flipping through some of the papers without looking up.</p>
<p>“‘91? That’s what? Three years ago? No, I was traveling back then. I just arrived back and haven’t had a chance to catch up with everything. Who are you?” I ask once more. “What am I doing here?”</p>
<p>Still, he ignores my question.</p>
<p>“I figured.” He mumbles. “The International Space Travel Regulations Act — ISTRA — was signed by all UN countries three years ago. It details all regulations concerning space travel, including providing taxi services to convicted or suspected criminals. Something you aren’t unfamiliar with, are you?”</p>
<p>He looks up now, I stare at him. He seems to enjoy this moment.</p>
<p>“The interesting part about this law is that it acts retroactively up to 300 years.”</p>
<p>He pauses for dramatic tension. I decide to not give him the satisfaction and continue to stare with a puzzled gaze. Not receiving the hoped reaction, he sighs, then continues.</p>
<p>“So, you’ve been doing a lot of traveling, haven’t you?”</p>
<p>“I do.”</p>
<p>“Well, let me cut to the chase” he seems to have already lost his patience. ”You were reprimanded for many of your taxi travels, including the most recent one with a certain individual called mr. Tunaki. You’ve had a trial and,”</p>
<p>“Hang on,” I say, “a trial?”</p>
<p>“Like I said, a trial, a little over a year ago. We actually tried to contact you via your valet but it seems that you were unavailable at that time. Section C of ISTRA mentions that after three failed attempts at communication with a suspect, we’re allowed to charge that person in absens — that’s Latin — meaning there’s an immediate trial. If, during that trial, said suspect still isn’t able to provide any rebuttal, the charges are automatically accepted.”</p>
<p>The cop stops reading from what I assume is a printout of section C of the so-called “International Space Travel Regulations Act”. He looks at me. I can’t say anything.</p>
<p>“Anyway,” he concludes, “you’ve been convicted on all accounts. Since you weren’t available at the time of sentencing you’ve received a suspended sentence, as well as a fine. This last one will be automatically collected from your bank account now that you have been informed about the sentence. Any questions?”</p>
<p>I look at him in disbelief.</p>
<p>“Well,” I stammer, “why did you abduct me out butt naked from my hotel room?” It’s the only reasonable question I can come up with, I’m still processing the rest.</p>
<p>“Sure. ISTRA section C also outlines the procedure for dealing with absent suspects or convicts upon their resurfacing. They are to be informed immediately, or as soon as possible, about their current situation. This is of course meant to protect the rights of each suspect, or, in your case, convict.” He smiles when he says “convict”.</p>
<p>“So what, a fine?”</p>
<p>“Yes, well, the fine was set on, let me check, 1.2 million Earth Dollars, since you’re an Earth Dollar Bank client, we can automatically collect this charge from your account, which will happen as soon as you leave this office.”</p>
<p>“But, you can’t do that!” I shout. I want to stand up but realize just in time that my towel might drop… so I stay seated.</p>
<p>“As a matter of fact, sir, I can, and I have. The charge has already been prepared and will be automatically deducted once you leave this office.”</p>
<p>I can’t say anything. 1.2 million is almost the whole of my capital. But the cop doesn’t stop there.</p>
<p>“As to your suspended sentence, you’ll still have to serve it. The judge ordered, let me check, 2 years in prison. We won’t arrest you right now, because we want to allow you to get your business in order before serving your sentence. You have a week where you’re not allowed to leave the city, your passport has been invalidated, and together with the fine charge, all access to your bank account will be blocked until you’ve served your sentence. You’re to report next week, Monday, at 7 AM in Yokohama General Prison. If you fail to report there on time, you’ll be arrested and your sentence will automatically be prolonged by a year. At least, that’s what the judge’s order says. Any questions?”</p>
<p>I just stare into nothingness. Less than an hour ago, I was having a bath, now I’m a convicted criminal. I’m out of money and I’ll have to serve two years in prison.</p>
<p>“No? Ok, then you’re free to go, until next week, of course.”</p>
<p>The cop smiles, stands up, walks to the door and unlocks it with some kind of wristband sensor. Another cop walks in, drags me up — I’m just in time to grab my towel — and leads me out. I’m handed a folder of papers while walking out, my file with all necessary information, and that’s it. I’m on the street in front of the police office. In a towel.</p>
<p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
 ]]></summary>

                <updated>2024-07-19T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ array_find in PHP 8.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/array-find-in-php-84"/>

                <id>https://www.stitcher.io/blog/array-find-in-php-84</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8.4 adds a handful of functions that have been missing for a while: <code><span class="hl-property">array_find</span>()</code> and its variants. The purpose of <code><span class="hl-property">array_find</span>()</code> is simple: pass it an array and a callback, and return the first element for which the callback returns true.</p>
<pre><span class="hl-variable">$numbers</span> = [1, 2, 3, 4, 5, 6];

<span class="hl-variable">$firstMatch</span> = <span class="hl-property">array_find</span>(
    <span class="hl-property">array</span>: <span class="hl-variable">$numbers</span>, 
    <span class="hl-property">callback</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">int</span> $number</span>) =&gt; <span class="hl-variable">$number</span> % 2 === 0
);
</pre>
<p>To start off with, I want to make a note on naming conventions: in Laravel, the function that returns the first element from an array that matches a callback is called <code><span class="hl-type">Collection</span>::<span class="hl-property">first</span>()</code> instead of <em>find</em>. This might cause some confusion for people expecting <code><span class="hl-property">array_find</span>()</code> to return <em>all</em> elements that match the callback's condition.</p>
<p>The decision for <code><span class="hl-property">array_find</span>()</code> over <code><span class="hl-property">array_first</span>()</code> isn't all that weird though: lots of languages implement a method to find the <em>first matching</em> element from an array, and those functions are always called <em>find</em>. Just to name two examples: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find">JavaScript</a> and <a href="https://doc.rust-lang.org/rust-by-example/fn/closures/closure_examples/iter_find.html">Rust</a>.</p>
<p>If you need a way to get <em>multiple elements</em> from the array based on a callback, then the <code><span class="hl-property">array_filter</span>()</code> function is what you're looking for.</p>
<pre><span class="hl-variable">$numbers</span> = [1, 2, 3, 4, 5, 6];

<span class="hl-variable">$allMatches</span> = <span class="hl-property">array_filter</span>(
    <span class="hl-property">array</span>: <span class="hl-variable">$numbers</span>, 
    <span class="hl-property">callback</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">int</span> $number</span>) =&gt; <span class="hl-variable">$number</span> % 2 === 0
);
</pre>
<p>Another important thing to note is that <code><span class="hl-property">array_find</span>()</code>, as well as the three other functions (we'll look at those later in this post), they accept both the value <em>and</em> key as arguments in the callback function:</p>
<pre><span class="hl-variable">$firstMatch</span> = <span class="hl-property">array_find</span>(
    <span class="hl-property">array</span>: <span class="hl-variable">$array</span>, 
    <span class="hl-property">callback</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">mixed</span> $value, <span class="hl-type">int|string</span> $key</span>) =&gt; <span class="hl-comment">/* … */</span>
);
</pre>
<p>By the way, you can read with me through the RFC to learn about all the details:</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/yuCTnlEUJ4c" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="array_find_key"><a href="#array_find_key" class="heading-anchor">#</a> array_find_key</h2>
<p>Besides <code><span class="hl-property">array_find</span>()</code>, there's now also a function called <code><span class="hl-property">array_find_key</span>()</code>. It does exactly the same, but returns the key instead of the value of the matched element:</p>
<pre><span class="hl-variable">$numbers</span> = [1, 2, 3, 4, 5, 6];

<span class="hl-variable">$firstMatchedKey</span> = <span class="hl-property">array_find_key</span>(
    <span class="hl-property">array</span>: <span class="hl-variable">$numbers</span>, 
    <span class="hl-property">callback</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">int</span> $number</span>) =&gt; <span class="hl-variable">$number</span> % 2 === 0
);
</pre>
<h2 id="array_any-and-array_all"><a href="#array_any-and-array_all" class="heading-anchor">#</a> array_any and array_all</h2>
<p>Finally, there are two related functions added, these two will return a boolean instead of a value. <code><span class="hl-property">array_any</span>()</code> will return <code><span class="hl-keyword">true</span></code> if at least one element within the array matches a callback's condition, while <code><span class="hl-property">array_all</span>()</code> will return <code><span class="hl-keyword">true</span></code>, <em>only</em> if <em>all</em> elements match the callback's condition:</p>
<pre><span class="hl-variable">$numbers</span> = [1, 2, 3, 4, 5, 6];

<span class="hl-comment">// True: at least one element is dividable by 2</span>
<span class="hl-property">array_any</span>(
    <span class="hl-property">array</span>: <span class="hl-variable">$numbers</span>,
    <span class="hl-property">callback</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">int</span> $number</span>) =&gt; <span class="hl-variable">$number</span> % 2 === 0
);

<span class="hl-comment">// False: not all elements are dividable by 2</span>
<span class="hl-property">array_all</span>(
    <span class="hl-property">array</span>: <span class="hl-variable">$numbers</span>,
    <span class="hl-property">callback</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">int</span> $number</span>) =&gt; <span class="hl-variable">$number</span> % 2 === 0
);

<span class="hl-comment">// True: all elements are smaller than 10</span>
<span class="hl-property">array_all</span>(
    <span class="hl-property">array</span>: <span class="hl-variable">$numbers</span>,
    <span class="hl-property">callback</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">int</span> $number</span>) =&gt; <span class="hl-variable">$number</span> &lt; 10
);
</pre>
 ]]></summary>

                <updated>2024-07-18T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What&#039;s new in PHP 8.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-in-php-84"/>

                <id>https://www.stitcher.io/blog/new-in-php-84</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8.4 will be released on <a href="https://wiki.php.net/todo/php84">November 21, 2024</a>. It'll include property hooks, HTML 5 support, as well as chaining methods on <code><span class="hl-keyword">new</span></code> without additional parentheses — a big one!</p>
<hr />
<h3 id="property-hooks-rfc"><a href="#property-hooks-rfc" class="heading-anchor">#</a> Property hooks <small><a target="_blank" href="https://wiki.php.net/rfc/property-hooks">RFC</a></small></h3>
<p>One of the biggest changes in modern-PHP history: the ability to define property hooks, eliminating the need for a lot of boilerplate code.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BookViewModel</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$authors</span>,
    </span>) {}

    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$credits</span> {
        <span class="hl-keyword">get</span> {
            <span class="hl-keyword">return</span> <span class="hl-property">implode</span>('<span class="hl-value">, </span>', <span class="hl-property">array_map</span>(
                <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Author</span> $author</span>) =&gt; <span class="hl-variable">$author</span>-&gt;<span class="hl-property">name</span>, 
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">authors</span>,
            ));
        }
    }
    
    <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$mainAuthor</span> {
        <span class="hl-keyword">set</span> (<span class="hl-type">Author</span> <span class="hl-variable">$mainAuthor</span>) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">authors</span>[] = <span class="hl-variable">$mainAuthor</span>;
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">mainAuthor</span> = <span class="hl-variable">$mainAuthor</span>;
        }
        
        <span class="hl-keyword">get</span> =&gt; <span class="hl-variable">$this</span>-&gt;<span class="hl-property">mainAuthor</span>;
    }
}
</pre>
<p>The goal of property hooks is to remove a lot of getters and setters, by allowing each property to define its own <code><span class="hl-keyword">get</span></code> and <code><span class="hl-keyword">set</span></code> hooks. Hooks are optional, and you don't have to add both of them on a specific property. For example, a property with only a <code><span class="hl-keyword">get</span></code> hook is virtual property.</p>
<p>There is a lot to say about property hooks, and I plan to write a followup post on them soon, so make sure to <a target="_blank" href="/mail">subscribe</a> if you want to know when that one is done. One final thing I'd like to mention — probably what I'm most hyped about: property hooks can be defined in interfaces!</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">HasAuthors</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$credits</span> { <span class="hl-keyword">get</span>; }
    <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$mainAuthor</span> { <span class="hl-keyword">get</span>; <span class="hl-keyword">set</span>; }
}
</pre>
<hr />
<h3 id="new-without-parentheses-rfc"><a href="#new-without-parentheses-rfc" class="heading-anchor">#</a> <code><span class="hl-keyword">new</span></code> without parentheses <small><a target="_blank" href="https://wiki.php.net/rfc/new_without_parentheses">RFC</a></small></h3>
<p>As if property hooks alone wasn't enough, PHP 8.4 has another feature that will save so much boilerplate code: you don't have to wrap <code><span class="hl-keyword">new</span></code> invocations within parenthesis anymore to be able to chain methods on them. So instead of doing this:</p>
<pre><span class="hl-variable">$name</span> = (<span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$objectOrClass</span>))-&gt;<span class="hl-property">getShortName</span>();
</pre>
<p>You can now do this:</p>
<pre><span class="hl-variable">$name</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$objectOrClass</span>)-&gt;<span class="hl-property">getShortName</span>();
</pre>
<p>I don't know about you, but I write a lot of code like this, and so I'm super happy that we're finally getting rid of those brackets. It doesn't only work for methods, by the way. You can also chain properties, static methods, constants — whatever you want. You can read all about this new feature in this <a href="/blog/new-with-parentheses-php-84">dedicated post</a>.</p>
<hr />
<h3 id="jit-changes-rfc"><a href="#jit-changes-rfc" class="heading-anchor">#</a> JIT changes <small><a target="_blank" href="https://wiki.php.net/rfc/jit_config_defaults">RFC</a></small></h3>
<p>PHP 8.4 changes the way the <a href="/blog/php-jit">JIT</a> is enabled. Previously, you had to set <code>opcache.jit_buffer_size</code> to <code>0</code> in order to disable the JIT, but now you can disable it like so:</p>
<pre>opcache.jit=disable
opcache.jit_buffer_size=64m
</pre>
<p>The only way users can be affected by this change is if they did specify a <code>opcache.jit_buffer_size</code> but no <code>opcache.jit</code>. In that case, you'll have to add <code>opcache.jit=tracing</code> to enable the JIT again.</p>
<p>Finally, there have also been some <a target="_blank" href="https://wiki.php.net/rfc/jit-ir">improvements to the JIT</a> which makes it run faster in some cases, and use less memory.</p>
<hr />
<h3 id="implicit-nullable-types-deprecation"><a href="#implicit-nullable-types-deprecation" class="heading-anchor">#</a> Implicit nullable types <small class="breaking"><a href="https://wiki.php.net/rfc/deprecate-implicitly-nullable-types">deprecation</a></small></h3>
<p>PHP had this weird behaviour where a typed variable with a default <code><span class="hl-keyword">null</span></code> value would be made nullable automatically:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">save</span>(<span class="hl-injection"><span class="hl-type">Book</span> $book = <span class="hl-keyword">null</span></span>) {}

<span class="hl-comment">// Deprecated: Implicitly marking parameter $book as nullable is deprecated,</span>
<span class="hl-comment">// the explicit nullable type must be used instead</span>
</pre>
<p>This behaviour is now deprecated and will be removed in PHP 9. The solution is to make <code><span class="hl-type">Book</span></code> explicitly nullable:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">save</span>(<span class="hl-injection"><span class="hl-type">?Book</span> $book = <span class="hl-keyword">null</span></span>) {}
</pre>
<hr />
<h3 id="new-html5-support-rfc"><a href="#new-html5-support-rfc" class="heading-anchor">#</a> New HTML5 support <small><a target="_blank" href="https://wiki.php.net/rfc/domdocument_html5_parser">RFC</a></small></h3>
<p>PHP 8.4 adds a <code><span class="hl-type">\Dom\HTMLDocument</span></code> class which is able to parse HTML5 code properly. The old <code><span class="hl-type">\DOMDocument</span></code> class is still available for backwards compatibility.</p>
<pre><span class="hl-variable">$doc</span> = <span class="hl-type">\Dom\HTMLDocument</span>::<span class="hl-property">createFromString</span>(<span class="hl-variable">$contents</span>);
</pre>
<p>You can read all about the new HTML 5 parser <a href="/blog/html-5-in-php-84">here</a>.</p>
<hr />
<h3 id="array_find-rfc"><a href="#array_find-rfc" class="heading-anchor">#</a> array_find <small><a href="https://wiki.php.net/rfc/array_find">RFC</a></small></h3>
<p>There's a pretty simple new function added in PHP 8.4, one of those functions that you have to wonder about "hang on, wasn't that available yet?" I guess most developers have grown used to third party collection classes, although I think having <code><span class="hl-property">array_find</span>()</code> natively in PHP is pretty nice.</p>
<p>The naming might be a bit confusing though, because what this function does is it takes an array and callback, and will return the <em>first</em> element for which the callback returns <code><span class="hl-keyword">true</span></code>:</p>
<pre><span class="hl-variable">$firstMatch</span> = <span class="hl-property">array_find</span>(
    <span class="hl-variable">$posts</span>, 
    <span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {
        <span class="hl-keyword">return</span> <span class="hl-property">strlen</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span>) &gt; 5; 
    }
);
</pre>
<p>There are also some variations of this function called <code><span class="hl-property">array_find_key</span>()</code>, <code><span class="hl-property">array_any</span>()</code> and <code><span class="hl-property">array_all</span>()</code>, you can <a href="/blog/array-find-in-php-84">read all about them here</a>.</p>
<hr />
<p>PHP 8.4 is still in the development phase, so there's of course more to come. I'll update this post over time, so make sure to <a href="/mail">subscribe</a> if you want to be kept in the loop.</p>
<p>If you want something to watch next, make sure to check out my latest video as well:</p>
<iframe width="560" height="347" src="https://www.youtube.com/embed/CSNpmbUnN6Q" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2024-07-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ HTML 5 support in PHP 8.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/html-5-in-php-84"/>

                <id>https://www.stitcher.io/blog/html-5-in-php-84</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Even though HTML 5 has been around for over 16 years, PHP never had proper support for it. PHP does have <code><span class="hl-type">\DOMDocument</span></code>, which <em>in theory</em> should support HTML 4, but it isn't <em>really</em> HTML 4 compliant anymore.</p>
<p>So, yeah, classic PHP — right 😅? Well, we can laugh all we want, but let's take a moment to highlight new features that — albeit late — fix these quirks: <a href="/blog/new-in-php-84">PHP 8.4</a> is adding an HTML 5 compliant parser! In this post I'll go through the highlights of this new parser, and you can read with me through the whole RFC as well:</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/cjHRWio-c3M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="backwards-compatible"><a href="#backwards-compatible" class="heading-anchor">#</a> Backwards compatible</h2>
<p>One of the core requirements for this new parser is that it should be fully backwards compatible. That's why internals have chosen to make a completely new class — within a new namespace — to house the new HTML 5 parser. The old <code><span class="hl-type">\DOMDocument</span></code> class is left (mostly) alone. The only change in the old implementation is that <code><span class="hl-type">\DOMDocument</span></code> now extends the abstract <code><span class="hl-type">\Dom\Document</span></code> class, which is also the parent for the new, HTML 5 compliant implementation: <code><span class="hl-type">\Dom\HTMLDocument</span></code>.</p>
<p>If you want to use PHP's new HTML 5 parser, that's the one you need:</p>
<pre><span class="hl-comment">// HTML 5 compliant</span>
<span class="hl-variable">$dom</span> = <span class="hl-type">\Dom\HTMLDocument</span>::<span class="hl-property">createFromString</span>(<span class="hl-variable">$html</span>); 
</pre>
<p>While the old version is still available as usual:</p>
<pre><span class="hl-comment">// HTML 4-ish support</span>
<span class="hl-variable">$oldDom</span> = <span class="hl-keyword">new</span> <span class="hl-type">\DOMDocument</span>(); 
<span class="hl-variable">$oldDom</span>-&gt;<span class="hl-property">loadHTML</span>(<span class="hl-variable">$html</span>);
</pre>
<h2 id="constructing-doms"><a href="#constructing-doms" class="heading-anchor">#</a> Constructing DOMs</h2>
<p>One key difference you'll spot immediately is that the new implementation relies on static constructors instead of calling methods on the newly created object afterward. The new <code><span class="hl-type">HTMLDocument</span></code> class has three named constructors available:</p>
<pre><span class="hl-type">HTMLDocument</span>::<span class="hl-property">createEmpty</span>();
<span class="hl-type">HTMLDocument</span>::<span class="hl-property">createFromFile</span>(<span class="hl-variable">$path</span>);
<span class="hl-type">HTMLDocument</span>::<span class="hl-property">createFromString</span>(<span class="hl-variable">$html</span>);
</pre>
<p>These are their full signatures:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">createEmpty</span>(<span class="hl-injection"><span class="hl-type">string</span> $encoding = &quot;UTF-8&quot;</span>): <span class="hl-type">HTMLDocument</span>;
<span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">createFromFile</span>(<span class="hl-injection"><span class="hl-type">string</span> $path, <span class="hl-type">int</span> $options = 0, <span class="hl-type">?string</span> $override_encoding = <span class="hl-keyword">null</span></span>): <span class="hl-type">HTMLDocument</span>;
<span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">createFromString</span>(<span class="hl-injection"><span class="hl-type">string</span> $source, <span class="hl-type">int</span> $options = 0, <span class="hl-type">?string</span> $override_encoding = <span class="hl-keyword">null</span></span>): <span class="hl-type">HTMLDocument</span>;
</pre>
<p>For the <code>$options</code> variable, these options are available:</p>
<ul>
<li>
<code><span class="hl-property">LIBXML_HTML_NOIMPLIED</span></code>
</li>
<li>
<code><span class="hl-property">LIBXML_COMPACT</span></code>
</li>
<li>
<code><span class="hl-property">LIBXML_NOERROR</span></code>
</li>
<li>
<code><span class="hl-type">\Dom\</span><span class="hl-property">NO_DEFAULT_NS</span></code>
</li>
</ul>
<p>The <code>$override_encoding</code> variable is used to override the implicit encoding detection routines as determined by the HTML parser spec. This can be useful when the document is downloaded manually.</p>
<h2 id="dom-objects"><a href="#dom-objects" class="heading-anchor">#</a> DOM Objects</h2>
<p>Note that using the new implementation will result in other types of value objects to be created as well. For example, instead of <code><span class="hl-type">\DOMNode</span></code>, you'll get <code><span class="hl-type">\DOM\Node</span></code>; instead of <code><span class="hl-type">\DOMElement</span></code>, you'll get <code><span class="hl-type">\DOM\Element</span></code>, etc. The RFC originally aimed to keep these objects the same between the old and new implementation, but there turned out to be too many differences. You can read all about them <a href="https://wiki.php.net/rfc/opt_in_dom_spec_compliance">here</a>.</p>
<hr />
<p>Albeit a bit late, I think this is a very nice addition to PHP. I definitely have some usecases for it! What are your thoughts? You can leave them in the comments down below!</p>
 ]]></summary>

                <updated>2024-07-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Timeline Taxi: chapter 1 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/timeline-taxi-chapter-01"/>

                <id>https://www.stitcher.io/blog/timeline-taxi-chapter-01</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
<p>A throbbing pain wakes me up as it shoots from my lower arm up to my shoulder. My first instinct is to reach for whatever’s hurting my arm, but I recover fast enough to know that I shouldn’t. It’s been centuries since the invention of deep sleep, yet we still need pain stimuli to wake from it. Why no one has bothered to come up with a better way than shooting electrochoques through an arm is beyond me. I turn right, mr. Tunaki is still strapped in firmly, deep asleep. Just the way I left him. I turn to the dashboard in front of me, both our vitals are good. Speed is nominal, 0.99995% c. We’re three days worth of travel time out from Earth. All is good. I remove the probe from my arm as I stare into the blueshifted space in front of me. Just the way I left it.</p>
<p>Mr. Tunaki gets another day of deep sleep before waking up. He doesn’t enjoy his pain shock either, but he’s a little more verbal about it. He reaches to his right arm and starts pulling on the probe — I need to pin his left hand to ensure he doesn’t rip his arteries. I’m serious: these probes make a mess when you pull them out uncontrolled. I once had a client who ripped it off as soon as he awoke and it took me three days of cleaning afterwards. Well, it took the valet three days of cleaning, no way I’m doing that myself. But I know the drill: secure their hands, let them curse, let them shout, lull them like a baby. “I understand it’s painful sir, I know it’s confusing. It’ll only take a minute. You’re doing good. You’re doing great, sir.”</p>
<p>The thought of almost being home helps mr. Tunaki to calm down. His crimes expired two Earth years ago, but we figured we would take some margin just to be sure. After all, it’s only a week of travel time for us, so why not? “Two more days,” I tell him as I hand him a bag of dried spinach pasta. 500 years of space travel and we’re still eating the same kind of boring food we’d eat back then. To be fair, I suspect there will be ships with more luxurious life support systems by now. I think I heard they were making significant progress in that area over the past decades. I might need to look into some upgrades. An updated kitchen would be nice. Luckily, mr. Tunaki doesn’t mind the food quality. He gobbles up his bag as if it’s the best meal he ever had. That’s what over 20 days of deep sleep does with a person — it transforms rubbish space food into a feast.</p>
<hr />
<p>“Earth, Ground, this is Taxi LT-22, do you copy?”</p>
<p>“Taxi LT-22, this is Earth, Ground, we copy. Welcome back.”</p>
<p>“Earth, how are things down there? Everything’s still the way I left it?”</p>
<p>“Taxi LT-22, everything’s still good here, how was your trip?”</p>
<p>“All good, Earth, thanks. Glad to be back!. Can you send us our parking procedures? We’ll arrive in about two hours.”</p>
<p>“Taxi LT-22, copy, stand by.”</p>
<p>“Taxi LT-22, you can park in orbit lane A44, section B. You can shuttle down from there to Singapore spaceport.”</p>
<p>“Earth, Ground, thank you. Would there be any chance to shuttle down to Yokohama spaceport instead? I’ve got a client who’s from that region.”</p>
<p>“Taxi LT-22, copy, stand by.”</p>
<p>“Taxi LT-22, you can park in orbit lane A44, section D, and shuttle down to Yokohama spaceport instead.”</p>
<p>“Earth, Ground, lane A44, section D, shuttle down to Yokohama; copy that.”</p>
<p>“Taxi LT-22, your parking documents have been sent over. If you need anything else, let us know.”</p>
<p>“Earth, Ground, copy that; thank you, have a nice day.”</p>
<p>With a parking spot secured, I check up on Earth’s — and my personal — financial situation. In theory, the Earth Dollar should be pretty stable, but being away for years on end always has risks. It’s looking good though. Mr. Tunaki’s payment is already there as well. Perfect. There’s about two years of pure luxury waiting for me; and that is if I take into account the upgrades I want to do to my ship. I’ll have to talk to my valet about it. I hope Wakato is still working at Yokohama spaceport, that would be nice.</p>
<p>We park in lane A44, section D, and prepare for separation. I help mr. Tunaki into the shuttle, strap him in, and take place in the pilot seat. “This is the bumpy part of the ride,” I warn him. “There’s a bag underneath your seat if you need it.“</p>
<p>He needed it.</p>
<p>We arrive at Yokohama spaceport without any other problems, although mr. Tunaki vomited part of his spinach pasta outside the bag, onto his lap and, more importantly, onto the chair. “Don’t worry about it,” I lie, “this happens almost always.” Meanwhile I’m worrying about the poor valet who will need to clean up the mess. It stinks.</p>
<p>We make a soft landing on one of the spaceport runways and we taxi to gate A44. I power down the shuttle’s engine, and look who’s there!</p>
<p>“Wakato! Konnichiwa!” I exclaim in my best Japanese as I crouch out of the shuttle. “It’s great to see you!”</p>
<p>“Sir! It’s great to see you!” Wakato replies, “Did you have a good trip?”</p>
<p>“All fine. You don’t seem to have aged at all.”</p>
<p>“Oh but I did, and I’m noticing it more and more,” Wakato laughs. “I’m actually retiring next year.”</p>
<p>“Oh that’s too bad… you’re one of the best valets I’ve ever worked with, I mean that.”</p>
<p>“There’s a new guy here now, I’m training him to be my replacement. He’s pretty good, I think you’ll like him. “</p>
<p>“Ah well… we’ll see. Hey about the shuttle, my client wasn’t able to find the bag in time… So there’s some cleaning up to do. I’ve also ordered a refueling shipment. I checked fuel prices when I arrived and they seemed very favorable, so I just ordered a full refueling. Apart from that, it’s the standard maintenance tasks that need to be done, you know the drill, I’ve sent you the full report.”</p>
<p>“I’ll have all of it taken care of, sir!”</p>
<p>“Oh, could you look into whether we can upgrade the ship’s kitchen? I’m really sick of having to eat bagged food.”</p>
<p>“I’ll look into it and send you the available options, sir.”</p>
<p>“Thank you, Wakato San!”</p>
<p>“Sir, if you don’t mind. There was a gentleman asking about you a while ago. I told him you were still on your journey, but maybe you could get in touch with him once you’re back. It was a bit strange sir, the gentleman didn’t want to say why he needed you and didn’t want to leave any contact details.”</p>
<p>“Don’t worry about it,” I tell Wakato, “this happens to me multiple times. Potential clients want to get a hold of me as soon as possible, especially those with shady things going on in their lives.” I whisper the “shady” part because mr. Tunaki is unloading his bags from the hold, and can probably hear me if I speak too loud. “I’m sure he’ll be in touch again,” I continue, “if he hasn’t already found another pilot. In any case, I plan on staying for a year or two, so either he will have to wait, or find someone else. But thanks for letting me know!”</p>
<p>I grab my bag from the shuttle’s hold, shake mr. Tunaki’s hand, and wish him well. Who knows what he’ll do, but he’s not my problem anymore. I walk towards the spaceport exit hall, board the ferry, and am walking into the crowd ten minutes later. The city center is busy — too busy to my liking — but I make it to the hotel without any problems. I’ll stay here for a day or two to relax, then I’ll start to plan. Even though seven years is a relatively short period of time, it takes a significant amount of work and planning to get everything back into order. “Part of the job,” I mumble to myself as I sigh and open the hotel door.</p>
<hr />
<p>It’s a nice room, it looks out on the spaceport floating on the bay in the distance. I hope Wakato can do something about that kitchen… I pour a drink from the minibar, and prepare a bath. Oh how I’m looking forward to a bath. I undress, drop all my clothes in the middle of the room. But right when I’m ready to step into the bath, the hotel phone rings. I sigh — again. My guess is that it’s Wakato with news about the kitchen, that’s fast; so I run to the phone and pick it up.</p>
<p>“Hello?”</p>
<p>I’m greeted by an unfamiliar voice.</p>
<p>“Yes, speaking,” I reply, “who is this?” Maybe it’s that client Wakato was talking about. I don’t really feel like meeting anyone right now…</p>
<p>“I’m sorry to disturb you, sir,” the voice replies, “I’m doctor Jonathan Russel, from the Sheffield Institute of Space Travel. I need to speak to you very urgently. I —”</p>
<p>“I’m sorry,” I interrupt, “mister, doctor, I just returned from a long trip, and I’m really not interested in whatever you wanna talk about. So thank you for your interest but —”</p>
<p>“Oh but sir,” the doctor says, “your valet told me this would really interest you.”</p>
<p>So it is probably that guy Wakato was talking about. Well, if he deemed it important enough to pass my private coordinates to a random stranger, then maybe I should check it out. I’ll admit, I am a little intrigued by what doctor Jonathan Russel from the Sheffield Institute of Space Travel wants to talk about.</p>
<p>“Ok,” I say, “you have five minutes.”</p>
<p>“I actually think it would be better to talk face to face,” the doctor replied.</p>
<p>I roll my eyes, whatever interest I had is quickly dissipating. “Look, I don’t feel like going out, maybe we should schedule an appointment somewhere in the coming week then.”</p>
<p>“Oh, no worries, sir, I’m in the lobby of your hotel. I can come right up if that’s ok for you.”</p>
<p>Suddenly I feel worried about the intentions of this doctor, he’s already in my hotel? But my curiosity gets the upper hand.</p>
<p>“I’ll come down,” I finally say, “I’ll meet you in the lobby. How will I recognise you?”</p>
<p>“Oh I’ll recognise you sir, but I’m basically the one person who’s dressed wrong for the occasion. You can’t miss me.” He chuckles as he says it.</p>
<p>“Ok,” I sigh out loud, “I’ll be there in five.”</p>
<p><div class="author">
    <p>
        This post is part of a hobby project of mine: I'm writing a short sci-fi novel, and I want to share my progress with you.
        I'm in no way a professional fiction writer, so you might find what comes next to be total crap, and that's fine.
        If you make it to the end, I'd appreciate to hear your honest feedback in the comments at the bottom of this page.
    </p>

    <p>
        If you happen to like what you're reading: I'll be posting the next chapter next week. If you want to be sure you don't miss the next post,
        you can <a href="/timeline-taxi">leave your email address</a>, and I'll mail you when a new chapter is published.
    </p>
</div>
</p>
 ]]></summary>

                <updated>2024-07-12T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ New without parentheses in PHP 8.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-with-parentheses-php-84"/>

                <id>https://www.stitcher.io/blog/new-with-parentheses-php-84</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I like syntactic sugar. You know why? It's the small changes that have the biggest impact in the long run. <a href="/blog/constructor-promotion-in-php-8">Promoted properties</a>, <a href="/blog/new-in-php-84#property-hooks-rfc">Property hooks</a>, <a href="/blog/new-in-php-81#first-class-callable-syntax-rfc">First class callables</a> all had a huge impact on my day-to-day development life — and that's just a few of them. PHP 8.4 adds some more syntactic sugar, and I couldn't be more excited about it: you don't have to wrap newly created objects within parentheses anymore in order to chain methods on them.</p>
<p>Or, in other words, you can get rid of these two brackets:</p>
<pre><span class="hl-deletion">(</span><span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$className</span>)<span class="hl-deletion">)</span>-&gt;<span class="hl-property">getShortName</span>();
</pre>
<p>It seems like such a small change, but I write this kind of code so often, and it's so nice that I won't have to think about wrapping stuff in brackets again. Roman <a href="https://rfc.stitcher.io/rfc/new-myclass-method-without-parentheses#pronskiy-373">phrased it like this</a>:</p>
<blockquote>
<p>Every time I find myself typing <code>new MyClass()</code> and then returning back and adding those parentheses. It would be good to reduce this friction and make PHP coding flow smoother.</p>
</blockquote>
<p>Exactly! It's these small things that have a huge impact on a daily basis. I love it! In this post, I'm going share some of the details of this new feature, and you can read with me through the whole RFC as well:</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/3t4BxdkVL8M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="methods,-properties,-and-more"><a href="#methods,-properties,-and-more" class="heading-anchor">#</a> Methods, properties, and more</h2>
<p>Thanks to this new feature, you can chain much more than just methods on newly created objects: methods, properties, static methods and properties, you can use even array access or invoke the newly created class directly:</p>
<pre><span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()::<span class="hl-property">CONSTANT</span>;
<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()::<span class="hl-property">$staticProperty</span>;
<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()::<span class="hl-property">staticMethod</span>();
<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()-&gt;<span class="hl-property">property</span>;
<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()-&gt;<span class="hl-property">method</span>();
<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()();
<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>(['<span class="hl-value">value</span>'])[0];
</pre>
<p>Granted, something like <code><span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()()</code> looks a bit weird, it might just require some time to get used to, we'll see.</p>
<h2 id="also-for-dynamic-and-anonymous-classes"><a href="#also-for-dynamic-and-anonymous-classes" class="heading-anchor">#</a> Also for dynamic and anonymous classes</h2>
<p>The same syntax can be used on dynamic class names: class names that are resolved via a variable or via function calls:</p>
<pre><span class="hl-variable">$className</span> = <span class="hl-type">MyClass</span>::<span class="hl-keyword">class</span>;

<span class="hl-keyword">new</span> <span class="hl-variable">$className</span>()-&gt;<span class="hl-property">property</span>;
<span class="hl-keyword">new</span> (<span class="hl-property">trim</span>('<span class="hl-value"> MyClass </span>'))-&gt;<span class="hl-property">method</span>();
</pre>
<p>As well as on anonymous classes:</p>
<pre><span class="hl-keyword">new</span> <span class="hl-keyword">class</span> () { <span class="hl-comment">/* … */</span> }-&gt;<span class="hl-property">method</span>();
</pre>
<p>While I think shorter isn't always better, it's good to have this functionality available, just in case.</p>
<h2 id="constructor-brackets-are-required"><a href="#constructor-brackets-are-required" class="heading-anchor">#</a> Constructor brackets are required</h2>
<p>There's one caveat to this feature: the new class instantiation needs to be called <em>with</em> constructor brackets, even if no constructor parameters are passed:</p>
<pre><span class="hl-comment">// This is valid PHP if MyClass has an empty constructor</span>
<span class="hl-variable">$class</span> = <span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>; 

<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span><span class="hl-striped">-&gt;<span class="hl-property">method</span>()</span> <span class="hl-comment">// This isn't valid</span>

<span class="hl-keyword">new</span> <span class="hl-type">MyClass</span>()-&gt;<span class="hl-property">method</span>() <span class="hl-comment">// But this is</span>
</pre>
<p>The reason for this requirement is that without the constructor brackets, the PHP parser wouldn't be able to properly determine whether it's a new class instantiation or not. The <a href="https://wiki.php.net/rfc/new_without_parentheses#why_the_proposed_syntax_is_unambiguous">RFC</a> explains this behaviour more in depth in order to avoid any ambiguities.</p>
<h2 id="anonymous-classes-are-the-exception"><a href="#anonymous-classes-are-the-exception" class="heading-anchor">#</a> Anonymous classes are the exception</h2>
<p>The previous limitation however isn't present for anonymous classes, because their constructor brackets come <em>before</em> the class' body:</p>
<pre><span class="hl-keyword">new</span> <span class="hl-keyword">class</span> { <span class="hl-comment">/* … */</span> }-&gt;<span class="hl-property">method</span>();
<span class="hl-keyword">new</span> <span class="hl-keyword">class</span> () { <span class="hl-comment">/* … */</span> }-&gt;<span class="hl-property">method</span>();
</pre>
<p>Both are valid.</p>
<hr />
<p>Despite a couple of minor gotchas, I'd say this is a super nice addition to PHP, a small feature, but one with a big impact. Leave your thoughts about it in the comment section down below (I've added comments on this blog!), and don't forget to <a href="/mail">subscribe to my mailing list</a> if you want to be kept in the loop!</p>
 ]]></summary>

                <updated>2024-07-11T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ You should ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/you-should"/>

                <id>https://www.stitcher.io/blog/you-should</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Have I ever told you the story of how I got my job? I've now been a developer advocate for PHP at JetBrains for over two years, and I always considered myself to be pretty lucky being able to turn what used to be my hobby into my job.</p>
<p>Ok sure, <em>luck</em> had something to do with it, but the most crucial factor was actually a single blog post. One post, now more than 7 years ago, is what triggered a chain of events that led me to where I'm at today. I oftentimes remind myself of this blog post, and I think it would make an inspiring story to share with you as well.</p>
<p>So, back to 2017. I was working at your average web agency. One of my hobby side projects during that time was to build a static site generator in PHP. I needed a test subject, so I made a small blog to try it out. Eventually I lost interest in the static site generator idea, but the blog stayed. I'm still using that static generator to power what you're reading right now, but I would never want anyone else to use it.</p>
<p>Anyway, I wrote the occasional blog post, and one day I stumbled upon a video on Laracasts. It was titled "<a href="https://laracasts.com/series/php-bits/episodes/1">Visual Debt</a>" — and boy, did I disagree with everything said in it.</p>
<p>So I reached for the only platform I had: write a <a href="https://stitcher.io/blog/a-programmers-cognitive-load">reaction post</a> about it. A couple of weeks later and I checked up on my analytics — I occasionally did so to see how many people were reading my stuff, mostly to boost my ego a little bit. That one post apparently had thousands of views — much more than any of the other posts I had written up until that point. What happened was that someone I never heard of shared my post on his newsletter, which apparently had a huge following, and it spread from there.</p>
<p>That someone was <a href="https://freek.dev/">Freek</a>. I checked out his website, which led me to his company's website, which made me realise there was this small agency called <a href="https://spatie.be/">Spatie</a> 30 kilometers from my home. Apparently, they were looking to hire a PHP developer. I had been close to burning out on my current job for months by this time, but I never have had the courage to start a new job search. However, this company really sparked my interest.</p>
<p>So I sent them a casual mail. I attached my CV, but most importantly, I attached my GitHub account. I was invited for an introductory meeting a week later. It went well, and I was surprised to learn that I didn't have to do any technical tests. They already knew my blog, they knew my GitHub, they knew me.</p>
<p>I woke up the next morning, finding an email from Freek in my inbox: "We really liked meeting you, and we'd like to invite you for a second meeting." A couple of months later, I started working at Spatie. I had an amazing 5 years there, met a lot of cool people within the community (offline and online), which is also how I met Roman, my current colleague at JetBrains. We were attending PHP Benelux, where I gave an unconf talk. It was about — believe it or not — that one blog post I wrote as a reaction to the Visual Debt video.</p>
<p>I kept in touch with Roman, and one day we started talking about an open position for a DA at JetBrains. He had been following my blog and YouTube content and thought I'd be a good fit. And so, here were are.</p>
<p>Had it not been for that one video about Visual Debt, I doubt I'd be where I am today. So, in a way, all of this is thanks to Jeffrey Way, the creator of that video. By the way, besides that one video about Visual Debt, I agree with almost everything Jeffrey does at Laracasts, so you definitely should <a href="https://laracasts.com/">check him out</a> if you haven't heard of him.</p>
<p>Of course, I also have to thank myself for writing — I guess? I simply wrote whatever I wanted to write back then, I didn't have a content plan, I didn't have a strategy. I kept writing, and apparently it worked out pretty well.</p>
<p>I've never been a planner or a big strategist, let alone a skilled marketeer. I usually go where the flow takes me. I try to do whatever I like to do. That definitely makes me a bad businessman and I doubt I'll ever be able to count myself as one of the successful independent entrepreneurs. But I don't feel much ambition to be that. I just write some stuff and focus on the things I like to do, and it's leading me to great places anyway.</p>
<p>I'm going through a period of <a href="https://stitcher.io/blog/twitter-exit">reflection</a> these days, and it's showing me a lot of stuff I need to work on. But I'm also reminded about a lot of good stuff I'm thankful for. I figured I'd share those parts as well, because I think it could inspire a handful of people. Working on whatever makes you happy is a valid strategy. Not driven by money or fame, but just because you want to. Put that work out there in public. Not because you want to reach specific goals or numbers, but just because you can.</p>
<p>If you want to, you should.</p>
<p>PS: I've added comments to my blog, so you can leave your thoughts on this page now directly! I'd love to read your thoughts as well.</p>
 ]]></summary>

                <updated>2024-07-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP version stats: July, 2024 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-version-stats-july-2024"/>

                <id>https://www.stitcher.io/blog/php-version-stats-july-2024</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Every six months, I do an update on which PHP versions are used across the community. You can read the previous edition <a href="/blog/php-version-stats-january-2024">here</a>, I'll also include historic data in this post.</p>
<p>Keep in mind note that I'm working with the data available. That means that these charts are not a 100% accurate representation of the PHP community as a whole, but they <em>are</em> an accurate representation of one of the most prominent parts of PHP: the <a href="https://packagist.org/php-statistics">packagist ecosystem</a>.</p>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<h2 id="usage-statistics"><a href="#usage-statistics" class="heading-anchor">#</a> Usage Statistics</h2>
<p>As usual, we start by looking at the percentage of PHP versions being used today, note that I've omitted all versions that don't have more than 1% usage:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2023-01</td>
    <td>2023-07</td>
    <td>2024-01</td>
    <td>2024-07</td>
</tr>
<tr>
    <td>7.2</td>
    <td>4.3%</td>
    <td>4.3%</td>
    <td>2.5%</td>
    <td>2.0%</td>
</tr>
<tr>
    <td>7.3</td>
    <td>5.3%</td>
    <td>4.2%</td>
    <td>3.2%</td>
    <td>1.9%</td>
</tr>
<tr>
    <td>7.4</td>
    <td>27.7%</td>
    <td>19.9%</td>
    <td>13.6%</td>
    <td>10.2%</td>
</tr>
<tr>
    <td>8.0</td>
    <td>16.2%</td>
    <td>12.3%</td>
    <td>7.2%</td>
    <td>5.4%</td>
</tr>
<tr>
    <td>8.1</td>
    <td>38.8%</td>
    <td>39.3%</td>
    <td>35.2%</td>
    <td>26.1%</td>
</tr>
<tr>
    <td>8.2</td>
    <td>4.7%</td>
    <td>17.2%</td>
    <td>29.4%</td>
    <td>32.3%</td>
</tr>
<tr>
    <td>8.3</td>
    <td>0.0%</td>
    <td>0.2%</td>
    <td>6.4%</td>
    <td>19.9%</td>
</tr>
</table>
</div>
<p>Visualizing this data looks like this:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2024-jul-01.svg"><img src="/resources/img/blog/version-stats/2024-jul-01.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2024-jul-01.svg">Evolution of version usage</a></em></p>
<p>An additional data point I wanted to look into this time, is to compare the growth of each PHP version the first half year after its release.</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>6 month adoption rate</td>
</tr>
<tr>
    <td>7.0</td>
    <td>19.0%</td>
</tr>
<tr>
    <td>7.1</td>
    <td>16.2%</td>
</tr>
<tr>
    <td>7.2</td>
    <td>12.4%</td>
</tr>
<tr>
    <td>7.3</td>
    <td>19.8%</td>
</tr>
<tr>
    <td>7.4</td>
    <td>17.1%</td>
</tr>
<tr>
    <td>8.0</td>
    <td>9.2%</td>
</tr>
<tr>
    <td>8.1</td>
    <td>15.4%</td>
</tr>
<tr>
    <td>8.2</td>
    <td>12.5%</td>
</tr>
<tr>
    <td>8.3</td>
    <td>13.5%</td>
</tr>
</table>
</div>
<p>What's interesting is that the PHP 7.* versions seem to have had a faster adoption rate compared to PHP 8.* releases. From a personal point of view, I also feel less need to immediately update to newer PHP versions, especially since they didn't offer that many exciting features the past two years. I wonder if the adoption rate for PHP 8.4 will be higher or lower, especially since it has some very nice features (like <a href="/blog/new-in-php-84#property-hooks-rfc">property hooks</a>).</p>
<p>Let's take one more look at version evolution across time, you can spot the slowed down adoption rate in this chart as well::</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2024-jul-02.svg"><img src="/resources/img/blog/version-stats/2024-jul-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2024-jul-02.svg">All time evolution</a></em></p>
<h2 id="required-versions"><a href="#required-versions" class="heading-anchor">#</a> Required versions</h2>
<p>Next, I used Nikita's <a target="_blank" href="https://github.com/nikic/popular-package-analysis">popular package analyzer</a> to download the 1000 most popular composer packages. I use a script that scans these packages to determine their minimum required version. Here are the results:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2023-01</td>
    <td>2023-07</td>
    <td>2024-01</td>
    <td>2024-07</td>
</tr>
<tr>
    <td>5.2</td>
    <td>10</td>
    <td>7</td>
    <td>7</td>
    <td>5</td>
</tr>
<tr>
    <td>5.3</td>
    <td>78</td>
    <td>65</td>
    <td>58</td>
    <td>50</td>
</tr>
<tr>
    <td>5.4</td>
    <td>40</td>
    <td>31</td>
    <td>28</td>
    <td>26</td>
</tr>
<tr>
    <td>5.5</td>
    <td>37</td>
    <td>21</td>
    <td>16</td>
    <td>15</td>
</tr>
<tr>
    <td>5.6</td>
    <td>43</td>
    <td>32</td>
    <td>30</td>
    <td>29</td>
</tr>
<tr>
    <td>7.0</td>
    <td>30</td>
    <td>24</td>
    <td>24</td>
    <td>24</td>
</tr>
<tr>
    <td>7.1</td>
    <td>159</td>
    <td>125</td>
    <td>100</td>
    <td>93</td>
</tr>
<tr>
    <td>7.2</td>
    <td>144</td>
    <td>133</td>
    <td>123</td>
    <td>118</td>
</tr>
<tr>
    <td>7.3</td>
    <td>106</td>
    <td>56</td>
    <td>49</td>
    <td>42</td>
</tr>
<tr>
    <td>7.4</td>
    <td>98</td>
    <td>97</td>
    <td>87</td>
    <td>80</td>
</tr>
<tr>
    <td>8.0</td>
    <td>103</td>
    <td>144</td>
    <td>126</td>
    <td>123</td>
</tr>
<tr>
    <td>8.1</td>
    <td>129</td>
    <td>107</td>
    <td>154</td>
    <td>184</td>
</tr>
<tr>
    <td>8.2</td>
    <td>-</td>
    <td>94</td>
    <td>135</td>
    <td>153</td>
</tr>
<tr>
    <td>8.3</td>
    <td>-</td>
    <td>-</td>
    <td>0</td>
    <td>4</td>
</tr>
</table>
</div>
<p>There are two important notes to make here.</p>
<ol>
<li>This tables shows the <strong>minimum required version</strong>. That means that packages with a minimal version of, for example, 8.0, could also support PHP 8.1, PHP 8.2, and PHP 8.3.</li>
<li>If you count the numbers, you'll notice there are some differences between each year. Not every package lists a valid version string.</li>
</ol>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<p>Instead of comparing absolute numbers, it's best to plot this data into a chart for a relative comparison, so that we can see changes over time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2024-jul-03.svg"><img src="/resources/img/blog/version-stats/2024-jul-03.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2024-jul-03.svg">Minimal PHP requirement over time</a></em></p>
<p>We see the first four packages requiring PHP 8.3 as their minimal version this month, however there is a huge difference compared to PHP 8.2 and PHP 8.1, which had 94 and 125 packages using them as their minimum version respectively. Granted, PHP 8.3 has been a rather boring release, with quite a lot of deprecations as well, but I didn't expect the difference to be so big. We'll see how and if this trend continues in the next year with PHP 8.4.</p>
<p>Once again, I'd like to remind open source authors about the responsibility we collectively hold to move the PHP ecosystem forward. Bumping minimum requirements is a good thing to do, and should — in my opinion — but done more and faster. Feel free to disagree and share your thoughts via <a href="mailto:brendt@stitcher.io">email</a> or in the comments below this post.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2024-07-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ A vocal minority ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-vocal-minority"/>

                <id>https://www.stitcher.io/blog/a-vocal-minority</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's been a little over a week since I <a href="/blog/twitter-exit">logged off Twitter</a> — since I made my X-it (you're welcome to acknowledge my dad-joke skills). Since then, I've received numerous emails in support of that decision. It made me realise something important; two related things, actually.</p>
<p>My first realisation was that one of the biggest factors preventing me from leaving Twitter was FOMO — fear of missing out. The fear that I won't be up-to-date with what's happening in the PHP community anymore. The fear that <em>I</em> won't be relevant anymore. After my blog post and email last week though, lots of people reacted, which made me realise that FOMO is a thing, but more importantly that I shouldn't have that fear in the first place. That's where my second realisation comes in.</p>
<p>I learned about the <a href="https://en.wikipedia.org/wiki/Spotlight_effect">spotlight effect</a>: "the psychological phenomenon by which people tend to believe they are being noticed more than they really are". I think the same effect can be applied on communities of people. Having been in the Twitter bubble, I started to believe that it was a crucial part of being involved in the PHP community. However, given the amount of people who told me they have left Twitter long ago, and oftentimes social media in general; I can't help but conclude that Twitter isn't as representative as I liked to think.</p>
<p>That's the spotlight effect in action: Twitter has been my most important communication channel for years, so naturally, I got biased towards it. Most likely though, it only represents a vocal minority, a small subsection of the PHP community. The thing with vocal minorities is that they stand out much more compared to silent majorities, and trick us into thinking that those majorities don't exist, or that they aren't as relevant compared to our own bubble, our own comfort zone.</p>
<p>This is no one's fault, no one's doing this on purpose. But coming to this realisation makes me much more chill about leaving Twitter. I probably won't miss out on as much as I thought I would. My plan forward is to rely on RSS and email as my primary channels of communication. We'll see how it goes. On a personal level I can say that I haven't missed Twitter this past week, and the need to check up on it is subsiding.</p>
<p>Overall I had a good week, I finally managed to write down a couple of chapters for a scifi novel I've been wanted to write. I'm 9000 words in, and it's been such a great project to work on, just because I want and can. I hope you don't mind if I share some more updates about it with you in the future. Do let me know if you really don't want to hear anything about it though, I'll keep your feedback in mind.</p>
<p>Finally, if you mailed me and I haven't replied personally to your answer on my previous post yet: I do plan on replying to all mails, I just have been AFK a lot these days :)</p>
 ]]></summary>

                <updated>2024-07-03T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Leaving Twitter ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/twitter-exit"/>

                <id>https://www.stitcher.io/blog/twitter-exit</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Five.</p>
<p>That's the amount of times I instinctively wrote "twitter.com" in Chrome's URL bar today. Five times I saw the login screen instead of my home feed, and five times I was reminded about the decision I made last night. Even <em>while</em> writing this, I have the urge to <em>quickly</em> cmd+tab into chrome, go to Twitter and check up on… I don't even know what.</p>
<p>I'm not allowing myself to do that anymore; yesterday evening I decided I'd log off of Twitter, hopefully for good.</p>
<p>Yesterday in general was a weird day. I visited the doctor, talked about burnout, she wrote me off work for a couple of weeks, and gave me one task: try to get my thoughts back in order. There are many factors in play, and I don't feel the need to share all of them with the world wide web. The "full picture" also doesn't matter for what I <em>do</em> want to share: that realisation I had yesterday evening, lying awake, trying to make sense of it all. "The bucket's full", the doctor had told me, "nothing will fit anymore. You'll have to make some changes."</p>
<p>I'm not a <em>total mess</em> by the way. I caught this early (thanks to my wife), and I'm dealing with it, and I'll get it fixed. However, yesterday it was clear to me that in order to do so, I needed to get rid of one specific thing. It's definitely not the only culprit, but yes, Twitter has had an effect on the downwards spiral I'm experiencing.</p>
<p>Now, my job involves being online, a lot. I'm a developer advocate so people need to know me, and I need to know them. I've always thought to be very lucky or blessed having been able to turn what I used to do as my hobby, into my full time job. I get to create, I get to interact with like-minded people, I get to build meaningful relationships. Naturally, having to be involved with the PHP community, Twitter was one of the hot spots for me.</p>
<p>I used to use Twitter as a place to meet new people, to discover interesting ideas. PHP developers shared projects, opinions, blog posts, videos, and it was a great platform for discovery on the web.</p>
<p>But, obviously, Twitter has changed. People might still be tweeting about those things, they just don't reach me anymore. Twitter's goal has shifted into keeping people on the platform, while I need exactly the opposite. My home feed these days is filled with indie SaaS developers, content- and course creator guru's, thought leaders, self-proclaimed SEO-experts, and people trying to sell me whatever they are making. It has grown into an alienating, artificial "positive-vibes" feedback loop. The Algorithm™ is serving a different kind of content these days, forcing more and more people to make that kind of content, rinse and repeat.</p>
<p>And you know what? It works. I can't stop scrolling. After ten minutes I suddenly think: what am I doing here? I close the tab. Ten minutes later I've somehow ended up scrolling that same feed again — I don't even remember how I got there.</p>
<p>By pure coincidence, while I'm writing this post, a <a href="https://aggregate.stitcher.io/post/34b8f076-5d1c-4d68-8997-7a5d3d862c92">great blog post</a> suddenly popped into my feed (RSS feed, that is, not Twitter), it talks about the same topic:</p>
<blockquote>
<p>Like many, I bought into the software hustle culture, spurred by Twitter and loads of success stories by indie hackers who seem to be able to fart money before I've even had my first coffee.</p>
</blockquote>
<p>From my point of view, the worst part is that this content doesn't <em>really</em> make me happy. It doesn't <em>really</em> inspire. It doesn't <em>really</em> make me a better person. Of course, everyone <em>wants</em> me to think that <em>their</em> content and <em>their</em> tweets are different and valuable, but in the end they bring little to no value. That might be different for others, but <em>for me,</em> it simply doesn't work anymore. I'm sick of it. Twitter's Algorithm™ has had such a negative impact on my happiness, my self-worth, and my motivation, that I can't continue to mindlessly scroll.</p>
<p>So I decided to log off. I'll have to think about how I can still do my job without Twitter. I might go on a blocking and mute spree once I start work again, trying to clean my home feed. On the other hand, given how much Twitter changed over the past years, I'm not at all convinced it offers enough value for what I'm trying to do anyway. We'll see… People who still want to reach me or be kept up to date about what I'm doing can always <a href="mailto:brendt@stitcher.io">mail</a> me if they want to.</p>
 ]]></summary>

                <updated>2024-06-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Tagged Singletons ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/tagged-singletons"/>

                <id>https://www.stitcher.io/blog/tagged-singletons</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've added a pretty interesting feature to <a href="https://tempest.stitcher.io">Tempest</a>: tagged singletons. Let me give you the tl;dr: Tempest allows you to attach a tag to a singleton definition, which means you can have multiple singletons of the same class, as long as their tags differ.</p>
<p>They can be registered manually like so:</p>
<pre><span class="hl-variable">$container</span>-&gt;<span class="hl-property">singleton</span>(
    <span class="hl-type">Highlighter</span>::<span class="hl-keyword">class</span>, 
    <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">LightTerminalTheme</span>()), 
    <span class="hl-property">tag</span>: '<span class="hl-value">cli</span>',
);
</pre>
<p>Or you could use an initializer:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Singleton</span>(<span class="hl-property">tag</span>: '<span class="hl-value">web</span>')]</span></span>
<span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">WebHighlighterInitializer</span> <span class="hl-keyword">implements</span><span class="hl-type"> Initializer
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">initialize</span>(<span class="hl-injection"><span class="hl-type">Container</span> $container</span>): <span class="hl-type">Highlighter</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>());
    }
}
</pre>
<p>And you can retrieve a specific tagged singleton like so:</p>
<pre><span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-type">Highlighter</span>::<span class="hl-keyword">class</span>, <span class="hl-property">tag</span>: '<span class="hl-value">cli</span>');
</pre>
<p>Or by using the <code><span class="hl-attribute">#[<span class="hl-type">Tag</span>]</span></code> attribute for autowired dependencies:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">HttpExceptionHandler</span> <span class="hl-keyword">implements</span><span class="hl-type"> ExceptionHandler
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        </span><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Tag</span>('<span class="hl-value"><span class="hl-value">web</span></span>')]</span></span><span class="hl-injection"> <span class="hl-keyword">private</span> <span class="hl-type">Highlighter</span> <span class="hl-property">$highlighter</span>,
    </span>) {}
}
</pre>
<p>Ok but, singletons should be… singletons, right? How can you have multiple singletons for the same class? And what about tight coupling between abstracts and implementations?</p>
<p>Well that's why I'm writing this blog post.</p>
<h2 id="let's-work-through-it"><a href="#let's-work-through-it" class="heading-anchor">#</a> Let's work through it</h2>
<p>In order to understand the usefulness of tagged singletons, I'll have to make sure we're on the same page about a couple of things regarding dependency injection: the pattern itself, the container, autowiring, singletons, and finally the topic of "object identity".</p>
<p>It's a multi-layered answer, but I hope it'll be an interesting read — I definitely found it an interesting topic to write about.</p>
<h3 id="dependency-injection"><a href="#dependency-injection" class="heading-anchor">#</a> Dependency Injection</h3>
<p>Let's start from the beginning: what is dependency injection? Here's the definition from <a href="https://en.wikipedia.org/wiki/Dependency_injection">Wikipedia</a>:</p>
<blockquote>
<p>dependency injection is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs</p>
</blockquote>
<p>Note that this definition says nothing about <em>how</em> dependencies are injected. The pattern is about the fact the dependencies are passed from the <em>outside into</em> an object.</p>
<p>Following that definition, this is an example of dependency injection:</p>
<pre><span class="hl-variable">$object</span> = <span class="hl-keyword">new</span> <span class="hl-type">HttpExceptionHandler</span>(
    <span class="hl-property">highlighter</span>: <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(
        <span class="hl-property">theme</span>: <span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>(),
    ),
);
</pre>
<p>In this example, <code><span class="hl-type">HttpExceptionHandler</span></code> has a dependency on <code><span class="hl-type">Highlighter</span></code>, which has a dependency on <code><span class="hl-type">CssTheme</span></code>. We've manually constructed all dependencies needed, but it's still dependency injection.</p>
<p>As a side note; I like to think of dependencies as more than only objects, a dependency could  be a scalar value as well — which is extremely useful for injecting config values, but that's a story for another time.</p>
<p>So: dependency injection is about <em>injecting dependencies</em> from the <em>outside</em> into a class, so that that class doesn't have to worry about constructing and managing those dependencies by itself.</p>
<h3 id="the-container"><a href="#the-container" class="heading-anchor">#</a> The container</h3>
<p>Next is the container, which is what most people think about when they say "dependency injection". The container is no more than a tool to make dependency injection more convenient. A container could be as simple as this, a class that's essentially a key/value store of dependency definitions:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Container</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$definition</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">register</span>(<span class="hl-injection"><span class="hl-type">string</span> $key, <span class="hl-type">Closure</span> $definition</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">instances</span>[<span class="hl-variable">$key</span>] = <span class="hl-variable">$definition</span>;
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">get</span>(<span class="hl-injection"><span class="hl-type">string</span> $key</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-variable">$definition</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">instances</span>[<span class="hl-variable">$key</span>] ?? <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">UnknownDependency</span>();
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$definition</span>(<span class="hl-variable">$this</span>);
    }
}
</pre>
<p>Setting up the container would look something like this:</p>
<pre><span class="hl-variable">$container</span> = (<span class="hl-keyword">new</span> <span class="hl-type">Container</span>())
    -&gt;<span class="hl-property">register</span>('<span class="hl-value">cssTheme</span>', <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>) =&gt; <span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>)
    -&gt;<span class="hl-property">register</span>('<span class="hl-value">highlighter</span>', <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>) =&gt; <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">cssTheme</span>')))
    -&gt;<span class="hl-property">register</span>('<span class="hl-value">httpExceptionHandler</span>', <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>) =&gt; <span class="hl-keyword">new</span> <span class="hl-type">HttpExceptionHandler</span>(<span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">highlighter</span>')));

<span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">httpExceptionHandler</span>');
</pre>
<p>Now, this isn't how most real-life containers work; and that's for good reasons: this is a rather inconvenient way of managing dependencies. I deliberately wrote it like this though to clarify how a container, in its core, is a key/value store of definition functions. You can register objects in it, and you can get objects from it.</p>
<p>A slightly more convenient way to register objects is by not specifying textual keys, but instead using the class name of the object:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Container</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$instances</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">register</span>(<span class="hl-injection"><span class="hl-type">string</span> $className, <span class="hl-type">Closure</span> $definition</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">instances</span>[<span class="hl-variable">$instance</span>::<span class="hl-keyword">class</span>] = <span class="hl-variable">$definition</span>;
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>That way, you don't have to come up with textual IDs for every dependency you want to register, you can simply use its class name:</p>
<pre><span class="hl-variable">$container</span> = (<span class="hl-keyword">new</span> <span class="hl-type">Container</span>())
    -&gt;<span class="hl-property">register</span>(<span class="hl-type">CssTheme</span>::<span class="hl-keyword">class</span>, <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>) =&gt; <span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>)
    -&gt;<span class="hl-property">register</span>(<span class="hl-type">Highlighter</span>::<span class="hl-keyword">class</span>, <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>) =&gt; <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-type">CssTheme</span>::<span class="hl-keyword">class</span>)))
    -&gt;<span class="hl-property">register</span>(<span class="hl-type">HttpExceptionHandler</span>::<span class="hl-keyword">class</span>, <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>) =&gt; <span class="hl-keyword">new</span> <span class="hl-type">HttpExceptionHandler</span>(<span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-type">Highlighter</span>::<span class="hl-keyword">class</span>)));
</pre>
<p>Even more convenient: you could infer the class name from the closure's definition with just a little bit of reflection on the definition's return type:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Container</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$instances</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">register</span>(<span class="hl-injection"><span class="hl-type">Closure</span> $definition</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$reflection</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionFunction</span>(<span class="hl-variable">$definition</span>);
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">instances</span>[<span class="hl-variable">$reflection</span>-&gt;<span class="hl-property">getReturnType</span>()-&gt;<span class="hl-property">getName</span>()] = <span class="hl-variable">$definition</span>;
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>Which leads to even less work!</p>
<pre><span class="hl-variable">$container</span> = (<span class="hl-keyword">new</span> <span class="hl-type">Container</span>())
    -&gt;<span class="hl-property">register</span>(<span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>): <span class="hl-type">CssTheme</span> =&gt; <span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>)
    -&gt;<span class="hl-property">register</span>(<span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>): <span class="hl-type">Highlighter</span> =&gt; <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-type">CssTheme</span>::<span class="hl-keyword">class</span>)))
    -&gt;<span class="hl-property">register</span>(<span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Container</span> $container</span>): <span class="hl-type">HttpExceptionHandler</span> =&gt; <span class="hl-keyword">new</span> <span class="hl-type">HttpExceptionHandler</span>(<span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-type">Highlighter</span>::<span class="hl-keyword">class</span>)));
</pre>
<p>Remember, our main goal is developer experience at this point. We'd probably cache the final or "compiled" key/value store for production, so why not use a little reflection to make our lives easier?</p>
<p>In the end though, the only thing we're doing is figuring out which key to use for which dependency. Most containers happen to use the class name because it's convenient, but it could be anything you'd like. It's just a key.</p>
<h3 id="autowiring"><a href="#autowiring" class="heading-anchor">#</a> Autowiring</h3>
<p>Speaking of convenience, real dependency containers do a lot more than just keeping track of keys and values. Autowiring is probably one of the container's biggest advantages. Autowiring is a mechanism that allows the container to come up with definitions for dependencies itself, instead of needing each definition to be manually defined. You can still define definitions for specific cases if you need to, but only for the cases where autowiring isn't smart enough.</p>
<p>Essentially, you'd write this:</p>
<pre><span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-type">HttpExceptionHandler</span>::<span class="hl-keyword">class</span>);
</pre>
<p>And the container would use reflection to find the right dependencies:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Container</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">get</span>(<span class="hl-injection"><span class="hl-type">string</span> $key</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-variable">$definition</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">instances</span>[<span class="hl-variable">$key</span>] 
            ?? <span class="hl-variable">$this</span>-&gt;<span class="hl-property">autowire</span>(<span class="hl-variable">$key</span>);
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$definition</span>(<span class="hl-variable">$this</span>);
    }
    
    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">autowire</span>(<span class="hl-injection"><span class="hl-type">string</span> $class</span>): <span class="hl-type">Closure</span>
    {
        <span class="hl-variable">$constructor</span> = (<span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$class</span>))-&gt;<span class="hl-property">getConstructor</span>();
        
        <span class="hl-variable">$dependencies</span> = [];
        
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$constructor</span>-&gt;<span class="hl-property">getParameters</span>() <span class="hl-keyword">as</span> <span class="hl-variable">$parameter</span>) {
            <span class="hl-variable">$dependencies</span>[<span class="hl-variable">$parameter</span>-&gt;<span class="hl-property">getName</span>()] = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">get</span>(<span class="hl-variable">$parameter</span>-&gt;<span class="hl-property">getType</span>()-&gt;<span class="hl-property">getName</span>());
        }
        
        <span class="hl-comment">// The autowire definition is created on the fly</span>
        <span class="hl-keyword">return</span> <span class="hl-keyword">fn</span> () =&gt; <span class="hl-keyword">new</span> <span class="hl-variable">$class</span>(...<span class="hl-variable">$dependencies</span>);
    }
}
</pre>
<p>That's autowiring: adding convenience for developers, so that they don't have to specify every definition manually. The reason the container can do autowiring, is because we've agreed to use class names as dependency keys, and those class names happen to be available within object constructors as well:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">HttpExceptionHandler</span>
{
    <span class="hl-comment">// Highlighter is both the parameter's type,</span>
    <span class="hl-comment">// but also the dependency's key:</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">Highlighter</span> <span class="hl-property">$highlighter</span>,
    </span>) {}
}
</pre>
<p>You don't <em>need</em> to use class names, by the way. You <em>could</em> make a container that only uses manual defined dependency IDs like in the very first example, and use attributes to handle autowiring:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">HttpExceptionHandler</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
         </span><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Autowire</span>('<span class="hl-value"><span class="hl-value">highlighter</span></span>')]</span></span><span class="hl-injection"> <span class="hl-keyword">private</span> <span class="hl-type">Highlighter</span> <span class="hl-property">$highlighter</span>,
    </span>) {}
}
</pre>
<p>But honestly, using the class name works and requires less typing. So why bother?</p>
<h3 id="singletons"><a href="#singletons" class="heading-anchor">#</a> Singletons</h3>
<p>Well, we <em>do</em> sometimes bother, which is why I added tagged singletons in Tempest, but we're getting ahead of ourselves. Let's first discuss singletons on their own. Singletons are a special kind of dependencies: as soon as the container has constructed a singleton, it will be cached, and that cached version is used whenever the same class is requested again.</p>
<p>A simplistic implementation could look something like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Container</span>
{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$singletons</span>;
    
    <span class="hl-comment">// Registering the singleton is very similar</span>
    <span class="hl-comment">// to registering normal definitions</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">singleton</span>(<span class="hl-injection"><span class="hl-type">Closure</span> $definition</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$reflection</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionFunction</span>(<span class="hl-variable">$definition</span>);
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">singletons</span>[<span class="hl-variable">$reflection</span>-&gt;<span class="hl-property">getReturnType</span>()-&gt;<span class="hl-property">getName</span>()] = <span class="hl-variable">$definition</span>;
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
    
    <span class="hl-comment">// We need to have some additions in our get method</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">get</span>(<span class="hl-injection"><span class="hl-type">string</span> $className</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-comment">// If there's a singleton definition</span>
        <span class="hl-keyword">if</span> (<span class="hl-variable">$singleton</span> = (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">singletons</span>[<span class="hl-variable">$className</span>] ?? <span class="hl-keyword">null</span>)) {
        
            <span class="hl-comment">// We'll check whether it's still in its definition form</span>
            <span class="hl-keyword">if</span> (<span class="hl-variable">$singleton</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Closure</span>) {
            
                <span class="hl-comment">// If so, we'll execute the definition once,</span>
                <span class="hl-comment">// and store its result (the singleton object)</span>
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">singletons</span>[<span class="hl-variable">$className</span>] = <span class="hl-variable">$singleton</span>(<span class="hl-variable">$this</span>);
            }
            
            <span class="hl-comment">// Finally we'll return the singleton object itself</span>
            <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">singletons</span>[<span class="hl-variable">$className</span>];
        }
        
        <span class="hl-comment">// If there's no singleton,</span>
        <span class="hl-comment">// we'll just resolve the dependency as normal</span>
        <span class="hl-variable">$definition</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">instances</span>[<span class="hl-variable">$className</span>] 
            ?? <span class="hl-variable">$this</span>-&gt;<span class="hl-property">autowire</span>(<span class="hl-variable">$className</span>);
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$definition</span>(<span class="hl-variable">$this</span>);
    }
}
</pre>
<p>Singletons can be super useful in cases where constructing objects take time, like for example objects that represent over-the-wire connections to external services, or when a dependency is used in many places throughout your codebase, in which case it might be better to have one shared instance of it, instead of numerous copies of the same class.</p>
<p>The highlighter example falls in the latter category: it's used all over the place, including loops, so I'd rather have one instance of it, instead of possibly hundreds.</p>
<p>So, now that we know about the container, autowiring, and singletons, we can finally discuss <em>tagged singletons</em>.</p>
<h3 id="tagged-singletons"><a href="#tagged-singletons" class="heading-anchor">#</a> Tagged singletons</h3>
<p>In essence, tagged singletons are no different from normal singletons, they just don't use the class name as their identifier. The reason is simple: binding singletons to class names can sometimes be limiting.</p>
<p>Take our highlighter example: I actually need <em>two</em> singleton instances of it: one for highlighting code on the web, and one for highlighting code in the console. And I actually sometimes need <em>both</em> of them, within the same request or command invocation. Going into the details of why would lead us too far, but I'm fairly certain that everyone who has ever worked on a larger codebase has a similar example: you need <em>two</em> single instances of the same class, slightly configured differently.</p>
<p>One solution people come up with is to have dedicated interfaces for each responsibility. These interfaces don't <em>do</em> anything, they are only there to help the container figure out which class to provide:</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">CliHighlighter</span> <span class="hl-keyword">extends</span> <span class="hl-type">Highlighter</span> {}
 
<span class="hl-keyword">interface</span> <span class="hl-type">WebHighlighter</span> <span class="hl-keyword">extends</span> <span class="hl-type">Highlighter</span> {} 
</pre>
<p>People then provide custom implementations for these interfaces, wrapping the original highlighter object:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">GenericCliHighlighter</span> <span class="hl-keyword">implements</span><span class="hl-type"> CliHighlighter
</span>{
    <span class="hl-keyword">private</span> <span class="hl-type">Highlighter</span> <span class="hl-property">$highlighter</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">highlighter</span> = <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">LightTerminalTheme</span>());
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">string</span> $content</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">highlighter</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$content</span>);
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">GenericWebHighlighter</span> <span class="hl-keyword">implements</span><span class="hl-type"> WebHighlighter
</span>{
    <span class="hl-keyword">private</span> <span class="hl-type">Highlighter</span> <span class="hl-property">$highlighter</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">highlighter</span> = <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>());
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">string</span> $content</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">highlighter</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$content</span>);
    }
}
</pre>
<p>In some cases you'd need to extend the parent class instead of using an interface if the code you're integrating with has chosen inheritance over composition, but it would look quite similar: a <em>lot</em> of code, just to make sure the container understands what we want.</p>
<p>Let's say we don't have two variations of our singleton, but five. What about the overhead then? Remember how the container's task was to make our lives easier? Now we find ourselves making our lives more difficult, just because the container isn't smart enough.</p>
<p>Ok, what about an alternative? We could have a factory class, something like this:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">HighlighterFactory</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">make</span>(<span class="hl-injection"><span class="hl-type">string</span> $key</span>): <span class="hl-type">Highlighter</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-variable">$key</span>) {
            '<span class="hl-value">cli</span>' =&gt; <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">LightTerminalTheme</span>()),
            '<span class="hl-value">web</span>' =&gt; <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>()),
        };
    }
}
</pre>
<p>Well… this "solution" is basically extracting part of the responsibility from the container, because it's falling short. It <em>should</em> be the container's task to know how to construct objects, but apparently it doesn't know how to do so in all cases. And thus we provide a custom factory — a mini-container in disguise — to "solve" our problem.</p>
<p>Oh, by the way, have you spotted how this factory doesn't support singletons? Should we implement it? Making it even more a mini-container?</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">HighlighterFactory</span>
{
    <span class="hl-keyword">private</span> <span class="hl-keyword">static</span> <span class="hl-type">?Highlighter</span> <span class="hl-property">$cli</span> = <span class="hl-keyword">null</span>;
    <span class="hl-keyword">private</span> <span class="hl-keyword">static</span> <span class="hl-type">?Highlighter</span> <span class="hl-property">$web</span> = <span class="hl-keyword">null</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">make</span>(<span class="hl-injection"><span class="hl-type">string</span> $key</span>): <span class="hl-type">Highlighter</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-variable">$key</span>) {
            '<span class="hl-value">cli</span>' =&gt; <span class="hl-type">self</span>::<span class="hl-property">$cli</span> ??= <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">LightTerminalTheme</span>()),
            '<span class="hl-value">web</span>' =&gt; <span class="hl-type">self</span>::<span class="hl-property">$web</span> ??= <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">CssTheme</span>()),
        };
    }
}
</pre>
<p>I think you see what I'm getting at, right? Either solutions are truly suboptimal. Remember that we have to write this code for every dependency that needs singleton variations. All because our container lacks.</p>
<p>Ok so, tagged singletons solve this problem. The only thing they do is to optionally define another identifier for a singleton:</p>
<pre><span class="hl-variable">$container</span>-&gt;<span class="hl-property">singleton</span>(
    <span class="hl-type">Highlighter</span>::<span class="hl-keyword">class</span>, 
    <span class="hl-keyword">new</span> <span class="hl-type">Highlighter</span>(<span class="hl-keyword">new</span> <span class="hl-type">LightTerminalTheme</span>()), 
    <span class="hl-property">tag</span>: '<span class="hl-value">cli</span>',
);
</pre>
<p>The identifier of this singleton would be <code>Highlighter#cli</code> (technically it would be the FQCN of <code><span class="hl-type">Highlighter</span></code>, but you get the point). Apart from that, you have two ways to specify the tag when requesting a dependency, either when manually resolving a dependency from the container:</p>
<pre><span class="hl-variable">$container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-type">Highlighter</span>::<span class="hl-keyword">class</span>, <span class="hl-property">tag</span>: '<span class="hl-value">cli</span>');
</pre>
<p>Or by using the <code><span class="hl-attribute">#[<span class="hl-type">Tag</span>]</span></code> attribute while autowiring:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">HttpExceptionHandler</span> <span class="hl-keyword">implements</span><span class="hl-type"> ExceptionHandler
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        </span><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Tag</span>('<span class="hl-value"><span class="hl-value">web</span></span>')]</span></span><span class="hl-injection"> <span class="hl-keyword">private</span> <span class="hl-type">Highlighter</span> <span class="hl-property">$highlighter</span>,
    </span>) {}
}
</pre>
<p>In short, tagged singletons give a programmer control over the dependency's identifier, <em>only</em> when needed. It's the next logical step in making our lives more convenient, which is all the container is about.</p>
<h2 id="but-this-is-wrong!"><a href="#but-this-is-wrong!" class="heading-anchor">#</a> But this is wrong!</h2>
<p>I'll list some of the counterarguments I got, and try to defend my case as well as possible.</p>
<p><strong>There can only be one singleton per class!</strong> — Well this statement actually mixes two ideas together. The <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a> indeed describes one instance per class. However, this isn't necessarily what the container is doing. A more apt name would be <em>cached dependencies</em>, but unfortunately we've gotten so used to the term "singleton", which is now causing confusion.</p>
<p>Also, thanks to modern containers, we've gotten used to <em>the class name</em> being the dependency key, which causes the misconception that the class name can be the <em>only</em> viable dependency key. I hope this blogpost has giving you some food for thought and will allow you to <a href="/blog/rational-thinking">challenge any preconceptions</a>.</p>
<p><strong>Tagged singletons tie a concrete implementation to an abstract!</strong> — True. By introducing a tag, we request <em>one specific</em> instance from the container. We're doing micromanagement and not programming to abstractions or interfaces anymore. This isn't any different from the two solutions others proposed though. Creating empty interfaces or subclasses just to please the container is equally <em>concrete</em>. It's not because we slammed the keyword <code><span class="hl-keyword">interface</span></code> in front of it that it suddenly is the perfect design. The factory solution is exactly the same: you request a very <em>specific</em> implementation. The only difference with tagged singletons is that there is more code to write in both other solutions, and more places to fail.</p>
<p>The reality is, sometimes we <em>need</em> a very specific thing. Adding layers of abstraction just to be able to say you're programming "the right way" — well, it isn't "the right way".</p>
<h2 id="in-closing"><a href="#in-closing" class="heading-anchor">#</a> In closing</h2>
<p>I had a lot of fun writing this post, and I hope you enjoyed reading it, even if you disagreed with some parts. I'd love to further talk about it, so feel free to come say hi on the <a href="https://discord.com/channels/1236153076688359495/1244626907580989450">Tempest Discord</a>, and subscribe to my <a href="/mail">mailing list</a> to be kept into the loop about future content.</p>
 ]]></summary>

                <updated>2024-05-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP in 2024 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-in-2024"/>

                <id>https://www.stitcher.io/blog/php-in-2024</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's 2024, and I'm excited about PHP. Will some people think I'm weird because of that? Sure. Do I have good reasons to be excited about a programming language that's been around for more than 25 years, which generally has a reputation of being the underdog compared to other languages?</p>
<p>Absolutely!</p>
<p>There <em>are</em> very good reasons to be excited about PHP these days. Today, I want to share some of the things I'm most excited about this year for PHP.</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/p_6ewdiwnRo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="continuous-evolution"><a href="#continuous-evolution" class="heading-anchor">#</a> Continuous evolution</h2>
<p>When Nikita left over two years ago — Nikita being <em>the</em> main contributor and driver for PHP, he went to work on LLVM — I'll admit I was <a href="/blog/php-in-2022">scared for PHP's future</a>:</p>
<blockquote>
<p>I'm a little worried now that Nikita has stepped down. He's definitely not the only person capable of working on PHP's core, but he <em>did</em> a tremendous amount of work these past years with PHP 8.0 and 8.1.
I don't think 2022 will be the most mind blowing year for PHP, but rather a year of adding stability.</p>
</blockquote>
<p>Looking back, I think that fear wasn't needed. The <a href="https://thephp.foundation/">PHP Foundation</a> has grown into a well-established community, with now 10 developers being paid to work on PHP core. Two major features being worked on at the moment come to mind: <a href="https://rfc.stitcher.io/rfc/property-hooks">property hooks</a> — which I'm hopeful for will pass once it comes to voting; and a <a href="https://www.youtube.com/watch?v=uWsGDUCxbT0">rework of Pecl</a> — PHP's extension manager.</p>
<p>Of course, I still got a sliver of hope when it comes to generics, which the Foundation is/was also looking into. I do think that the only viable way forward is <a href="/blog/we-dont-need-runtime-type-checks">runtime-ignored generics</a> though, time will tell whether the Foundation will be able to cultivate a new mindset or not.</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/XE4g1Tl6RQw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="frankenphp"><a href="#frankenphp" class="heading-anchor">#</a> FrankenPHP</h2>
<p>One of the cool things happening in PHP land today is a project called <a href="https://frankenphp.dev/">FrankenPHP</a>. It's been in the works for a year or two — if I remember correctly, and it's getting some real traction these days.</p>
<p>FrankenPHP is an app server for PHP, written in Go, that gives existing PHP apps a major performance boost, and it's super easy to get started with. It also supports compiling PHP projects as standalone binaries, worker mode for long-lived applications, is three times faster than PHP-FPM, HTTP/2 and HTTP/3 support, and more.</p>
<p>Recently, we've seen support for FrankenPHP for <a href="https://blog.laravel.com/octane-frankenphp">Laravel</a> and <a href="https://github.com/php-runtime/frankenphp-symfony">Symfony</a>. So it's growing into something big.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="laravel"><a href="#laravel" class="heading-anchor">#</a> Laravel</h2>
<p>I think it's fair to say at this point that Laravel's marketing strategy is working well. Laravel itself — <a href="https://laravel.com/">the open source framework</a> — is by far the most popular one within the PHP community; but they've also managed to create an ecosystem of products built with and for Laravel, to build a sustainable business. Just recently, Laravel <a href="https://twitter.com/taylorotwell/status/1768417227202613437">hired 6 new people</a>, from a COO to BizOps to engineers; and Taylor mentioned that "serious business is underway".</p>
<p>Modern businesses are growing and embracing PHP, which is great to see.</p>
<p>One of the things I embraced last year was <a href="https://laravel-livewire.com/">Laravel Livewire</a>, a tool that allows you to write interactive apps, without any JavaScript. I did some tinkering with it, and had a lot of fun making a game:</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/lnWrM6RXNak" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="discovering-php"><a href="#discovering-php" class="heading-anchor">#</a> Discovering PHP</h2>
<p>What I found especially heartwarming to see is how people outside the PHP community are re-discovering PHP. There have been a number of examples of people coming from the JavaScript world, suddenly <a href="https://www.youtube.com/watch?v=Spwv0RbITmE">realising Laravel is a thing</a>, and a <em>good</em> thing; and there are people like ThePrimeagen on YouTube who were pleasantly surprised by PHP:</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/WsnHWxO7Krw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="composer-and-packagist"><a href="#composer-and-packagist" class="heading-anchor">#</a> Composer and Packagist</h2>
<p>The PHP ecosystem keeps growing as well: there's a continuous growth in packages, indicating an active ecosystem.</p>
<p><a href="/resources/img/blog/php-in-2024/01.png"><img src="/resources/img/blog/php-in-2024/01.png" srcset="/resources/img/blog/php-in-2024/01-1050x466.png 1050w, /resources/img/blog/php-in-2024/01-1820x808.png 1820w, /resources/img/blog/php-in-2024/01-1486x660.png 1486w, /resources/img/blog/php-in-2024/01-2350x1044.png 2350w, /resources/img/blog/php-in-2024/01-2101x933.png 2101w" sizes="" alt=""></img></a></p>
<p>On top of that, Packagist recently crossed the <strong>one hundred billion downloads</strong> milestone. That's a <a href="/blog/php-in-2022#the-ecosystem">doubling in two years time</a>! We're now at <strong>105 134 384 876</strong>, and that number keeps growing.</p>
<p>I think it's fair to say: <strong>PHP is not dead</strong>!</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/x9bSUo6TGgY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2024-03-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Testing Patterns ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/testing-patterns"/>

                <id>https://www.stitcher.io/blog/testing-patterns</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>While building <a href="/blog/a-syntax-highlighter-that-doesnt-suck">tempest/highlight</a>, I came across an interesting design problem. One of its core components is a concept called "patterns"; these are classes that match a very specific part of code-to-be-highlighted using regex. Part of my test suite's responsibility is to test each of these patterns individually, to make sure they match the correct tokens, and don't match any incorrect ones.</p>
<p>Right now, tempest/highlight counts 109 pattern classes, a handful of them representing a collection of patterns such as keywords or operators. Take, for example, the <code><span class="hl-type">NewObjectPattern</span></code> that matches PHP class names when they are used to create a new object:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">NewObjectPattern</span> <span class="hl-keyword">implements</span><span class="hl-type"> Pattern
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsPattern</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">new (?&lt;match&gt;[\w]+)</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTokenType</span>(): <span class="hl-type">TokenType</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">TokenType</span>::<span class="hl-property">TYPE</span>;
    }
}

</pre>
<p>With 109 patterns (and that number is still growing), the question arises: how to test them? I could write individual tests for all of them, which is what I started out with. That grew into a mess pretty quickly though, so I created a trait called <code><span class="hl-type">TestsPatterns</span></code> which has this method:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">assertMatches</span>(<span class="hl-injection">
    <span class="hl-type">Pattern</span> $pattern,
    <span class="hl-type">string</span> $content,
    <span class="hl-type">string|array|null</span> $expected,
</span>): <span class="hl-type">void</span> {
    <span class="hl-variable">$matches</span> = <span class="hl-variable">$pattern</span>-&gt;<span class="hl-property">match</span>(<span class="hl-variable">$content</span>);

    <span class="hl-keyword">if</span> (<span class="hl-property">is_string</span>(<span class="hl-variable">$expected</span>)) {
        <span class="hl-variable">$expected</span> = [<span class="hl-variable">$expected</span>];
    }

    <span class="hl-keyword">if</span> (<span class="hl-variable">$expected</span> === <span class="hl-keyword">null</span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">assertCount</span>(
            <span class="hl-property">expectedCount</span>: 0,
            <span class="hl-property">haystack</span>: <span class="hl-variable">$matches</span>['<span class="hl-value">match</span>'],
            <span class="hl-property">message</span>: <span class="hl-property">sprintf</span>(
                &quot;<span class="hl-value">Expected there to be no matches at all in %s, but there were: %s</span>&quot;,
                <span class="hl-variable">$pattern</span>::<span class="hl-keyword">class</span>,
                <span class="hl-property">var_export</span>(<span class="hl-variable">$matches</span>['<span class="hl-value">match</span>'], <span class="hl-keyword">true</span>),
            )
        );

        <span class="hl-keyword">return</span>;
    }

    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$expected</span> <span class="hl-keyword">as</span> <span class="hl-variable">$key</span> =&gt; <span class="hl-variable">$expectedValue</span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">assertSame</span>(
            <span class="hl-property">expected</span>: <span class="hl-variable">$expectedValue</span>,
            <span class="hl-property">actual</span>: <span class="hl-variable">$matches</span>['<span class="hl-value">match</span>'][<span class="hl-variable">$key</span>][0],
            <span class="hl-property">message</span>: <span class="hl-property">sprintf</span>(
                &quot;<span class="hl-value">Pattern in %s did not match %s, found %s instead.</span>&quot;,
                <span class="hl-variable">$pattern</span>::<span class="hl-keyword">class</span>,
                <span class="hl-property">var_export</span>(<span class="hl-variable">$expectedValue</span>, <span class="hl-keyword">true</span>),
                <span class="hl-property">var_export</span>(<span class="hl-variable">$matches</span>['<span class="hl-value">match</span>'][<span class="hl-variable">$key</span>][0], <span class="hl-keyword">true</span>),
            ),
        );
    }
}
</pre>
<p>This trait can be used like so:</p>
<pre>
<span class="hl-keyword">class</span> <span class="hl-type">NewObjectPatternTest</span> <span class="hl-keyword">extends</span> <span class="hl-type">TestCase</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">TestsPatterns</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">test_pattern</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">assertMatches</span>(
            <span class="hl-property">pattern</span>: <span class="hl-keyword">new</span> <span class="hl-type">NewObjectPattern</span>(),
            <span class="hl-property">content</span>: '<span class="hl-value">new Foo()</span>',
            <span class="hl-property">expected</span>: '<span class="hl-value">Foo</span>',
        );

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">assertMatches</span>(
            <span class="hl-property">pattern</span>: <span class="hl-keyword">new</span> <span class="hl-type">NewObjectPattern</span>(),
            <span class="hl-property">content</span>: '<span class="hl-value">(new Foo)</span>',
            <span class="hl-property">expected</span>: '<span class="hl-value">Foo</span>',
        );
    }
}
</pre>
<p>This trait significantly reduced the amount of code I had to write: it takes a <code><span class="hl-type">Pattern</span></code> object, and checks whether a given input returns a matching output.</p>
<p>Good enough? Well, not so fast. Writing tests this way for 109 patterns actually gets pretty boring, pretty fast. I believe that to write a thorough test suite, writing tests need to be as frictionless as possible, otherwise people (me) will just skip writing tests in the long run.</p>
<p>So, I wondered: "can I reduce this friction even more?"</p>
<p><a href="https://blog.martinhujer.cz/how-to-use-data-providers-in-phpunit/">Data providers</a> came to mind: what if I made one class that contained all my test cases, and only needed to provide the data?</p>
<p>It would look something like this:</p>
<pre>
<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">PatternsTest</span> <span class="hl-keyword">extends</span> <span class="hl-type">TestCase</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">TestsPatterns</span>;

    <span class="hl-attribute">#[<span class="hl-type">Test</span>]</span>
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">DataProvider</span>('<span class="hl-value">patterns</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">test_patterns_with_attribute</span>(<span class="hl-injection"><span class="hl-type">Pattern</span> $pattern, <span class="hl-type">string</span> $input, <span class="hl-type">string</span> $output</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">assertMatches</span>(
            <span class="hl-property">pattern</span>: <span class="hl-variable">$pattern</span>,
            <span class="hl-property">content</span>: <span class="hl-variable">$input</span>,
            <span class="hl-property">expected</span>: <span class="hl-variable">$output</span>,
        );
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">patterns</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            [<span class="hl-keyword">new</span> <span class="hl-type">NewObjectPattern</span>(), '<span class="hl-value">new Foo()</span>', '<span class="hl-value">Foo</span>'],     
            [<span class="hl-keyword">new</span> <span class="hl-type">NewObjectPattern</span>(), '<span class="hl-value">(new Foo)</span>', '<span class="hl-value">Foo</span>'],     
            [<span class="hl-keyword">new</span> <span class="hl-type">NewObjectPattern</span>(), '<span class="hl-value">new Foo</span>', '<span class="hl-value">Foo</span>'],     
            
            <span class="hl-comment">// …</span>
        ];   
    }
}
</pre>
<p>Now there is even less duplicated setup code to write! However, there is a glaring problem: this approach scales poorly. Can you imagine having all pattern tests in one test file? Luckily, PhpStorm allows to run a single data provider entry, and is able to tell you which specific data provider entry failed, so there is some fine-grained control:</p>
<p><img src="/resources/img/blog/pattern-test/phpstorm.png" srcset="/resources/img/blog/pattern-test/phpstorm-2-749x578.png 2w, /resources/img/blog/pattern-test/phpstorm-2-1059x817.png 2w, /resources/img/blog/pattern-test/phpstorm-2-1298x1002.png 2w, /resources/img/blog/pattern-test/phpstorm-1366x634.png 1366w, /resources/img/blog/pattern-test/phpstorm-2-1499x1157.png 2w, /resources/img/blog/pattern-test/phpstorm-2.png 2w, /resources/img/blog/pattern-test/phpstorm-1115x518.png 1115w, /resources/img/blog/pattern-test/phpstorm-1764x820.png 1764w, /resources/img/blog/pattern-test/phpstorm-1577x733.png 1577w, /resources/img/blog/pattern-test/phpstorm-788x366.png 788w, /resources/img/blog/pattern-test/phpstorm-2-1676x1294.png 2w" sizes="" alt=""></img></p>
<p>But still… hundreds, potentially thousands, of tests in the same file doesn't seem like an approach that would work in the long run.</p>
<p>Data providers gave me another idea though. What if there's one "main test" that's responsible for testing all patterns, but what if its data provider entries were aggregated from separate files?</p>
<p>What if…</p>
<p>What if I kept patterns and their specific tests together? Would that be possible?</p>
<p>Definitely! How about using attributes on the pattern class itself?</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">PatternTest</span>(<span class="hl-property">input</span>: '<span class="hl-value">new Foo()</span>', <span class="hl-property">output</span>: '<span class="hl-value">Foo</span>')]</span></span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">PatternTest</span>(<span class="hl-property">input</span>: '<span class="hl-value">(new Foo)</span>', <span class="hl-property">output</span>: '<span class="hl-value">Foo</span>')]</span></span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">PatternTest</span>(<span class="hl-property">input</span>: '<span class="hl-value">new Foo</span>', <span class="hl-property">output</span>: '<span class="hl-value">Foo</span>')]</span></span>
<span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">NewObjectPattern</span> <span class="hl-keyword">implements</span><span class="hl-type"> Pattern
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsPattern</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">new (?&lt;match&gt;[\w]+)</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTokenType</span>(): <span class="hl-type">TokenType</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">TokenType</span>::<span class="hl-property">TYPE</span>;
    }
}
</pre>
<p>With these attributes in place, I could now rewrite my data provider method like so:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">patterns</span>(): <span class="hl-type">Generator</span>
{
    <span class="hl-variable">$patternFiles</span> = <span class="hl-property">glob</span>(<span class="hl-property">__DIR__</span> . '<span class="hl-value">/../src/Languages/*/Patterns/**.php</span>');

    <span class="hl-keyword">foreach</span> (<span class="hl-variable"><span class="hl-variable">$patternFiles</span></span> <span class="hl-keyword">as</span> <span class="hl-variable"><span class="hl-variable">$patternFile</span></span>) {
        <span class="hl-variable"><span class="hl-variable">$className</span></span> = <span class="hl-property">str_replace</span>(
            <span class="hl-property">search</span>: [<span class="hl-property">__DIR__</span> . '<span class="hl-value">/../src/</span>', '<span class="hl-value">/</span>', '<span class="hl-value">.php</span>'],
            <span class="hl-property">replace</span>: ['<span class="hl-value">Tempest\\Highlight\\</span>', '<span class="hl-value">\\</span>', '<span class="hl-value"></span>'],
            <span class="hl-property">subject</span>: <span class="hl-variable"><span class="hl-variable">$patternFile</span></span>,
        );

        <span class="hl-variable"><span class="hl-variable">$reflectionClass</span></span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable"><span class="hl-variable">$className</span></span>);

        <span class="hl-variable"><span class="hl-variable">$attributes</span></span> = <span class="hl-variable"><span class="hl-variable">$reflectionClass</span></span>-&gt;<span class="hl-property">getAttributes</span>(<span class="hl-type">PatternTest</span>::<span class="hl-keyword">class</span>);

        <span class="hl-keyword">foreach</span> (<span class="hl-variable"><span class="hl-variable">$attributes</span></span> <span class="hl-keyword">as</span> <span class="hl-variable"><span class="hl-variable">$attribute</span></span>) {
            /** <span class="hl-value">@var</span> <span class="hl-type">PatternTest</span> <span class="hl-variable"><span class="hl-variable">$patternTest</span></span> */
            <span class="hl-variable">$patternTest</span> = <span class="hl-variable">$attribute</span>-&gt;<span class="hl-property">newInstance</span>();

            <span class="hl-keyword">yield</span> [<span class="hl-variable">$reflectionClass</span>-&gt;<span class="hl-property">newInstance</span>(), <span class="hl-variable">$patternTest</span>];
        }
    }
}
</pre>
<p>Let me quickly run you through what happens. First, the data provider scans all classes in the right directories:</p>
<pre><span class="hl-variable">$patternFiles</span> = <span class="hl-property">glob</span>(<span class="hl-property">__DIR__</span> . '<span class="hl-value">/../src/Languages/*/Patterns/**.php</span>');
</pre>
<p>Next, it gathers one of more <code><span class="hl-type">PatternTest</span></code> attributes from these classes:</p>
<pre><span class="hl-variable">$reflectionClass</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$className</span>);

<span class="hl-variable">$attributes</span> = <span class="hl-variable">$reflectionClass</span>-&gt;<span class="hl-property">getAttributes</span>(<span class="hl-type">PatternTest</span>::<span class="hl-keyword">class</span>);
</pre>
<p>Finally, each of those attributes is used to generate a test:</p>
<pre><span class="hl-keyword">foreach</span> (<span class="hl-variable">$attributes</span> <span class="hl-keyword">as</span> <span class="hl-variable">$attribute</span>) {
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">PatternTest</span> <span class="hl-variable">$patternTest</span> */</span>
    <span class="hl-variable">$patternTest</span> = <span class="hl-variable">$attribute</span>-&gt;<span class="hl-property">newInstance</span>();

    <span class="hl-keyword">yield</span> [<span class="hl-variable">$reflectionClass</span>-&gt;<span class="hl-property">newInstance</span>(), <span class="hl-variable">$patternTest</span>];
}
</pre>
<p>And… that's it! In this case, I find this approach to be very handy: whenever I create a new pattern class, the first thing I do is add a couple of pattern tests to it so that I have an example to look at. There's also no need to worry about performance overhead: the whole testsuite for <code>tempest/highlight</code> runs in 50ms.</p>
<p>The only downside to this approach is that you cannot run a <em>specific</em> pattern test on its own, without having first run the whole testsuite. PhpStorm is able to run data provider entries individually when they are listed within the data provider method, but filling that array dynamically of course prevents PhpStorm from detecting that.</p>
<p>You can rerun specific pattern tests when they failed, and I find that adding a good error message helps you to quickly find the problem:</p>
<p><img src="/resources/img/blog/pattern-test/phpstorm-2.png" srcset="/resources/img/blog/pattern-test/phpstorm-2-749x578.png 749w, /resources/img/blog/pattern-test/phpstorm-2-1059x817.png 1059w, /resources/img/blog/pattern-test/phpstorm-2-1298x1002.png 1298w, /resources/img/blog/pattern-test/phpstorm-2-1499x1157.png 1499w, /resources/img/blog/pattern-test/phpstorm-2-1676x1294.png 1676w" sizes="" alt=""></img></p>
<p>I'll acknowledge that this is indeed a minor downside to this approach. However, I find that for this specific use case, I'm saving lots of time, and I've removed the majority of friction while testing <code>tempest/highlight</code>. In the end, for me, it's a win.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2024-03-22T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Building a custom language in tempest/highlight ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/building-a-custom-language-in-tempest-highlight"/>

                <id>https://www.stitcher.io/blog/building-a-custom-language-in-tempest-highlight</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Yesterday, I wrote about the <em>why</em> of <a href="/blog/a-syntax-highlighter-that-doesnt-suck">making a new syntax highlighter</a>. Today I want to write about the <em>how</em>.</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/cZugbAR8Fyg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>Let's explain how <code>tempest/highlight</code> works by implementing a new language — <a href="https://laravel.com/docs/11.x/blade">Blade</a> is a good candidate. It looks something like this:</p>
<pre><span class="hl-keyword">@if</span>(! <span class="hl-keyword">empty</span>(<span class="hl-variable">$items</span>))
    &lt;<span class="hl-keyword">div</span> <span class="hl-property">class</span>=&quot;container&quot;&gt;
        Items: {{ <span class="hl-property">count</span>(<span class="hl-variable">$items</span>) }}.
    &lt;/<span class="hl-keyword">div</span>&gt;
<span class="hl-keyword">@endslot</span>
</pre>
<p>In order to build such a new language, you need to understand <em>three</em> concepts of how code is highlighted: <em>patterns</em>, <em>injections</em>, and <em>languages</em>.</p>
<h3 id="1.-patterns"><a href="#1.-patterns" class="heading-anchor">#</a> 1. Patterns</h3>
<p>A <em>pattern</em> represents part of code that should be highlighted. A <em>pattern</em> can target a single keyword like <code>return</code> or <code>class</code>, or it could be any part of code, like for example a comment: <code>/* this is a comment */</code> or an attribute: <code>#[Get(uri: '/')]</code>.</p>
<p>Each <em>pattern</em> is represented by a simple class that provides a regex pattern, and a <code>TokenType</code>. The regex pattern is used to match relevant content to this specific <em>pattern</em>, while the <code>TokenType</code> is an enum value that will determine how that specific <em>pattern</em> is colored.</p>
<p>Here's an example of a simple <em>pattern</em> to match the namespace of a PHP file:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Tempest\Highlight\IsPattern</span>;
<span class="hl-keyword">use</span> <span class="hl-type">Tempest\Highlight\Pattern</span>;
<span class="hl-keyword">use</span> <span class="hl-type">Tempest\Highlight\Tokens\TokenType</span>;

<span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">NamespacePattern</span> <span class="hl-keyword">implements</span><span class="hl-type"> Pattern
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsPattern</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">namespace (?&lt;match&gt;[\w\\\\]+)</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTokenType</span>(): <span class="hl-type">TokenType</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">TokenType</span>::<span class="hl-property">TYPE</span>;
    }
}
</pre>
<p>Note that each pattern must include a regex capture group that's named <code>match</code>. The content that matched within this group will be highlighted.</p>
<p>For example, this regex <code>namespace (?&lt;match&gt;[\w\\\\]+)</code> says that every line starting with <code>namespace</code> should be taken into account, but only the part within the named group <code>(?&lt;match&gt;…)</code> will actually be colored. In practice that means that the namespace name matching <code>[\w\\\\]+</code>, will be colored.</p>
<p>Yes, you'll need some basic knowledge of regex. Head over to <a href="https://regexr.com/">https://regexr.com/</a> if you need help, or take a look at the existing patterns in this repository.</p>
<p><strong>In summary:</strong></p>
<ul>
<li>Pattern classes provide a regex pattern that matches parts of code.</li>
<li>Those regexes should contain a group named <code>match</code>, which is written like so <code>(?&lt;match&gt;…)</code>, this group represents the code that will actually be highlighted.</li>
<li>Finally, a pattern provides a <code><span class="hl-type">TokenType</span></code>, which is used to determine the highlight style for the specific match.</li>
</ul>
<h3 id="2.-injections"><a href="#2.-injections" class="heading-anchor">#</a> 2. Injections</h3>
<p>Once you've understood patterns, the next step is to understand <em>injections</em>. <em>Injections</em> are used to highlight different languages within one code block. For example: HTML could contain CSS, which should be styled properly as well.</p>
<p>An <em>injection</em> will tell the highlighter that it should treat a block of code as a different language. For example:</p>
<pre>&lt;<span class="hl-keyword">div</span>&gt;
    &lt;<span class="hl-keyword">x-slot</span> <span class="hl-property">name</span>=&quot;styles&quot;&gt;
        &lt;<span class="hl-keyword">style</span>&gt;<span class="hl-keyword">
            body </span>{
                <span class="hl-property">background-color</span>: red;
            }
        &lt;/<span class="hl-keyword">style</span>&gt;
    &lt;/<span class="hl-keyword">x-slot</span>&gt;
&lt;/<span class="hl-keyword">div</span>&gt;
</pre>
<p>Everything within <code>&lt;<span class="hl-keyword">style</span>&gt;&lt;/<span class="hl-keyword">style</span>&gt;</code> tags should be treated as CSS. That's done by injection classes:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Tempest\Highlight\Highlighter</span>;
<span class="hl-keyword">use</span> <span class="hl-type">Tempest\Highlight\Injection</span>;
<span class="hl-keyword">use</span> <span class="hl-type">Tempest\Highlight\IsInjection</span>;

<span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">CssInjection</span> <span class="hl-keyword">implements</span><span class="hl-type"> Injection
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsInjection</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">&lt;style&gt;(?&lt;match&gt;(.|\n)*)&lt;\/style&gt;</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parseContent</span>(<span class="hl-injection"><span class="hl-type">string</span> $content, <span class="hl-type">Highlighter</span> $highlighter</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$highlighter</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$content</span>, '<span class="hl-value">css</span>');
    }
}
</pre>
<p>Just like patterns, an <em>injection</em> must provide a pattern. This pattern, for example, will match anything between style tags: <code>&lt;<span class="hl-keyword">style</span>&gt;(?&lt;<span class="hl-keyword">match</span>&gt;(.|\n)*)&lt;\/style&gt;</code>.</p>
<p>The second step in providing an <em>injection</em> is to parse the matched content into another language. That's what the <code><span class="hl-property">parseContent</span>()</code> method is for. In this case, we'll get all code between the style tags that was matched with the named <code>(?&lt;match&gt;…)</code> group, and parse that content as CSS instead of whatever language we're currently dealing with.</p>
<p><strong>In summary:</strong></p>
<ul>
<li>Injections provide a regex that matches a blob of code of language A, while in language B.</li>
<li>Just like patterns, injection regexes should contain a group named <code>match</code>, which is written like so: <code>(?&lt;match&gt;…)</code>.</li>
<li>Finally, an injection will use the highlighter to parse its matched content into another language.</li>
</ul>
<h3 id="3.-languages"><a href="#3.-languages" class="heading-anchor">#</a> 3. Languages</h3>
<p>The last concept to understand: <em>languages</em> are classes that bring <em>patterns</em> and <em>injections</em> together. Take a look at the <code><span class="hl-type">HtmlLanguage</span></code>, for example:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">HtmlLanguage</span> <span class="hl-keyword">extends</span> <span class="hl-type">BaseLanguage</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getInjections</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            ...<span class="hl-keyword">parent</span>::<span class="hl-property">getInjections</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">PhpInjection</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">PhpShortEchoInjection</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">CssInjection</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">CssAttributeInjection</span>(),
        ];
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPatterns</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            ...<span class="hl-keyword">parent</span>::<span class="hl-property">getPatterns</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">OpenTagPattern</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">CloseTagPattern</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">TagAttributePattern</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">HtmlCommentPattern</span>(),
        ];
    }
}

</pre>
<p>This <code><span class="hl-type">HtmlLanguage</span></code> class specifies the following things:</p>
<ul>
<li>PHP can be injected within HTML, both with the short echo tag <code>&lt;?=</code> and longer <code>&lt;?php</code> tags</li>
<li>CSS can be injected as well, JavaScript support is still work in progress</li>
<li>There are a bunch of patterns to highlight HTML tags properly</li>
</ul>
<p>On top of that, it extends from <code><span class="hl-type">BaseLanguage</span></code>. This is a language class that adds a bunch of cross-language injections, such as blurs and highlights. Your language doesn't <em>need</em> to extend from <code><span class="hl-type">BaseLanguage</span></code> and could implement <code><span class="hl-type">Language</span></code> directly if you want to.</p>
<p>With these three concepts in place, let's bring everything together to explain how you can add your own languages.</p>
<h3 id="adding-custom-languages"><a href="#adding-custom-languages" class="heading-anchor">#</a> Adding custom languages</h3>
<p>So we're adding <a href="https://laravel.com/docs/11.x/blade">Blade</a> support. We could create a new language class and start from scratch, but it'd probably be easier to extend an existing language, <code><span class="hl-type">HtmlLanguage</span></code> is probably the best. Let create a new <code><span class="hl-type">BladeLanguage</span></code> class that extends from <code><span class="hl-type">HtmlLanguage</span></code>:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BladeLanguage</span> <span class="hl-keyword">extends</span> <span class="hl-type">HtmlLanguage</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getInjections</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            ...<span class="hl-keyword">parent</span>::<span class="hl-property">getInjections</span>(),
        ];
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPatterns</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            ...<span class="hl-keyword">parent</span>::<span class="hl-property">getPatterns</span>(),
        ];
    }
}
</pre>
<p>With this class in place, we can start adding our own patterns and injections. Let's start with adding a pattern that matches all Blade keywords, which are always prepended with the <code>@</code> sign. Let's add it:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BladeKeywordPattern</span> <span class="hl-keyword">implements</span><span class="hl-type"> Pattern
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsPattern</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">(?&lt;match&gt;\@[\w]+)\b</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTokenType</span>(): <span class="hl-type">TokenType</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">TokenType</span>::<span class="hl-property">KEYWORD</span>;
    }
}
</pre>
<p>And register it in our <code><span class="hl-type">BladeLanguage</span></code> class:</p>
<pre>    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPatterns</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            ...<span class="hl-keyword">parent</span>::<span class="hl-property">getPatterns</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">BladeKeywordPattern</span>(),
        ];
    }
</pre>
<p>Next, there are a couple of places within Blade where you can write PHP code: within the <code><span class="hl-keyword">@php</span></code> keyword, as well as within keyword brackets: <code><span class="hl-keyword">@if</span> (<span class="hl-property">count</span>(…))</code>. Let's write two injections for that:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BladePhpInjection</span> <span class="hl-keyword">implements</span><span class="hl-type"> Injection
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsInjection</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">\@php(?&lt;match&gt;(.|\n)*?)\@endphp</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parseContent</span>(<span class="hl-injection"><span class="hl-type">string</span> $content, <span class="hl-type">Highlighter</span> $highlighter</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$highlighter</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$content</span>, '<span class="hl-value">php</span>');
    }
}
</pre>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BladeKeywordInjection</span> <span class="hl-keyword">implements</span><span class="hl-type"> Injection
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsInjection</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">(\@[\w]+)\s?\((?&lt;match&gt;.*)\)</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parseContent</span>(<span class="hl-injection"><span class="hl-type">string</span> $content, <span class="hl-type">Highlighter</span> $highlighter</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$highlighter</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$content</span>, '<span class="hl-value">php</span>');
    }
}
</pre>
<p>Let's add these to our <code><span class="hl-type">BladeLanguage</span></code> class as well:</p>
<pre>    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getInjections</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            ...<span class="hl-keyword">parent</span>::<span class="hl-property">getInjections</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">BladePhpInjection</span>(),
            <span class="hl-keyword">new</span> <span class="hl-type">BladeKeywordInjection</span>(),
        ];
    }
</pre>
<p>Next, you can write <code>{{ … }}</code> and <code>{!! … !!}</code> to echo output. Whatever is between these brackets is also considered PHP, so, one more injection:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BladeEchoInjection</span> <span class="hl-keyword">implements</span><span class="hl-type"> Injection
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsInjection</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">({{|{!!)(?&lt;match&gt;.*)(}}|!!})</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parseContent</span>(<span class="hl-injection"><span class="hl-type">string</span> $content, <span class="hl-type">Highlighter</span> $highlighter</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$highlighter</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$content</span>, '<span class="hl-value">php</span>');
    }
}
</pre>
<p>And, finally, you can write Blade comments like so: <code>{{-- --}}</code>, this can be a simple pattern:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BladeCommentPattern</span> <span class="hl-keyword">implements</span><span class="hl-type"> Pattern
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">IsPattern</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPattern</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">(?&lt;match&gt;\{\{\-\-(.|\n)*?\-\-\}\})</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTokenType</span>(): <span class="hl-type">TokenType</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">TokenType</span>::<span class="hl-property">COMMENT</span>;
    }
}
</pre>
<p>With all of that in place, the only thing left to do is to add our language to the highlighter:</p>
<pre><span class="hl-variable">$highlighter</span>-&gt;<span class="hl-property">addLanguage</span>('<span class="hl-value">blade</span>', <span class="hl-keyword">new</span> <span class="hl-type">BladeLanguage</span>());
</pre>
<p>And we're done! Blade support with just a handful of patterns and injections!</p>
<p>I think that the ability to extend from other languages and language injections are both really powerful to be able to quickly build new languages. Of course, <strong>you're free to <a href="https://github.com/tempestphp/highlight">send pull requests</a> with support for additional languages as well! Take a look at the <a href="https://github.com/tempestphp/highlight/tree/main/tests/Languages">package's tests</a> to learn how to write tests for patterns and injections.</strong></p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2024-03-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ A syntax highlighter that doesn&#039;t suck ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-syntax-highlighter-that-doesnt-suck"/>

                <id>https://www.stitcher.io/blog/a-syntax-highlighter-that-doesnt-suck</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It all started with Aidan sending me this message:</p>
<blockquote>
<p>Huh. Isn't there a better way to do syntax highlighting for that?</p>
</blockquote>
<p>He was talking about code blocks for the upcoming <a href="https://tempest.stitcher.io/">Tempest docs</a> site. I must say I wasn't surprised by his question, although I had hoped he wouldn't ask it.</p>
<p>I wrote code blocks like so:</p>
<pre>public function store(&lt;hljs type&gt;BookRequest&lt;/hljs&gt; $request)</pre>
<p>That's right, I manually add and parse special "highlight" tokens in them. Take a look at, for example, the source of my latest <a href="https://github.com/brendt/stitcher.io/blob/master/src/content/blog/2023-03-17-new-in-php-83.md">what new in PHP 8.3</a> post. Lots of <code>hljs</code> tags everywhere.</p>
<p>Of course, I don't do this without reason. I used <a href="https://highlightjs.org/">highlight.js</a> for years, and found it increasingly frustrating that it didn't render code blocks correctly — especially modern PHP syntax. Maybe three or four years ago, I switched to <a href="https://github.com/scrivo/highlight.php">highlight.php</a>, a PHP port of highlight.js. It wasn't any better than highlight.js, but at least it did its rendering server-side, which is always a good thing.</p>
<p>The major benefit of server-side rendering, was that I was able to add a small parser on top of it. With it, I could control my code block's styling when it didn't work exactly right. Hello <code>hljs</code> tags!</p>
<p>Maybe it's just me, but I really cannot stand wrongly highlighted code blocks, so I was willing to do whatever it takes to get it right. Even if it meant manual work for every single code block I'd write. It's one of these things I got used to over time though, and I didn't really question it anymore. Shortly after adding my custom syntax, I added keyboard shortcuts to wrap selected text in <code>hljs</code> tokens, so it wasn't even that much a bother — to me, at least.</p>
<p>However, when I started drafting the Tempest docs, I knew deep down that this solution wouldn't work long-term. Tempest — and that includes its documentation — is an open source project. If one of the goals is for people to contribute, then I can't expect them to learn a quirky syntax I came up with a couple of years ago.</p>
<p>So, yes, Aidan's right to ask this question.</p>
<blockquote>
<p>Isn't there a better way to do syntax highlighting for that?</p>
</blockquote>
<p>"No problem", I told him, "I'll find a replacement!" Originally I had other plans that day, but I imagined it wouldn't be so hard to switch to another highlighter. It's a couple of years later, surely there will be a better solution now.</p>
<p>Right?</p>
<p>First, I looked at highlight.js again. It was still rendering PHP code as if it was PHP 7.4. Stuff like attributes, function names, and some types weren't highlighted at all. Unacceptable.</p>
<p>Next, I looked at <a href="https://torchlight.dev/">Torchlight</a>. As far as I knew, it's a "highlighter as a service" (it's also a game I used to play, but that's irrelevant). Torchlight was created a year or two ago, and I heard pretty good things of it. I believe the Laravel docs uses it.</p>
<p>I had high hopes for Torchlight. They had a free plan for open source projects, so let's go!!</p>
<p>Unfortunately, one small issue: it only works in Laravel projects. Torchlight requires Laravel facades to be booted in order to work. That would mean manually booting up Laravel in a project that's not using Laravel at all. On top of that, Torchlight makes API requests, so I figured it wouldn't be the most performant solution anyway. The way I write content is by doing lots of refreshes, and I need changes to be instantly visible. So, Torchlight was out.</p>
<p>Next on my list was <a href="https://github.com/shikijs/shiki">Shiki</a>, which has a <a href="https://github.com/spatie/shiki-php">PHP wrapper</a>. Shiki supports TextMate grammar, which is used for syntax highlighting in many editors. In general, it's  much more accurate than something like highlight.js, <em>and</em> you can run it server-side. Nice!</p>
<p>Remember what I said about performance though? Yeah… Shiki is slow. Like, super slow. It took more than 10 seconds to render the <a href="https://tempest.stitcher.io/02-controllers">Controllers docs page</a>, which only includes a handful of code blocks.</p>
<p>Sure, one "solution" to that is caching, but when I'm writing, I want things to appear instantly. Even with caching, you'd still look at 1-2 second page refreshes when you're making changes to code blocks, which — to me — is unacceptable.</p>
<p>At this point I was becoming frustrated. Surely it can't be that there is no proper solution to syntax highlighting that satisfies these three requirements??</p>
<ul>
<li>Fast enough so that page load times are tolerable without caching during development.</li>
<li>Server-side rendered, it's just text after all; why would you bother all clients to do more work while the server could do it once?</li>
<li>Support proper PHP syntax, or at least provide an easy way to add new syntax outside the package's core, so that new PHP syntax (or other languages) will have support immediately when people need it.</li>
</ul>
<p>"HOW HARD CAN IT BE?" — I asked Aidan in frustration, ready to give up. "We'll stick with my quirky syntax, and I'll manually add <code>hljs</code> tags afterward whenever people send PRs. Good enough."</p>
<p>But Aidan wasn't ready to let go:</p>
<blockquote>
<p>I’m very determined to find a solution to this syntax highlighting problem though.</p>
</blockquote>
<p>With these words of "encouragement", I decided to consider one final option. Let's write something myself. It's just syntax highlighting — "how hard can it be?" If I wasn't able to get something working in a couple of hours, I could still abandon the idea.</p>
<p>"Working on it", I told Aidan.</p>
<p>What happened during the next two days is hard to describe, but you probably recognise the feeling nevertheless: being so deep into "the zone" and determined to solve a problem that everything else must give way.</p>
<p>It took a couple of iterations, some dreaming about it during the night — I tend to dream about code when I'm deep into a project, nothing to worry about. But yesterday morning, everything fell into place.</p>
<p>This is what I sent Aidan at 6:57 AM:</p>
<blockquote>
<p>Ok Aidan, I need you to keep calm. Ok?</p>
<p>EVERYTHING WORKS 😱😱😱😱😱😱😱😱</p>
</blockquote>
<p>Ok, not <em>everything</em> worked, but all important things <em>did</em>:</p>
<ul>
<li>Server-side rendered highlights</li>
<li>Fast enough to handle stuff without any caching</li>
<li>Accurate syntax highlighting</li>
<li>
<a href="/blog/building-a-custom-language-in-tempest-highlight">An easy API to add new languages</a>
</li>
<li>Language injection support, so that you can combine multiple languages within one codeblock (it's actually pretty neat)</li>
</ul>
<p>And so… I'd like to present, a code highlighter that doesn't suck: <a href="https://github.com/tempestphp/highlight">tempest/highlight</a>.</p>
<p>Ok, it still sucks a bit, because I still need to add more languages, and there will probably be some inaccuracies within the languages I already added (PHP, HTML, CSS, and Blade). But: the foundation is there, and it works. I'm actually already using it on the Tempest docs site, because why not?</p>
<p>I'm now going to switch this blog over as well, though I will keep the backwards compatibility option for now, because I don't want to be bothered with updating hundreds of past blog posts.</p>
<p>So, if you're in need for a code highlighter that doesn't suck, feel free to check out <a href="https://github.com/tempestphp/highlight">tempest/highlight</a>! Also, if you're looking for an open source project to contribute to: I more than welcome PRs! (The README gives you more info on how to get started.)</p>
<p>PS: give it a star as well while you're there 😉</p>
<p>PPS: here's a code block rendered with the new highlighter:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BookController</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>(<span class="hl-property">uri</span>: '<span class="hl-value">/books/{book}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">Book</span> $book, <span class="hl-type">User</span> $user</span>): <span class="hl-type">View</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">Front/books/detail.view.php</span>',
            <span class="hl-property">book</span>: <span class="hl-variable">$book</span>,
            <span class="hl-property">user</span>: <span class="hl-variable">$user</span>,
        );
    }
}
</pre>
<p>PPPS: here's a vlog showing the initial implementation of this package:</p>
<iframe width="560" height="345" src="https://www.youtube.com/embed/cZugbAR8Fyg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 ]]></summary>

                <updated>2024-03-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The framework that gets out of your way ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/the-framework-that-gets-out-of-your-way"/>

                <id>https://www.stitcher.io/blog/the-framework-that-gets-out-of-your-way</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>This post was first published for my newsletter subscribers. You can subscribe by mailing <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>.</em></p>
<p>Half a year ago, I wrote this:</p>
<blockquote>
<p>Ok, so, I've started working on something — probably the biggest project I've worked on in a while — and I'm having a blast. I'm building… A framework 😳</p>
</blockquote>
<p>If you haven't heard of that framework before — it's called Tempest — you could check out me building the foundations of it during <a href="https://www.youtube.com/playlist?list=PL0bgkxUS9EaILnUL8Q4np6B3qxjQbE7PH">several livestreams</a>.</p>
<p>I had a break working on Tempest for a couple of months because of other projects, but recently I started diving into it again. I've actually used it to build a small website, and let me tell you: I really enjoyed it.</p>
<p>That probably shouldn't come as a surprise since I built it the way I like to build things. But still, I was very happy seeing all pieces fit together so perfectly. Granted: there is a lot more fine-tuning to do, but I do think there's some potential here.</p>
<p>To be clear: Tempest doesn't aim to replace any frameworks like Laravel or Symfony; but for getting smaller PHP websites up and running? I feel like there's a lot of potential for a small and modern framework.</p>
<p>I especially like how Tempest gets out of your way. There's no need for config files or any setup, Tempest understands your code. I'm not kidding, <a href="https://twitter.com/brendt_gd/status/1757043283656667420">it works really well</a>.</p>
<p>So, I'd say go check out a very pre-alpha version of what undoubtedly will become something great in the future: <a href="https://github.com/tempestphp/tempest-framework">https://github.com/tempestphp/tempest-framework</a>.</p>
<h2 id="on-a-personal-note"><a href="#on-a-personal-note" class="heading-anchor">#</a> On a personal note</h2>
<p>Much to my frustration, I've been sick since mid-December. Nothing serious, just a very annoying cough that doesn't want to go away. I've seen my doctor numerous times, a specialist, I'm using an inhaler, nasal spray, tried antacids, nothing seems to work. I actually have had the same issue for multiple years now: periods of coughing without any clear reason or solution.</p>
<p>Like I said, it's not too serious, just an annoying cough that doesn't want to go away, though it is very limiting when trying to record videos or audio. The more I talk, the worse it gets, so proper recording sessions aren't really an option right now. That three-minute video about Tempest I linked a couple paragraphs ago took waaaaay too much time and editing to get all the coughs out…</p>
<p>That's why I've been rather quiet on <a href="https://www.youtube.com/@phpannotated">PHP Annotated</a>, and why I've mostly focussed on writing content for PhpStorm lately. Last week, the first post in a series about JetBrains' <a href="https://blog.jetbrains.com/phpstorm/2024/02/ai-for-php-how-to-automate-unit-testing-using-ai-assistant/">AI Assistant for Unit Testing</a> went live, and I've got a couple more scheduled soon.</p>
<p>I <em>really</em> hope my coughing gets over soon, and I <em>really</em> hope we'll find a proper solution. I've got another doctor's appointment scheduled next week and hope new medication will have a better impact.</p>
<p>Anyway, I mainly wanted to share this with you in case people were wondering why PHP Annotated is so quiet lately. I really want to get back into it a soon as possible though!</p>
<p>That's it for today's newsletter, do check out <a href="https://github.com/tempestphp/tempest-framework">Tempest</a> <em>and give it a star while you're there</em> 😉</p>
<p>Until next time</p>
<p>Brent</p>
<p>PS: I feel real inspired to livestream today. I'm still coughing, but I hope I'll manage. Come say hi:</p>
<iframe width="560" height="420" src="https://www.youtube.com/embed/Hf09ZCY9-8I" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 ]]></summary>

                <updated>2024-02-19T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP version stats: January, 2024 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-version-stats-january-2024"/>

                <id>https://www.stitcher.io/blog/php-version-stats-january-2024</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's time for another version stats post! This is my biyearly summary of which PHP versions are used across the community. You can read the previous edition <a href="/blog/php-version-stats-july-2023">here</a>, but I'll also include historic data in this post.</p>
<p>Keep in mind note that I'm working with the data available. That means that these charts are not a 100% accurate representation of the PHP community as a whole, but they <em>are</em> an accurate representation of one of the most prominent parts of PHP: the <a href="https://packagist.org/php-statistics">packagist ecosystem</a>.</p>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<h2 id="usage-statistics"><a href="#usage-statistics" class="heading-anchor">#</a> Usage Statistics</h2>
<p>Let's start with the percentage of PHP versions being used today, and compare it to the previous three editions, note that I've omitted all versions that don't have more than 1% usage:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2022-07</td>
    <td>2023-01</td>
    <td>2023-07</td>
    <td>2024-01</td>
</tr>
<tr>
    <td>7.1</td>
    <td>1.9%</td>
    <td>1.8%</td>
    <td>1.3%</td>
    <td>1.0%</td>
</tr>
<tr>
    <td>7.2</td>
    <td>5.1%</td>
    <td>4.3%</td>
    <td>4.3%</td>
    <td>2.5%</td>
</tr>
<tr>
    <td>7.3</td>
    <td>8.0%</td>
    <td>5.3%</td>
    <td>4.2%</td>
    <td>3.2%</td>
</tr>
<tr>
    <td>7.4</td>
    <td>38.4%</td>
    <td>27.7%</td>
    <td>19.9%</td>
    <td>13.6%</td>
</tr>
<tr>
    <td>8.0</td>
    <td>20.6%</td>
    <td>16.2%</td>
    <td>12.3%</td>
    <td>7.2%</td>
</tr>
<tr>
    <td>8.1</td>
    <td>24.5%</td>
    <td>38.8%</td>
    <td>39.3%</td>
    <td>35.2%</td>
</tr>
<tr>
    <td>8.2</td>
    <td>0.0%</td>
    <td>4.7%</td>
    <td>17.2%</td>
    <td>29.4%</td>
</tr>
<tr>
    <td>8.3</td>
    <td>0.0%</td>
    <td>0.0%</td>
    <td>0.2%</td>
    <td>6.4%</td>
</tr>
</table>
</div>
<p>Visualizing this data looks like this:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2024-jan-01.svg"><img src="/resources/img/blog/version-stats/2024-jan-01.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2024-jan-01.svg">Evolution of version usage</a></em></p>
<p>There seems to be a slightly faster adoption of PHP 8.3 compared to PHP 8.2: 6.4% of projects are using PHP 8.3 within the first two months of its release, for PHP 8.2 it  was 4.7%.</p>
<p>Furthermore, the PHP 7.* share continues to shrink — a good thing given that support for the 7.* series ended more than a year ago. Right now PHP 8.1 is the oldest supported version, only receiving security updates until November 25 this year. I can't help it, I keep saying the same thing over and over again, <a href="/blog/a-storm-in-a-glass-of-water">it's important update your PHP installations</a>!</p>
<p>Moving on to the all-time overview chart, here you can see the evolution of version usage across time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2024-jan-02.svg"><img src="/resources/img/blog/version-stats/2024-jan-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2024-jan-02.svg">All time evolution</a></em></p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="required-versions"><a href="#required-versions" class="heading-anchor">#</a> Required versions</h2>
<p>Next, I used Nikita's <a target="_blank" href="https://github.com/nikic/popular-package-analysis">popular package analyzer</a> to download the 1000 most popular composer packages. I use a script that scans these packages to determine their minimum required version. Here are the results:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2022-07</td>
    <td>2023-01</td>
    <td>2023-07</td>
    <td>2024-01</td>
</tr>
<tr>
    <td>5.2</td>
    <td>10</td>
    <td>10</td>
    <td>7</td>
    <td>7</td>
</tr>
<tr>
    <td>5.3</td>
    <td>77</td>
    <td>78</td>
    <td>65</td>
    <td>58</td>
</tr>
<tr>
    <td>5.4</td>
    <td>40</td>
    <td>40</td>
    <td>31</td>
    <td>28</td>
</tr>
<tr>
    <td>5.5</td>
    <td>35</td>
    <td>37</td>
    <td>21</td>
    <td>16</td>
</tr>
<tr>
    <td>5.6</td>
    <td>42</td>
    <td>43</td>
    <td>32</td>
    <td>30</td>
</tr>
<tr>
    <td>7.0</td>
    <td>29</td>
    <td>30</td>
    <td>24</td>
    <td>24</td>
</tr>
<tr>
    <td>7.1</td>
    <td>153</td>
    <td>159</td>
    <td>125</td>
    <td>100</td>
</tr>
<tr>
    <td>7.2</td>
    <td>130</td>
    <td>144</td>
    <td>133</td>
    <td>123</td>
</tr>
<tr>
    <td>7.3</td>
    <td>104</td>
    <td>106</td>
    <td>56</td>
    <td>49</td>
</tr>
<tr>
    <td>7.4</td>
    <td>86</td>
    <td>98</td>
    <td>97</td>
    <td>87</td>
</tr>
<tr>
    <td>8.0</td>
    <td>94</td>
    <td>103</td>
    <td>144</td>
    <td>126</td>
</tr>
<tr>
    <td>8.1</td>
    <td>125</td>
    <td>129</td>
    <td>107</td>
    <td>154</td>
</tr>
<tr>
    <td>8.2</td>
    <td>-</td>
    <td>-</td>
    <td>94</td>
    <td>135</td>
</tr>
<tr>
    <td>8.3</td>
    <td>-</td>
    <td>-</td>
    <td>-</td>
    <td>0</td>
</tr>
</table>
</div>
<p>There are two important notes to make here.</p>
<ol>
<li>This tables shows the <strong>minimum required version</strong>. That means that packages with a minimal version of, for example, 8.0, could also support PHP 8.1, PHP 8.2, and PHP 8.3.</li>
<li>If you count the numbers, you'll notice there are some differences between each year. Not every package lists a valid version string.</li>
</ol>
<br>
<p>Instead of comparing absolute numbers, it's best to plot this data into a chart for a relative comparison, so that we can see changes over time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2024-jan-03.svg"><img src="/resources/img/blog/version-stats/2024-jan-03.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2024-jan-03.svg">Minimal PHP requirement over time</a></em></p>
<p>Talking about progression, I'd like to remind open source maintainers about the power and responsibility they hold. Imagine if all modern open source packages only supported PHP versions that were actively worked on. My suspicion is that many more projects would be encouraged to update faster; eventually leading to a healthier, more performant, and more secure ecosystem. Open source maintainers yield quite a lot of power in this regard.</p>
<p>Also keep in mind that forcing a new minimal PHP requirement doesn't automatically block older projects from using your code: outdated projects can still download older versions of your packages, so there's really no good argument not to do it from a package maintainer's point of view.</p>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<p>That's all data I have to share for this edition of PHP's version stats. You can always reach me via <a href="mailto:brendt@stitcher.io">email</a> if you want to share your thoughts or have questions.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2024-01-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Passion projects ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/passion-projects"/>

                <id>https://www.stitcher.io/blog/passion-projects</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Do you remember when you fell in love with programming? It probably wasn't while you were learning code at school or online, or working on a client project.</p>
<p>You can probably relate. That moment when you were writing code because you wanted to, no, because you <em>desired</em> to. No deadlines, no pressure. Only that feeling of power, being able to create something from nothing <em>with code</em>. It could be something as simple as an HTML web page, a program on your calculator to — <em>hmm</em> — cheat on your maths exam, or hacking something together for a game you're playing.</p>
<p>For me, at least, those are some of the examples that resonate.</p>
<p>I'm writing this as a reminder to myself and whoever needs to hear it: don't forget that time when your programming passion sparked. You're older now, you've got other things to do, you have <em>responsibilities</em> now. You might never experience the same amount of joy compared to that first year of programming, behind the computer in the living room while your siblings were playing, making lots of noise and distracting you.</p>
<p>But you <em>can</em> still find passion projects. Keep an open mind. Write a game, a website, a book, whatever. Not because you must, not to impress your social media following, not to make a living out of it — but because you can, because it gives you joy.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2023-12-13T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ I don&#039;t know ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/i-dont-know"/>

                <id>https://www.stitcher.io/blog/i-dont-know</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Being online, I've gotten the impression that two groups of PHP developers are seriously divided: there are Symfony devs saying that Laravel is a hacky framework that leads to disaster, and there are Laravel devs saying that Symfony is a bloated framework that takes huge amounts of time to get things done.</p>
<p>I've always assumed this mentality existed mostly thanks to "being online", and that when it came to face-to-face interactions, people would be more forgiving towards each other.</p>
<p>Apparently, that assumption is wrong 😅</p>
<p>Last week, I went to SymfonyCon, and a year ago I went to Laracon. It turns out people are as harsh towards the other community in real life as they are online.</p>
<p>I'm baffled by this sentiment. There's no denying that people are building successful things with Symfony, just like there's no denying people are building successful things with Laravel. Why does anyone feel the need to convince me or others that their choice is superior? Why do we feel the need to pick sides? Why does it matter that someone else uses another solution to the same problem, if they manage to solve that problem equally well? Why do we feel the need to identify so strongly with a framework, that we need to dismiss the other?</p>
<p>I don't know.</p>
<p>Maybe we should say that more often: "I don't know", especially when it comes to the other side, and give them the benefit of the doubt.</p>
<p>What are your thoughts? Have you had the same experience? Maybe completely the opposite? <a href="mailto:brendt@stitcher.io">Let me know</a>!</p>
<p>PS: there were also a bunch of nice people at both SymfonyCon and Laracon, maybe that's good to mention as well 😁</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2023-12-12T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The RFC Vote project ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/rfc-vote"/>

                <id>https://www.stitcher.io/blog/rfc-vote</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been head over heels into programming the past two weeks. I started a new open source project, and it's been going great! Today, I want to share a bit of what's going on, and hope to peak your interest as well.</p>
<p>Two weeks ago, I had a chat with my colleague Roman about how PHP is evolving: we both want to get a better understanding of how the community feels about RFCs. While technically, the internals mailing list is open to everyone, I know only a very small group of PHP developers who actually participate. So we decided to build a small app that could help us and the community to lower the bar for participation.</p>
<p>Its temporary name is "RFC Vote" — but please share your ideas if you have better names! It's a small project that allows everyone to vote for RFCs. The most interesting part though is <em>how</em> you vote: if you vote directly, you <em>must</em> give argumentation to explain why you voted yes or no. On top of that: everyone can vote for existing arguments individually. Say someone already shared the same reasons as you for voting yes or no, then you can simply vote for that argument, instead of writing something on your own — argument votes are added to the total result as well.</p>
<p>We hope that by using this vote mechanic, we'll get better insights into <em>why</em> people vote the way they do, and not just <em>if</em> people would like a feature or not. And, <em>maybe</em> — we can even inspire internal developers to take a look at the community results, before casting their own vote for upcoming RFCs.</p>
<p>Here's an except from our <a href="https://rfc.stitcher.io/about">about page</a>:</p>
<blockquote>
<p>This project is dedicated to providing a platform for the PHP community to express their thoughts and feelings about the proposals for the PHP language in an easier way.</p>
<p>Our main goal is to visualize the diverse opinions and arguments surrounding PHP's proposed features, making it easier to understand the benefits and downsides of each proposal. By doing so, we hope to foster a greater understanding of how PHP developers feel about these changes.</p>
<p>While official voting on RFCs is limited to internal qualified developers and a specific group of contributors, RFC Vote offers a space for everyone in the PHP community to share their voice. Your votes and comments won't directly influence the official PHP RFC outcomes, but they can serve as valuable insights for those involved in the decision-making process.</p>
<p>In addition to casting a vote, you are encouraged to share your reasoning behind your choices on each RFC. By explaining why you voted yes or no, we can collectively gain better insights into the popularity or concerns associated with an RFC. This collaborative approach allows us to learn from one another and contributes to a more informed and connected PHP community.</p>
</blockquote>
<p>So, next thing I knew, I was <a href="https://github.com/brendt/rfc-vote">programming</a> like a madman, did some <a href="https://www.youtube.com/playlist?list=PL0bgkxUS9EaLguM2puiMD-NiiV6r5b8RY">livestreams</a> to show off the progress, and got help from <a href="https://github.com/brendt/rfc-vote/graphs/contributors">9 other developers</a>.</p>
<p>After two weeks, we're nearing a "version 1", and so I wanted to share it with you as well. Maybe you have some ideas, questions, or just want to take a look? Well, the site is already live here: <a href="https://rfc.stitcher.io/">https://rfc.stitcher.io/</a>, and you can check out the code on <a href="https://github.com/brendt/rfc-vote">GitHub</a>.</p>
<p><a href="mailto:brendt@stitcher.io">Let me know your thoughts</a>!</p>
<p>Oh, by the way, I'll be doing another live stream at 11 CEST today (less than 2 hours from when this post was published), so you might want to tune in? I'll see you there!</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/pUJ0oES1nYg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 ]]></summary>

                <updated>2023-08-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What&#039;s new in PHP 8.3 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-in-php-83"/>

                <id>https://www.stitcher.io/blog/new-in-php-83</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><iframe width="560" height="422" src="https://www.youtube.com/embed/nJFsD0bnlTI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<div class="sidenote">
<p><strong>PHP 8.3 will be released on <a href="https://wiki.php.net/todo/php83">November 23, 2023</a></strong>; it has improvements to readonly classes, the new <code>json_validate()</code> function, additions to the recently added <code>Randomizer</code> class, stack overflow detection, and more.</p>
<p>In this post, we'll go through all features, performance improvements, changes and deprecations one by one. If you want to stay up to date, you can <a href="/mail">subscribe to my newsletter</a>, <a href="/twitter">follow me on Twitter</a>, or <a href="/rss">subscribe to my RSS feed</a>.</p>
</div>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h3 id="readonly-amendments-rfc"><a href="#readonly-amendments-rfc" class="heading-anchor">#</a> Readonly amendments <small><a target="_blank" href="https://wiki.php.net/rfc/readonly_amendments">RFC</a></small></h3>
<p>This RFC proposed two changes, only one was accepted: being able to reinitialize readonly properties while cloning. That might sound like a very big deal, but this RFC only addresses a very specific (but important) edge case: overwriting property values within <code>__clone()</code>, in order to allow deep cloning readonly properties.</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">DateTime</span> <span class="hl-property">$createdAt</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__clone</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">createdAt</span> = <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>(); 
        <span class="hl-comment">// This is allowed,</span>
        <span class="hl-comment">// even though `createdAt` is a readonly property.</span>
    }
}
</pre>
<p>You can read an in-depth post about this RFC and some sidenotes <a href="/blog/cloning-readonly-properties-in-php-83">here</a>.</p>
<hr />
<h3 id="typed-class-constants-rfc"><a href="#typed-class-constants-rfc" class="heading-anchor">#</a> Typed class constants <small><a target="_blank" href="https://wiki.php.net/rfc/typed_class_constants">RFC</a></small></h3>
<p>You can now typehint class constants:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">const</span> <span class="hl-type">string</span> <span class="hl-property">BAR</span> = '<span class="hl-value">baz</span>'; 
} 
</pre>
<hr />
<h3 id="#[override]-attribute-rfc"><a href="##[override]-attribute-rfc" class="heading-anchor">#</a> <code>#[Override]</code> attribute <small><a target="_blank" href="https://wiki.php.net/rfc/marking_overriden_methods">RFC</a></small></h3>
<p>The new <code>#[Override]</code> attribute is used to show a programmer's intent. It basically says "I know this method is overriding a parent method. If that would ever change, please let me know".</p>
<p>Here's an example:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Parent</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">methodWithDefaultImplementation</span>(): <span class="hl-type">int</span>
    {
        <span class="hl-keyword">return</span> 1;
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Child</span> <span class="hl-keyword">extends</span> <span class="hl-type">Parent</span>
{
    <span class="hl-attribute">#[<span class="hl-type">Override</span>]</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">methodWithDefaultImplementation</span>(): <span class="hl-type">int</span>
    {
        <span class="hl-keyword">return</span> 2; <span class="hl-comment">// The overridden method</span>
    }
} 
</pre>
<p>Now, let's imagine at one point the parent method changes its method name:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Parent</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">methodWithNewImplementation</span>(): <span class="hl-type">int</span>
    {
        <span class="hl-keyword">return</span> 1;
    }
}
</pre>
<p>Thanks to the <code>#[Override]</code> attribute, PHP will be able to detect that <code>Child::methodWithDefaultImplementation()</code> doesn't override anything anymore, and it will throw an error.</p>
<p>You can <a href="/blog/override-in-php-83">read more about the <code>#[Override]</code> attribute here</a>.</p>
<hr />
<h2 id="negative-indices-in-arrays-breaking"><a href="#negative-indices-in-arrays-breaking" class="heading-anchor">#</a> Negative indices in arrays <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING#L19">breaking</a></small></h2>
<p>If you have an empty array, add an item with a <em>negative</em> index, and then add another item, that second item would always start at index <code>0</code>:</p>
<pre><span class="hl-variable">$array</span> = [];

<span class="hl-variable">$array</span>[-5] = '<span class="hl-value">a</span>';
<span class="hl-variable">$array</span>[] = '<span class="hl-value">b</span>';

<span class="hl-property">var_export</span>(<span class="hl-variable">$array</span>);

<span class="hl-comment">//array (</span>
<span class="hl-comment">//  -5 =&gt; 'a',</span>
<span class="hl-comment">//  0 =&gt; 'b',</span>
<span class="hl-comment">//)</span>
</pre>
<p>Starting from PHP 8.3, the next item will be added at index <code>-4</code>:</p>
<pre><span class="hl-comment">//array (</span>
<span class="hl-comment">//  -5 =&gt; 'a',</span>
<span class="hl-comment">//  -4 =&gt; 'b',</span>
<span class="hl-comment">//)</span>
</pre>
<hr />
<h3 id="anonymous-readonly-classes-upgrading"><a href="#anonymous-readonly-classes-upgrading" class="heading-anchor">#</a> Anonymous readonly classes <small><a target="_blank" href="https://github.com/php/php-src/blob/master/UPGRADING#L48">UPGRADING</a></small></h3>
<p>Previously, you weren't able to mark anonymous classes as readonly. That's fixed in PHP 8.3:</p>
<pre><span class="hl-variable">$class</span> = <span class="hl-keyword">new</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> {
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$foo</span> = 'bar',
    </span>) {}
};
</pre>
<hr />
<h3 id="the-new-json_validate()-function-rfc"><a href="#the-new-json_validate()-function-rfc" class="heading-anchor">#</a> The new <code>json_validate()</code> function <small><a target="_blank" href="https://wiki.php.net/rfc/json_validate">RFC</a></small></h3>
<p>Previously, the only way to validate whether a string was valid JSON, was to decode it and detect whether any errors were thrown. This new <code>json_validate()</code> function is beneficial if you only need to know whether the input is valid JSON, since it uses less memory compared to decoding the string.</p>
<pre><span class="hl-property">json_validate</span>(string <span class="hl-variable">$json</span>, int <span class="hl-variable">$depth</span> = 512, int <span class="hl-variable">$flags</span> = 0): <span class="hl-type">bool</span>
</pre>
<hr />
<h3 id="randomizer-additions-rfc"><a href="#randomizer-additions-rfc" class="heading-anchor">#</a> <code>Randomizer</code> additions <small><a target="_blank" href="https://wiki.php.net/rfc/randomizer_additions">RFC</a></small></h3>
<p>PHP 8.2 added the new <a href="/blog/new-in-php-82#new-random-extension-rfc">Randomizer</a> class. This update brings some small additions:</p>
<pre><span class="hl-type">Randomizer</span>::<span class="hl-property">getBytesFromString</span>(string <span class="hl-variable">$string</span>, int <span class="hl-variable">$length</span>): <span class="hl-type">string</span>
</pre>
<p>This method allows you to generate a string with a given length that consists of randomly selected bytes from a given string.</p>
<pre><span class="hl-type">Randomizer</span>::<span class="hl-property">getFloat</span>(
    float <span class="hl-variable">$min</span>,
    float <span class="hl-variable">$max</span>,
    <span class="hl-type">IntervalBoundary</span> <span class="hl-variable">$boundary</span> = <span class="hl-type">IntervalBoundary</span>::<span class="hl-property">ClosedOpen</span>
): <span class="hl-type">float</span>
</pre>
<p><code>getFloat()</code> returns a float between <code>$min</code> and <code>$max</code>. You can define whether <code>$min</code> and <code>$max</code> should be included thanks to the <code>IntervalBoundary</code> enum. <code>Closed</code> means the value is included, while <code>Open</code> means excluded.</p>
<pre><span class="hl-type">Randomizer</span>::<span class="hl-property">nextFloat</span>(): <span class="hl-type">float</span> {}
</pre>
<p>Finally, <code>nextFloat()</code> is a shorthand for <code>getFloat(0, 1, IntervalBoundary::ClosedOpen)</code>, in other words: it'll give you a random float between 0 and 1, where 1 is excluded.</p>
<hr />
<h3 id="dynamic-class-constant-fetch-rfc"><a href="#dynamic-class-constant-fetch-rfc" class="heading-anchor">#</a> Dynamic class constant fetch <small><a target="_blank" href="https://wiki.php.net/rfc/dynamic_class_constant_fetch">RFC</a></small></h3>
<p>PHP 8.3 allows you to fetch constants with a more dynamic syntax:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span> 
{
    <span class="hl-keyword">const</span> <span class="hl-property">BAR</span> = '<span class="hl-value">bar</span>';
}

<span class="hl-variable">$name</span> = '<span class="hl-property">BAR</span>';
 
<span class="hl-comment">// Instead of this:</span>
<span class="hl-property">constant</span>(<span class="hl-type">Foo</span>::<span class="hl-keyword">class</span> . '<span class="hl-value">::</span>' . <span class="hl-variable">$name</span>);

<span class="hl-comment">// You can now do this:</span>
<span class="hl-type">Foo</span>::{<span class="hl-variable">$name</span>};
</pre>
<hr />
<h3 id="more-appropriate-date/time-exceptions-rfc-breaking"><a href="#more-appropriate-date/time-exceptions-rfc-breaking" class="heading-anchor">#</a> More Appropriate Date/Time Exceptions <small><a target="_blank" href="https://wiki.php.net/rfc/datetime-exceptions">RFC</a></small> <small class="breaking"><a href="https://wiki.php.net/rfc/datetime-exceptions#backward_incompatible_changes">breaking</a></small></h3>
<p>In many cases, PHP would simply throw an <code>Exception</code> or <code>Error</code> object; or emit a warning or error when something went wrong in dealing with dates and times. This RFC goes through all those edge cases and adds proper, dedicated exceptions for them.</p>
<p>We now have exceptions like <code>DateMalformedIntervalStringException</code>, <code>DateInvalidOperationException</code>, and <code>DateRangeError</code>.</p>
<p>In general, these additions won't break any code, since these newly added exceptions and errors subclass the generic <code>Exception</code> and <code>Error</code> classes. However, there are three small breaking changes that come with this RFC:</p>
<ul>
<li>The <code>Epoch doesn't fit in a PHP integer</code> now returns a new <code>DateRangeError</code> instead of a generic <code>ValueError</code>, which it does not subclass. This is only an issue for 32-bit platforms.</li>
<li>The <code>Only non-special relative time specifications are supported for subtraction</code> warning with <code>DateTime::sub()</code> and <code>date_sub()</code> becomes a new <code>DateInvalidOperationException</code>.</li>
<li>The <code>Unknown or bad format (%s) at position %d (%c): %s</code> and <code>String '%s' contains non-relative elements</code> warnings that are created while parsing wrong/broken <code>DateInterval</code> strings will now throw a new <code>DateMalformedIntervalStringException</code> when used with the OO interface, instead of showing a warning and returning false.</li>
</ul>
<hr />
<h3 id="improved-unserialize()-error-handling-rfc"><a href="#improved-unserialize()-error-handling-rfc" class="heading-anchor">#</a> Improved <code>unserialize()</code> error handling <small><a target="_blank" href="https://wiki.php.net/rfc/improve_unserialize_error_handling">RFC</a></small></h3>
<p><code>unserialize()</code> will now always emit a <code>E_WARNING</code> when running into problems instead of sometimes an <code>E_NOTICE</code>.</p>
<p>This RFC also proposed adding more exceptions when running <code>unserialize()</code>, but that part didn't get accepted.</p>
<hr />
<h3 id="changes-to-the-range()-function-breaking"><a href="#changes-to-the-range()-function-breaking" class="heading-anchor">#</a> Changes to the <code>range()</code> function <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING#L19">breaking</a></small></h3>
<p>From the changelog:</p>
<ul>
<li>A <code>TypeError</code> is now thrown when passing objects, resources, or arrays as the boundary inputs</li>
<li>A more descriptive <code>ValueError</code> is thrown when passing 0 for <code>$step</code>
</li>
<li>A <code>ValueError</code> is now thrown when using a negative <code>$step</code> for increasing ranges</li>
<li>If <code>$step</code> is a float that can be interpreted as an int, it is now done so</li>
<li>A <code>ValueError</code> is now thrown if any argument is <code>infinity</code> or <code>NAN</code>
</li>
<li>An <code>E_WARNING</code> is now emitted if <code>$start</code> or <code>$end</code> is the empty string. The value continues to be cast to the value 0.</li>
<li>An <code>E_WARNING</code> is now emitted if <code>$start</code> or <code>$end</code> has more than one byte, only if it is a non-numeric string.</li>
<li>An <code>E_WARNING</code> is now emitted if <code>$start</code> or <code>$end</code> is cast to an integer because the other boundary input is a number. (e.g. <code>range(5, 'z');</code>)</li>
<li>An <code>E_WARNING</code> is now emitted if $step is a float when trying to generate a range of characters, except if both boundary inputs are numeric strings (e.g. <code>range('5', '9', 0.5);</code> does not produce a warning)</li>
<li>
<code>range()</code> now produce a list of characters if one of the boundary inputs is a string digit instead of casting the other input to int (e.g. <code>range('5', 'z');</code>)</li>
</ul>
<hr />
<h3 id="traits-and-static-properties-breaking"><a href="#traits-and-static-properties-breaking" class="heading-anchor">#</a> Traits and static properties <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING#L19">breaking</a></small></h3>
<p>From the changelog:</p>
<blockquote>
<p>Uses of traits with static properties will now redeclare static properties inherited from the parent class. This will create a separate static property storage for the current class. This is analogous to adding the static property to the class directly without traits.</p>
</blockquote>
<hr />
<h3 id="stack-overflow-detection-pr"><a href="#stack-overflow-detection-pr" class="heading-anchor">#</a> Stack overflow detection <small><a target="_blank" href="https://github.com/php/php-src/pull/9104">PR</a></small></h3>
<p>PHP 8.3 adds two new ini directives called <code>zend.max_allowed_stack_size</code> and <code>zend.reserved_stack_size</code>. Programs that are close to overflowing the call stack may now throw an <code>Error</code> when using more than the difference between <code>zend.max_allowed_stack_size</code> and <code>zend.reserved_stack_size</code>.</p>
<p>The benefit of this feature is that stack-overflow-induced segmentation faults won't result in segfaults anymore, making debugging a lot easier.</p>
<p>The default for <code>zend.max_allowed_stack_size</code> is <code>0</code>, meaning PHP will automatically determine a value. You can also provide <code>-1</code> to indicate there isn't a limit, or a specific number of bytes. The <code>zend.reserved_stack_size</code> directive is used to determine the "buffer zone", so that PHP is able to still throw an error instead of actually running out of memory. The value here should be a number of bytes, but PHP will determine a reasonable default for you, so you don't necessarily need to set it, unless you're running into edge cases for specific programs.</p>
<p>On a final note, for fibers, the existing <code>fiber.stack_size</code> directive is used as the max allowed stack size.</p>
<pre>zend.max_allowed_stack_size=128K
</pre>
<hr />
<h3 id="new-mb_str_pad-function-rfc"><a href="#new-mb_str_pad-function-rfc" class="heading-anchor">#</a> New <code>mb_str_pad</code> function <small><a href="https://wiki.php.net/rfc/mb_str_pad">RFC</a></small></h3>
<p>From the RFC:</p>
<blockquote>
<p>In PHP, various string functions are available in two variants: one for byte strings and another for multibyte strings. However, a notable absence among the multibyte string functions is a <code>mbstring</code> equivalent of <code>str_pad()</code>. The <code>str_pad()</code> function lacks multibyte character support, causing issues when working with languages that utilize multibyte encodings like UTF-8. This RFC proposes the addition of such a function to PHP, which we will call <code>mb_str_pad()</code>.</p>
</blockquote>
<p>The function looks like this:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">mb_str_pad</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $string, 
    <span class="hl-type">int</span> $length, 
    <span class="hl-type">string</span> $pad_string = &quot; &quot;, 
    <span class="hl-type">int</span> $pad_type = STR_PAD_RIGHT, 
    <span class="hl-type">?string</span> $encoding = <span class="hl-keyword">null</span>,
</span>): <span class="hl-type">string</span> {}
</pre>
<hr />
<h3 id="magic-method-closures-and-named-arguments-pr"><a href="#magic-method-closures-and-named-arguments-pr" class="heading-anchor">#</a> Magic method closures and named arguments <small><a href="https://github.com/php/php-src/commit/61e1f8aaebdd0f609ae6be5453d0bbab001cef12">PR</a></small></h3>
<p>Let's say you have a class that supports magic methods:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Test</span> {
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__call</span>(<span class="hl-injection">$name, $args</span>) 
    {
        <span class="hl-property">var_dump</span>(<span class="hl-variable">$name</span>, <span class="hl-variable">$args</span>);
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">__callStatic</span>(<span class="hl-injection">$name, $args</span>) {
        <span class="hl-property">var_dump</span>(<span class="hl-variable">$name</span>, <span class="hl-variable">$args</span>);
    }
}
</pre>
<p>PHP 8.3 allows you to create closures from those methods, and then pass named arguments to those closures. That wasn't possible before.</p>
<pre><span class="hl-variable">$test</span> = <span class="hl-keyword">new</span> <span class="hl-type">Test</span>();

<span class="hl-variable">$closure</span> = <span class="hl-variable">$test</span>-&gt;<span class="hl-property">magic</span>(...);

<span class="hl-variable">$closure</span>(<span class="hl-property">a</span>: '<span class="hl-value">hello</span>', <span class="hl-property">b</span>: '<span class="hl-value">world</span>'); 
</pre>
<hr />
<h3 id="invariant-constant-visibility-breaking"><a href="#invariant-constant-visibility-breaking" class="heading-anchor">#</a> Invariant constant visibility <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING">breaking</a></small></h3>
<p>Previously, visibility for constants weren't checked when implementing an interface. PHP 8.3 fixes this bug, but it might lead to code breaking in some places if you weren't aware of this behaviour.</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">I</span> {
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">FOO</span> = '<span class="hl-value">foo</span>';
}

<span class="hl-keyword">class</span> <span class="hl-type">C</span> <span class="hl-keyword">implements</span><span class="hl-type"> I </span>{
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">FOO</span> = '<span class="hl-value">foo</span>';
}
</pre>
<hr />
<h3 id="the-small-deprecations-rfc-rfc"><a href="#the-small-deprecations-rfc-rfc" class="heading-anchor">#</a> The small deprecations RFC <small><a href="https://wiki.php.net/rfc/deprecations_php_8_3">rfc</a></small></h3>
<p>As is usual with every release, there's a single RFC that adds a bunch of small deprecations. Keep in mind that <a href="/blog/dealing-with-deprecations">deprecations are no errors</a>, and these are generally a good thing for the language to move forward. These are the deprecations that passed, you can read more details about them in the RFC:</p>
<ul>
<li>Deprecate passing negative <code>$widths</code> to <code>mb_strimwidth()</code>
</li>
<li>Deprecate and remove the <code>NumberFormatter::TYPE_CURRENCY</code> constant</li>
<li>Deprecate and remove the broken pre-PHP 7.1 Mt19937 implementation (<code>MT_RAND_PHP</code>)</li>
<li>Deprecate and remove calling <code>ldap_connect()</code> with 2 parameters <code>$host</code> and <code>$port</code>
</li>
<li>
<a href="https://wiki.php.net/rfc/assert-string-eval-cleanup">Deprecate remains of string evaluated code assertions</a>
</li>
</ul>
<hr />
<h3 id="small,-but-notable-changes"><a href="#small,-but-notable-changes" class="heading-anchor">#</a> Small, but notable changes</h3>
<p>Not every change in PHP passes the RFC process. In fact, the majority of changes include maintenance and bugfixing, and don't require an RFC. All of these changes are listed in the <a href="https://github.com/php/php-src/blob/master/UPGRADING">UPGRADING</a> document. I'll list some of the most prominent ones, but you should definitely read throughout the whole list if you want to know about the tiniest details.</p>
<ul>
<li>When using <a href="/blog/new-in-php-74#foreign-function-interface-rfc">FFI</a>, C functions that have a return type of <code>void</code> now return <code>null</code> instead of returning <code>FFI\CData:void</code>
</li>
<li>
<code>posix_getrlimit()</code> now takes an optional <code>$res</code> parameter to allow fetching a single resource limit.</li>
<li>
<code>gc_status()</code> has four new fields: <code>running</code>, <code>protected</code>, <code>full</code>, and <code>buffer_size</code>.</li>
<li>
<code>class_alias()</code> now supports creating an alias of an internal class.</li>
<li>
<code>mysqli_poll()</code> now raises a <code>ValueError</code> when the read nor error arguments are passed.</li>
<li>
<code>array_pad()</code> is now only limited by the maximum number of elements an array can have. Before, it was only possible to add at most 1048576 elements at a time.</li>
<li>New posix functions: <code>posix_sysconf()</code>, <code>posix_pathconf()</code>, <code>posix_fpathconf()</code>, and <code>posix_eaccess()</code>
</li>
<li>Executing <code>proc_get_status()</code> multiple times will now always return the right value on posix systems.</li>
<li>
<code>opcache.consistency_checks</code> ini directive was removed</li>
<li>
<a href="https://wiki.php.net/rfc/saner-array-sum-product">Improved <code>array_sum()</code> and <code>array_product()</code></a>
</li>
</ul>
<hr />
<p>That's it for now, but this list will grow over time. If you want to stay up to date, you can <a href="/mail">subscribe to my newsletter</a>, <a href="/twitter">follow me on Twitter</a>, or <a href="/rss">subscribe to my RSS feed</a>.</p>
 ]]></summary>

                <updated>2023-11-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ &quot;Is A&quot; or &quot;Acts As&quot; ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/is-a-or-acts-as"/>

                <id>https://www.stitcher.io/blog/is-a-or-acts-as</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I voiced my preference for the recent <a href="https://www.youtube.com/watch?v=lXsbFXYwxWU">interface default methods RFC</a>, and many people told me I was wrong: an interface is only a contract and shouldn't provide implementations.</p>
<p>They are, of course, right, but only half. Let's talk about object relations.</p>
<p>You can think of the classic class/interface relation as an <code>Is A</code> relation: you can say <code>Item Is A Purchasable Item</code>, or, in technical terms: <code>class Item implements Purchasable</code>.</p>
<p>I don't think there's any disagreement here amongst developers, this is the classic definition of an interface. It allows us to write code that works with all types of purchasables, without worrying which concrete implementation we're dealing with.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">createPayment</span>(<span class="hl-injection"><span class="hl-type">Purchasable</span> $purchasable</span>): <span class="hl-type">Payment</span>
{
    <span class="hl-variable">$price</span> = <span class="hl-variable">$purchasable</span>-&gt;<span class="hl-property">getPrice</span>();
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>This is where people who argue against interface default methods stop. If this is the only way you're using interfaces, then yes, you're right: interface default methods aren't necessary.</p>
<p>However, there is another way interfaces are used. And mind you: I'm not saying "there is another way interfaces <em>can</em> be used", no, I'm saying this <em>is</em> happening in modern PHP code, today, in many projects.</p>
<p>Here goes. Interfaces can be used to model an <code>Acts As</code> relation — I have a perfect example, thanks to <a target="_blank" href="https://www.garfieldtech.com/blog/beyond-abstract">Larry</a>.</p>
<p>Here's the so called <code>LoggerInterface</code>, part of <a target="_blank" href="https://www.php-fig.org/psr/psr-3/">PSR-3</a>:</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">LoggerInterface</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">emergency</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">alert</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">critical</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">error</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">warning</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">notice</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">info</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">debug</span>(<span class="hl-injection">
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">log</span>(<span class="hl-injection">
        $level, 
        <span class="hl-type">string|\Stringable</span> $message, 
        <span class="hl-type">array</span> $context = []
    </span>): <span class="hl-type">void</span>;
}
</pre>
<p>As you can see, most methods are essentially shortcuts for the <code>log</code> method: they are convenience methods so that you don't have to manually provide a logging level. It's a great design choice to include in the interface, as it forces all implementations to have better accessibility.</p>
<p>However, let's be honest, no one is ever going to need a logger with a different implementation of <code>debug</code> or <code>info</code> or any of the other shorthands. These methods will <em>always</em> look the same:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">debug</span>(<span class="hl-injection">
    <span class="hl-type">string|\Stringable</span> $message, 
    <span class="hl-type">array</span> $context = []
</span>): <span class="hl-type">void</span>
{
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">log</span>(<span class="hl-type">LogLevel</span>::<span class="hl-property">DEBUG</span>, <span class="hl-variable">$message</span>, <span class="hl-variable">$context</span>);
}
</pre>
<p>In essence, this <code>LoggerInterface</code> is not only describing an <code>Is A</code> relation — if that were the case we'd only need the <code>log</code> method. No, it also describes an <code>Acts As</code> relation: a concrete logger implementation can <code>Act As</code> as proper logger, including the convenience methods associated with it. <code>FileLogger Acts As LoggerInterface</code>, <code>Monolog Acts As LoggerInterface</code>.</p>
<p>It all boils down to the question: is this a valid way of writing and using interfaces? I would say, yes.</p>
<p>I'd encourage you to take a close look at your own projects, and be totally honest for a moment: are any of your interfaces describing an <code>Acts As</code> relationship? If they do, then you cannot make the case against interface default methods.</p>
 ]]></summary>

                <updated>2023-07-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP version stats: July, 2023 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-version-stats-july-2023"/>

                <id>https://www.stitcher.io/blog/php-version-stats-july-2023</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Once again, I'm writing my summary of which PHP versions are used across the community. You can read the previous edition <a href="/blog/php-version-stats-january-2023">here</a>, but I'll also include historic data in this post.</p>
<p>As always, it's important to note that I'm working with the data available to us. That means that these charts are not a 100% accurate representation of the PHP community as a whole, but they <em>are</em> an accurate representation of one of the most prominent parts of PHP: the <a href="https://packagist.org/php-statistics">packagist ecosystem</a>.</p>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<h2 id="usage-statistics"><a href="#usage-statistics" class="heading-anchor">#</a> Usage Statistics</h2>
<p>Let's start with the percentage of PHP versions being used today, and compare it to the previous three editions, note that I've omitted all versions that don't have more than 1% usage:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2022-01</td>
    <td>2022-07</td>
    <td>2023-01</td>
    <td>2023-07</td>
</tr>
<tr>
    <td>7.1</td>
    <td>2.4%</td>
    <td>1.9%</td>
    <td>1.8%</td>
    <td>1.3%</td>
</tr>
<tr>
    <td>7.2</td>
    <td>6.6%</td>
    <td>5.1%</td>
    <td>4.3%</td>
    <td>4.3%</td>
</tr>
<tr>
    <td>7.3</td>
    <td>12.0%</td>
    <td>8.0%</td>
    <td>5.3%</td>
    <td>4.2%</td>
</tr>
<tr>
    <td>7.4</td>
    <td>43.9%</td>
    <td>38.4%</td>
    <td>27.7%</td>
    <td>19.9%</td>
</tr>
<tr>
    <td>8.0</td>
    <td>23.9%</td>
    <td>20.6%</td>
    <td>16.2%</td>
    <td>12.3%</td>
</tr>
<tr>
    <td>8.1</td>
    <td>9.1%</td>
    <td>24.5%</td>
    <td>38.8%</td>
    <td>39.3%</td>
</tr>
<tr>
    <td>8.2</td>
    <td>0.0%</td>
    <td>0.0%</td>
    <td>4.7%</td>
    <td>17.2%</td>
</tr>
</table>
</div>
<p>Visualizing this data looks like this:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2023-jul-01.svg"><img src="/resources/img/blog/version-stats/2023-jul-01.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2023-jul-01.svg">Evolution of version usage</a></em></p>
<p>It's important to know which PHP versions are currently still supported: PHP 8.2 and PHP 8.1 are still receiving updates. PHP 8.0 is still getting security updates until the end of November, this year. That means that PHP 7.4 and below don't receive any updates more, and should be considered end of life.</p>
<p>In total, <strong>that's around 30% of packagist downloads by outdated and insecure version of PHP</strong>. At the beginning of this year, that number was closer to 40%, meaning we see a steady decline — a good thing!</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>Moving on to the all-time overview chart, here you can see the evolution of version usage across time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2023-jul-02.svg"><img src="/resources/img/blog/version-stats/2023-jul-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2023-jul-02.svg">All time evolution</a></em></p>
<p>It seems that <strong>PHP 8.1 saw the biggest growth over time since PHP 7.4 and PHP 5.5</strong>. PHP 8.2, in comparison, seems to make a slower start. It's also interesting to note a relative high percentage of PHP 8.1 two years in a row. Granted, PHP 8.1 was a pretty solid release with <a href="/blog/new-in-php-81">features like enums and readonly properties</a>. It'll be interesting to see how this graph evolves next year, when PHP 8.1 moves in security fixes only mode.</p>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<h2 id="required-versions"><a href="#required-versions" class="heading-anchor">#</a> Required versions</h2>
<p>Next, I used Nikita's <a target="_blank" href="https://github.com/nikic/popular-package-analysis">popular package analyzer</a> to download the 1000 most popular composer packages. I wrote a script that scans these packages to determine their minimum required version. Here are the results:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2022-01</td>
    <td>2022-07</td>
    <td>2023-01</td>
    <td>2023-07</td>
</tr>
<tr>
    <td>5.2</td>
    <td>10</td>
    <td>10</td>
    <td>10</td>
    <td>7</td>
</tr>
<tr>
    <td>5.3</td>
    <td>83</td>
    <td>77</td>
    <td>78</td>
    <td>65</td>
</tr>
<tr>
    <td>5.4</td>
    <td>43</td>
    <td>40</td>
    <td>40</td>
    <td>31</td>
</tr>
<tr>
    <td>5.5</td>
    <td>42</td>
    <td>35</td>
    <td>37</td>
    <td>21</td>
</tr>
<tr>
    <td>5.6</td>
    <td>49</td>
    <td>42</td>
    <td>43</td>
    <td>32</td>
</tr>
<tr>
    <td>7.0</td>
    <td>29</td>
    <td>29</td>
    <td>30</td>
    <td>24</td>
</tr>
<tr>
    <td>7.1</td>
    <td>190</td>
    <td>153</td>
    <td>159</td>
    <td>125</td>
</tr>
<tr>
    <td>7.2</td>
    <td>133</td>
    <td>130</td>
    <td>144</td>
    <td>133</td>
</tr>
<tr>
    <td>7.3</td>
    <td>116</td>
    <td>104</td>
    <td>106</td>
    <td>56</td>
</tr>
<tr>
    <td>7.4</td>
    <td>69</td>
    <td>86</td>
    <td>98</td>
    <td>97</td>
</tr>
<tr>
    <td>8.0</td>
    <td>160</td>
    <td>94</td>
    <td>103</td>
    <td>144</td>
</tr>
<tr>
    <td>8.1</td>
    <td>-</td>
    <td>125</td>
    <td>129</td>
    <td>107</td>
</tr>
<tr>
    <td>8.2</td>
    <td>-</td>
    <td>-</td>
    <td>-</td>
    <td>94</td>
</tr>
</table>
</div>
<p>There are two important notes to make here.</p>
<ol>
<li>This tables shows the <strong>minimum required version</strong>. That means that packages with a minimal version of, for example, 8.0, could also support PHP 8.1 or and PHP 8.2.</li>
<li>If you count the numbers, you'll notice there are some differences between each year. Not every package lists a valid version string.</li>
</ol>
<br>
<p>Instead of comparing absolute numbers, it's best to plot this data into a chart for a relative comparison, so that we can see changes over time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2023-jul-03.svg"><img src="/resources/img/blog/version-stats/2023-jul-03.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2023-jul-03.svg">Minimal PHP requirement over time</a></em></p>
<p>There seems to be <strong>a pretty big leap in PHP 8.0 and PHP 8.1 being the minimal versions</strong>  — a good thing. After all, the open source community plays a big part in pushing the community forward by increasing their minimal required version.</p>
<hr />
<p>That's all data I have to share for this edition of PHP's version stats. You can always reach me via <a href="mailto:brendt@stitcher.io">email</a> if you want to share your thoughts or have questions. You can also <a href="/mail">subscribe to my newsletter</a> if you want to receive updates about this blog in the future.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2023-07-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ #[Override] in PHP 8.3 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/override-in-php-83"/>

                <id>https://www.stitcher.io/blog/override-in-php-83</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>There's a new feature in PHP 8.3: the <code>#[Override]</code> attribute. It's a feature already known in other languages, but let me summarize in case you're unaware of what it does.</p>
<p>Marking a method with the <code>#[Override]</code> attributes signifies that you <em>know</em> this method is overriding a parent method. So the only thing it does, is show intent.</p>
<p>Why does that matter? You already know you're overriding a method, don't you? Well, let's imagine these two classes:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Parent</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">methodWithDefaultImplementation</span>(): <span class="hl-type">int</span>
    {
        <span class="hl-keyword">return</span> 1;
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Child</span> <span class="hl-keyword">extends</span> <span class="hl-type">Parent</span>
{
    <span class="hl-attribute">#[<span class="hl-type">Override</span>]</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">methodWithDefaultImplementation</span>(): <span class="hl-type">int</span>
    {
        <span class="hl-keyword">return</span> 2; <span class="hl-comment">// The overridden method</span>
    }
} 
</pre>
<p>Now, let's imagine at one point the parent method changes its method name:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Parent</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">methodWithNewImplementation</span>(): <span class="hl-type">int</span>
    {
        <span class="hl-keyword">return</span> 1;
    }
}
</pre>
<p>Before the <code>#[Override]</code> attribute, there was no way of knowing that <code>Child::methodWithDefaultImplementation()</code> doesn't override the renamed method anymore, which could lead to unforeseen bugs.</p>
<p>Thanks to <code>#[Override]</code> though, PHP now knows something is wrong, thanks to that attribute. It basically says "I know this method should override a parent method. If that would ever change, please let me know".</p>
<h2 id="some-thoughts"><a href="#some-thoughts" class="heading-anchor">#</a> Some thoughts</h2>
<p>What strikes me most about this RFC, is how irrelevant it could be. Once again we're adding runtime checks for something that could be determined by static analysers.</p>
<p>I don't want to repeat every argument I made in the past, so I'll just <a href="/blog/we-dont-need-runtime-type-checks">link to my previous thoughts on the topic</a>, and summarise: we're missing out. PHP internals should either come with an official spec for static analysers, or with a first-party static analyser. Why? Because so much more would be possible, and it would drive PHP forward tremendously.</p>
<p>Anyway, it seems like many people have tried to make the same argument about this RFC in particular <a href="https://externals.io/message/120233">on the Internals mailing list</a>, to no avail.</p>
<p>I don't mind this feature, although I'll probably never use it myself (I use an IDE that prevents me from making these kinds of mistakes, I don't need PHP's runtime to double-check it for me). What I am sad about, is how the PHP community is <a href="/blog/thoughts-on-asymmetric-visibility">divided</a> between the static-analysis and non-static-analysis camps, and I don't know if there will ever be someone who'll be able to unify and steer the language into a next decade of progression.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2023-06-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Don&#039;t be clever ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/dont-be-clever"/>

                <id>https://www.stitcher.io/blog/dont-be-clever</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Ten years ago, I wrote the most beautiful, clever, over-engineered piece of code ever. I was building a REST API for a startup, and discovered lots of repetition between controllers: I was building the same kind of actions and copying code over and over again. So I came up with a solution: <em>The CRUDController™</em>.</p>
<p>It was a beautifully complex, abstract class that integrated with Doctrine (the ORM that I was using back then). It had every possible CRUD operation you could think of — not just for entities, but also for child- and has many relations; there were automatic overviews, filtering, pagination, validation, data persistence, routing, and whatnot.</p>
<p>And the only thing I had to do was to create a new controller, extend from my amazing <em>CRUDController™</em>, provide an entity class, and be done.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">TimesheetController</span> <span class="hl-keyword">extends</span> <span class="hl-type">CRUDController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getEntity</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">Timesheet</span>::<span class="hl-keyword">class</span>;
    }
}
</pre>
<p>Such a blast!</p>
<p>Except, of course: exceptions started to emerge. Not the programming kind, but the business kind. <em>Some</em> controllers had to do <em>some</em> things a little differently. It was small things at first: different URL schemes, different kinds of validation; but soon, things grew more and more complex: support for nested entities or complex filtering, to name a few.</p>
<p>And young me? I just kept going. Adding the proverbial knobs and pulls to my abstract class (which was growing into a <em>set</em> of classes by now).</p>
<p>In the end, I created a monster; and — ironically — it had taken more time than if I had simply copied code between controllers over and over again. On top of that: I was leaving the startup, and no one really understood how more than 50 controllers actually worked.</p>
<p>You might assume I understood, but let me be clear: I didn't really know how much of it worked anymore.</p>
<p>Yes, I had failed to see the proper solution: a class generator — so that I didn't have to manually copy code again. It actually existed back then, I simply didn't know about it, no one told me about it, and I wasn't smart enough to question myself once I started going down a certain path.</p>
<p>It's such a classic example, many of you probably recognise it. I wouldn't say my coding skills were bad, by the way. No, I didn't question myself enough, I lacked self-reflection and wasn't able to critically look at my own ideas.</p>
<p>I wish I could show you <em>The CRUDController™</em>'s source code; but I don't have access to it anymore, unfortunately. Luckily, the memory still exists. And it's a memory I remind myself of very often when I'm going down the path of abstractions and complications. It's often enough to hold me back and look for better solutions.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2023-06-02T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Building a procedurally generated game with PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/procedurally-generated-game-in-php"/>

                <id>https://www.stitcher.io/blog/procedurally-generated-game-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Today, we're building a procedurally generated, 2D game with PHP. It's a simple game that's focussed around resource gathering on a procedurally generated map. In case you're unfamiliar with that term: it's a map there's generated by code, based on a seed. Every seed will generate a completely unique map. It looks something like this:</p>
<p><img src="/resources/img/blog/game/game-1.png" srcset="/resources/img/blog/game/game-1-1717x1088.png 1717w, /resources/img/blog/game/game-1-858x543.png 858w, /resources/img/blog/game/game-1-1214x769.png 1214w, /resources/img/blog/game/game-1-1919x1216.png 1919w, /resources/img/blog/game/game-1-1487x942.png 1487w" sizes="" alt=""></img></p>
<p>So, how do we go from plain PHP to a map like this? It all starts with noise.</p>
<h2 id="noise-generation"><a href="#noise-generation" class="heading-anchor">#</a> Noise generation</h2>
<p>Let's imagine we have grid of 150 by 100 pixels. Each pixel makes up a point of our map.</p>
<pre><span class="hl-variable">$pixels</span> = [];

<span class="hl-keyword">for</span>(<span class="hl-variable">$x</span> = 0; <span class="hl-variable">$x</span> &lt; 150; <span class="hl-variable">$x</span>++) {
    <span class="hl-keyword">for</span>(<span class="hl-variable">$y</span> = 0; <span class="hl-variable">$y</span> &lt; 100; <span class="hl-variable">$y</span>++) {
        <span class="hl-variable">$pixels</span>[<span class="hl-variable">$x</span>][<span class="hl-variable">$y</span>] = <span class="hl-property">drawPixel</span>(<span class="hl-variable">$x</span>, <span class="hl-variable">$y</span>, 0); 
    }
}
</pre>
<p>For now, the <code>drawPixel</code> function will generate a <code>div</code> per pixel, which can be laid out on a CSS grid. We can refactor to use <code>canvas</code> later, but being able to use CSS's built-in grid saves a lot of time.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">drawPixel</span>(<span class="hl-injection"><span class="hl-type">int</span> $x, <span class="hl-type">int</span> $y</span>): <span class="hl-type">string</span>
{
    <span class="hl-keyword">return</span> &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">HTML</span></span><span class="hl-injection">
    &lt;<span class="hl-keyword">div</span> <span class="hl-property">style</span>=&quot;<span class="hl-keyword">--x: </span>{$x};<span class="hl-keyword"> --y: </span>{$y};&quot;&gt;&lt;/<span class="hl-keyword">div</span>&gt;
    </span><span class="hl-property"><span class="hl-property">HTML</span></span>;
}
</pre>
<p>This is the template file:</p>
<pre>&lt;<span class="hl-keyword">style</span>&gt;<span class="hl-keyword">
    :root </span>{
        <span class="hl-property">--pixel-size</span>: 9px;
        <span class="hl-property">--pixel-gap</span>: 1px;
        <span class="hl-property">--pixel-color</span>: #000;
    }<span class="hl-keyword">

    .map </span>{
        <span class="hl-property">display</span>: grid;<span class="hl-keyword">
        grid-template-columns: repeat(</span>{{ <span class="hl-keyword">count</span>(<span class="hl-variable">$pixels</span>) }}, <span class="hl-keyword">var</span>(<span class="hl-property">--pixel-size</span>));
        <span class="hl-property">grid-auto-rows</span>: <span class="hl-keyword">var</span>(<span class="hl-property">--pixel-size</span>);
        <span class="hl-property">grid-gap</span>: <span class="hl-keyword">var</span>(<span class="hl-property">--pixel-gap</span>);
    }

    .map &gt;<span class="hl-keyword"> div </span>{
        <span class="hl-property">width</span>: <span class="hl-keyword">var</span>(<span class="hl-property">--pixel-size</span>);
        <span class="hl-property">height</span>: 100%;
        <span class="hl-property">grid-area</span>: <span class="hl-keyword">var</span>(<span class="hl-property">--y</span>) / <span class="hl-keyword">var</span>(<span class="hl-property">--x</span>) / <span class="hl-keyword">var</span>(<span class="hl-property">--y</span>) / <span class="hl-keyword">var</span>(<span class="hl-property">--x</span>);
        <span class="hl-property">background-color</span>: <span class="hl-keyword">var</span>(<span class="hl-property">--pixel-color</span>);
    }
&lt;/<span class="hl-keyword">style</span>&gt;

&lt;<span class="hl-keyword">div</span> <span class="hl-property">class</span>=&quot;map&quot;&gt;
    <span class="hl-keyword">@foreach</span>(<span class="hl-variable">$pixels</span> <span class="hl-keyword">as</span> <span class="hl-variable">$x</span> =&gt; <span class="hl-variable">$row</span>)
        <span class="hl-keyword">@foreach</span>(<span class="hl-variable">$row</span> <span class="hl-keyword">as</span> <span class="hl-variable">$y</span> =&gt; <span class="hl-variable">$pixel</span>)
            {!! <span class="hl-variable">$pixel</span> !!}
        <span class="hl-keyword">@endforeach</span>
    <span class="hl-keyword">@endforeach</span>
&lt;/<span class="hl-keyword">div</span>&gt;
</pre>
<p>This is the result:</p>
<p><img src="/resources/img/blog/game/game-20.png" srcset="/resources/img/blog/game/game-20-1214x769.png 1214w, /resources/img/blog/game/game-20-1919x1216.png 1919w, /resources/img/blog/game/game-20-1487x942.png 1487w, /resources/img/blog/game/game-20-1717x1088.png 1717w, /resources/img/blog/game/game-20-858x543.png 858w" sizes="" alt=""></img></p>
<p>By the way, I will get rid of the gaps between pixels, I only added them to show that these are indeed separate grid cells.</p>
<p>Let's play around with our grid. We'll start by assigning a value between 0 and 1 for each individual pixel. We'll use a class called <code>Noise</code> that takes a pixel's point (X/Y coordinates), and returns a value for that point. First, we'll return a random value.</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Noise</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">int</span> <span class="hl-property">$seed</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">generate</span>(<span class="hl-injection"><span class="hl-type">Point</span> $point</span>): <span class="hl-type">float</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">rand</span>(1, 100) / 100;
    }
}

<span class="hl-comment">// …</span>

<span class="hl-property">drawPixel</span>(<span class="hl-variable">$x</span>, <span class="hl-variable">$y</span>, <span class="hl-variable">$noise</span>-&gt;<span class="hl-property">generate</span>(<span class="hl-variable">$x</span>, <span class="hl-variable">$y</span>)); 
</pre>
<p>Here's the result:</p>
<p><img src="/resources/img/blog/game/game-2.png" srcset="/resources/img/blog/game/game-2-858x543.png 858w, /resources/img/blog/game/game-2-1919x1216.png 1919w, /resources/img/blog/game/game-2-1214x769.png 1214w, /resources/img/blog/game/game-2-1487x942.png 1487w, /resources/img/blog/game/game-2-1717x1088.png 1717w" sizes="" alt=""></img></p>
<p>Relying on randomness won't get us very far though. We want a given seed to generate the same map over and over again. So instead of randomness, let's write a hash function: a function that, for any given point and seed, will generate the same value over and over again. You could make it as simple as multiplying the seed with the x and y coordinates, and turning that into a fraction:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">generate</span>(<span class="hl-injection"><span class="hl-type">Point</span> $point</span>): <span class="hl-type">float</span>
{
    <span class="hl-variable">$hash</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">seed</span> * <span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> * <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span>;
    
    <span class="hl-keyword">return</span> <span class="hl-property">floatval</span>('<span class="hl-value">0.</span>' . <span class="hl-variable">$hash</span>);
}
</pre>
<p>The result, however, doesn't seem random enough. Remember that we want to generate a world map: we want some randomness, but also some cohesion. So our hash function will need to be a bit more complex.</p>
<p><img src="/resources/img/blog/game/game-3.png" srcset="/resources/img/blog/game/game-3-1487x942.png 1487w, /resources/img/blog/game/game-3-858x543.png 858w, /resources/img/blog/game/game-3-1214x769.png 1214w, /resources/img/blog/game/game-3-1919x1216.png 1919w, /resources/img/blog/game/game-3-1717x1088.png 1717w" sizes="" alt=""></img></p>
<p>Let's try an existing hash function that we don't need to invent ourselves. We probably want a performant one, since we're generating a hash for thousands of pixels. PHP has support for xxHash, which is an "extremely fast hashing algorithm". Let's give it a try.</p>
<pre><span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">hash</span>(<span class="hl-injection"><span class="hl-type">Point</span> $point</span>): <span class="hl-type">float</span>
{
    <span class="hl-variable">$hash</span> = <span class="hl-property">bin2hex</span>(
        <span class="hl-property">hash</span>(
            <span class="hl-property">algo</span>: '<span class="hl-value">xxh32</span>',
            <span class="hl-property">data</span>: <span class="hl-variable">$this</span>-&gt;<span class="hl-property">seed</span> * <span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> * <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span>,
        )
    );

    <span class="hl-variable">$hash</span> = <span class="hl-property">floatval</span>('<span class="hl-value">0.</span>' . <span class="hl-variable">$hash</span>);

    <span class="hl-keyword">return</span> <span class="hl-variable">$hash</span>;
}
</pre>
<p><img src="/resources/img/blog/game/game-4.png" srcset="/resources/img/blog/game/game-4-1214x769.png 1214w, /resources/img/blog/game/game-4-1717x1088.png 1717w, /resources/img/blog/game/game-4-858x543.png 858w, /resources/img/blog/game/game-4-1919x1216.png 1919w, /resources/img/blog/game/game-4-1487x942.png 1487w" sizes="" alt=""></img></p>
<p>This noise looks promising: it's quite random, but always yields the same result for a given seed. But going from this to a cohesive world map still seems like a leap. Let's change our hash function, so that it'll return the same color within a square of 10 pixels:</p>
<pre><span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">hash</span>(<span class="hl-injection"><span class="hl-type">Point</span> $point</span>): <span class="hl-type">float</span>
{
    <span class="hl-variable">$baseX</span> = <span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> / 10);
    <span class="hl-variable">$baseY</span> = <span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> / 10);

    <span class="hl-variable">$hash</span> = <span class="hl-property">bin2hex</span>(
        <span class="hl-property">hash</span>(
            <span class="hl-property">algo</span>: '<span class="hl-value">xxh32</span>',
            <span class="hl-property">data</span>: <span class="hl-variable">$this</span>-&gt;<span class="hl-property">seed</span> * <span class="hl-variable">$baseX</span> * <span class="hl-variable">$baseY</span>,
        )
    );

    <span class="hl-variable">$hash</span> = <span class="hl-property">floatval</span>('<span class="hl-value">0.</span>' . <span class="hl-variable">$hash</span>);

    <span class="hl-keyword">return</span> <span class="hl-property">sqrt</span>(<span class="hl-variable">$hash</span>);
}
</pre>
<p>Here's the result:</p>
<p><img src="/resources/img/blog/game/game-6.png" srcset="/resources/img/blog/game/game-6-1487x942.png 1487w, /resources/img/blog/game/game-6-1717x1088.png 1717w, /resources/img/blog/game/game-6-1919x1216.png 1919w, /resources/img/blog/game/game-6-858x543.png 858w, /resources/img/blog/game/game-6-1214x769.png 1214w" sizes="" alt=""></img></p>
<p>Oh, by the way: I take the square root of the hash, just to increase all values a little bit. That'll be useful in the future, but not necessary. Without the square root, the map looks like this:</p>
<p><img src="/resources/img/blog/game/game-5.png" srcset="/resources/img/blog/game/game-5-858x543.png 858w, /resources/img/blog/game/game-5-1214x769.png 1214w, /resources/img/blog/game/game-5-1487x942.png 1487w, /resources/img/blog/game/game-5-1717x1088.png 1717w, /resources/img/blog/game/game-5-1919x1216.png 1919w" sizes="" alt=""></img></p>
<p>Let's <em>imagine</em> something for a second. Let's say all pixels with a value higher than 0.6 are considered land, and all pixels with a lower value are considered water. Let's make some changes to our <code>drawPixel</code> method to reflect that behaviour:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">drawPixel</span>(<span class="hl-injection"><span class="hl-type">int</span> $x, <span class="hl-type">int</span> $y, <span class="hl-type">float</span> $value</span>): <span class="hl-type">string</span>
{
    <span class="hl-variable">$hexFromNoise</span> = <span class="hl-property">hex</span>(<span class="hl-variable">$value</span>);
    
    <span class="hl-variable">$color</span> = <span class="hl-keyword">match</span>(<span class="hl-keyword">true</span>) {
        <span class="hl-variable">$noise</span> &lt; 0.6 =&gt; &quot;<span class="hl-value">#0000{$hexFromNoise}</span>&quot;, <span class="hl-comment">// blue</span>
        <span class="hl-keyword">default</span> =&gt; &quot;<span class="hl-value">#00{$hexFromNoise}00</span>&quot;, <span class="hl-comment">// green</span>
    };
    
    <span class="hl-keyword">return</span> &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">HTML</span></span><span class="hl-injection">
    &lt;<span class="hl-keyword">div</span> <span class="hl-property">style</span>=&quot;<span class="hl-keyword">--x: </span>{$x};<span class="hl-keyword"> --y: </span>{$y};<span class="hl-keyword"> --pixel-color: </span>{$color}&quot;&gt;&lt;/<span class="hl-keyword">div</span>&gt;
    </span><span class="hl-property"><span class="hl-property">HTML</span></span>;
}
</pre>
<p>By the way, that <code>hex</code> function converts a value between 0 and 1 to a two-digit hexadecimal. It looks like this:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">hex</span>(<span class="hl-injection"><span class="hl-type">float</span> $value</span>): <span class="hl-type">string</span>
{
    <span class="hl-keyword">if</span> (<span class="hl-variable">$value</span> &gt; 1.0) {
        <span class="hl-variable">$value</span> = 1.0;
    }

    <span class="hl-variable">$hex</span> = <span class="hl-property">dechex</span>((int) (<span class="hl-variable">$value</span> * 255));

    <span class="hl-keyword">if</span> (<span class="hl-property">strlen</span>(<span class="hl-variable">$hex</span>) &lt; 2) {
        <span class="hl-variable">$hex</span> = &quot;<span class="hl-value">0</span>&quot; . <span class="hl-variable">$hex</span>;
    }

    <span class="hl-keyword">return</span> <span class="hl-variable">$hex</span>;
}

</pre>
<p>The result is looking a lot more like a map already:</p>
<p><img src="/resources/img/blog/game/game-7.png" srcset="/resources/img/blog/game/game-7-858x543.png 858w, /resources/img/blog/game/game-7-1214x769.png 1214w, /resources/img/blog/game/game-7-1487x942.png 1487w, /resources/img/blog/game/game-7-1919x1216.png 1919w, /resources/img/blog/game/game-7-1717x1088.png 1717w" sizes="" alt=""></img></p>
<p>Ok, pretty nice! But these sharp edges don't really look realistic. Can we find a way to make transitions between the edges more smooth?</p>
<h2 id="lerp"><a href="#lerp" class="heading-anchor">#</a> Lerp</h2>
<p>Time for some maths. Let's say we have two values: <code>0.34</code> and <code>0.78</code>. We want to know the value exactly in the middle between these two. How do we do that?</p>
<p><img src="/resources/img/blog/game/game-8.png" srcset="/resources/img/blog/game/game-8-1565x308.png 1565w, /resources/img/blog/game/game-8-782x154.png 782w, /resources/img/blog/game/game-8-1355x267.png 1355w, /resources/img/blog/game/game-8-1750x345.png 1750w, /resources/img/blog/game/game-8-1106x218.png 1106w" sizes="" alt=""></img></p>
<p>Well, there's a simple mathematical formula for that. It's called "Linear Interpolation" — "LERP" for short:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">lerp</span>(<span class="hl-injection"><span class="hl-type">float</span> $a, <span class="hl-type">float</span> $b, <span class="hl-type">float</span> $fraction</span>): <span class="hl-type">float</span>
{
    <span class="hl-keyword">return</span> <span class="hl-variable">$a</span> + <span class="hl-variable">$fraction</span> * (<span class="hl-variable">$b</span> - <span class="hl-variable">$a</span>);
}

<span class="hl-property">lerp</span>(0.34, 0.78, 0.5); <span class="hl-comment">// 0.56</span>
</pre>
<p>So, given a number <code>$a</code> (<code>0.34</code>), a number <code>$b</code> (<code>0.78</code>), and a fraction (<code>0.5</code>, also known as: "half"); we get <code>0.56</code> — the number exactly in the middle between <code>0.34</code> and <code>0.78</code>.</p>
<p><img src="/resources/img/blog/game/game-9.png" srcset="/resources/img/blog/game/game-9-1355x348.png 1355w, /resources/img/blog/game/game-9-782x201.png 782w, /resources/img/blog/game/game-9-1106x284.png 1106w, /resources/img/blog/game/game-9-1565x402.png 1565w, /resources/img/blog/game/game-9-1750x449.png 1750w" sizes="" alt=""></img></p>
<p>Thanks to the <em>fraction</em> part in our lerp formula, we can determine the value at <em>any place</em> between these points, not just the middle:</p>
<pre><span class="hl-property">lerp</span>(0.34, 0.78, 0.25); <span class="hl-comment">// 0.45</span>
</pre>
<p><img src="/resources/img/blog/game/game-10.png" srcset="/resources/img/blog/game/game-10-782x154.png 782w, /resources/img/blog/game/game-10-1355x267.png 1355w, /resources/img/blog/game/game-10-1106x218.png 1106w, /resources/img/blog/game/game-10-1750x345.png 1750w, /resources/img/blog/game/game-10-1565x308.png 1565w" sizes="" alt=""></img></p>
<p>Ok, so why is this important? Well, we can use our lerp function to smooth edges! Let go back to our noise pattern and explain:</p>
<p><img src="/resources/img/blog/game/game-6.png" srcset="/resources/img/blog/game/game-6-1487x942.png 1487w, /resources/img/blog/game/game-6-1717x1088.png 1717w, /resources/img/blog/game/game-6-1919x1216.png 1919w, /resources/img/blog/game/game-6-858x543.png 858w, /resources/img/blog/game/game-6-1214x769.png 1214w" sizes="" alt=""></img></p>
<p>Let's say that, instead of coloring each pixel in this grid, we only color a pixel when it's exactly on a 10x10 lattice. In other words: when its x and y coordinates are divisible by 10.</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Noise</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">generate</span>(<span class="hl-injection"><span class="hl-type">Point</span> $x</span>): <span class="hl-type">float</span>
    {
        <span class="hl-keyword">if</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> % 10 === 0 <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> % 10 === 0) {
            <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$point</span>);
        } <span class="hl-keyword">else</span> {
            <span class="hl-keyword">return</span> 0.0;
        }
    }

    <span class="hl-comment">// …</span>
}
</pre>
<p>Here's the lattice:</p>
<p><img src="/resources/img/blog/game/game-11.png" srcset="/resources/img/blog/game/game-11-1214x769.png 1214w, /resources/img/blog/game/game-11-1919x1216.png 1919w, /resources/img/blog/game/game-11-858x543.png 858w, /resources/img/blog/game/game-11-1717x1088.png 1717w, /resources/img/blog/game/game-11-1487x942.png 1487w" sizes="" alt=""></img></p>
<p>Let's imagine that these pixels are the <code>$a</code> and <code>$b</code> boundaries we pass into our lerp function. For any given pixel, it's trivial to determine these surrounding "fixed" points (they are on a fixed 10x10 grid) and we can also calculate the pixel's relative distance to those points. We can use the hash of these fixed points and the distance from any pixel to these points as input values for our lerp function. The result will be a value that's somewhere between the values of our two edge points — in other words: a smooth transition.</p>
<p><img src="/resources/img/blog/game/game-21.png" srcset="/resources/img/blog/game/game-21-1087x218.png 1087w, /resources/img/blog/game/game-21-1720x345.png 1720w, /resources/img/blog/game/game-21-1332x267.png 1332w, /resources/img/blog/game/game-21-769x154.png 769w, /resources/img/blog/game/game-21-1538x308.png 1538w" sizes="" alt=""></img></p>
<p>First, we'll use our lerp function on the y-axis (whenever x is divisible by 10). We'll determine the relative top and bottom points on our "lattice", calculate the distance between our current point and the top point, and then we'll use our lerp function to determine the right value between the top and bottom point, with that distance fraction:</p>
<pre><span class="hl-keyword">if</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> % 10 === 0 <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> % 10 === 0) {
    <span class="hl-variable">$noise</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$point</span>);
} <span class="hl-keyword">elseif</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> % 10 === 0) {
    <span class="hl-variable">$topPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: <span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span>,
        <span class="hl-property">y</span>: (<span class="hl-property">floor</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> / 10) * 10), 
        <span class="hl-comment">// The closest point divisible by 10, above our current pixel</span>
    );

    <span class="hl-variable">$bottomPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: <span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span>, 
        <span class="hl-property">y</span>: (<span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> / 10) * 10) 
        <span class="hl-comment">// The closest point divisible by 10, below our current pixel</span>
    );

    <span class="hl-variable">$noise</span> = <span class="hl-property">lerp</span>(
        <span class="hl-comment">// The hash value (or color) of that top point:</span>
        <span class="hl-property">a</span>: <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$topPoint</span>),
        
        <span class="hl-comment">// The hash value (or color) of that bottom point:</span>
        <span class="hl-property">b</span>: <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$bottomPoint</span>),
        
        <span class="hl-comment">// The distance between our current point and the top point</span>
        <span class="hl-comment">// — the fraction</span>
        <span class="hl-property">fraction</span>: (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> - <span class="hl-variable">$topPoint</span>-&gt;<span class="hl-property">y</span>) / (<span class="hl-variable">$bottomPoint</span>-&gt;<span class="hl-property">y</span> - <span class="hl-variable">$topPoint</span>-&gt;<span class="hl-property">y</span>),
    );
}
</pre>
<p>Here's the result, you can already see the smooth transition within the lines:</p>
<p><img src="/resources/img/blog/game/game-12.png" srcset="/resources/img/blog/game/game-12-1919x1216.png 1919w, /resources/img/blog/game/game-12-858x543.png 858w, /resources/img/blog/game/game-12-1214x769.png 1214w, /resources/img/blog/game/game-12-1487x942.png 1487w, /resources/img/blog/game/game-12-1717x1088.png 1717w" sizes="" alt=""></img></p>
<p>Next, let's add the same functionality in the other direction, when y is divisible by 10:</p>
<pre><span class="hl-keyword">if</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> % 10 === 0 <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> % 10 === 0) {
    <span class="hl-comment">// …</span>
} <span class="hl-keyword">elseif</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> % 10 === 0) {
    <span class="hl-comment">// …</span>
} <span class="hl-keyword">elseif</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> % 10 === 0) {
    <span class="hl-variable">$leftPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: (<span class="hl-property">floor</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> / 10) * 10),
        <span class="hl-property">y</span>: <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span>,
    );

    <span class="hl-variable">$rightPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: (<span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> / 10) * 10),
        <span class="hl-property">y</span>: <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span>,
    );

    <span class="hl-variable">$noise</span> = <span class="hl-property">lerp</span>(
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$leftPoint</span>),
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$rightPoint</span>),
        (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> - <span class="hl-variable">$leftPoint</span>-&gt;<span class="hl-property">x</span>) / (<span class="hl-variable">$rightPoint</span>-&gt;<span class="hl-property">x</span> - <span class="hl-variable">$leftPoint</span>-&gt;<span class="hl-property">x</span>),
    );
}
</pre>
<p>No surprises:</p>
<p><img src="/resources/img/blog/game/game-13.png" srcset="/resources/img/blog/game/game-13-2263x1434.png 2263w, /resources/img/blog/game/game-13-2613x1656.png 2613w, /resources/img/blog/game/game-13-2922x1852.png 2922w, /resources/img/blog/game/game-13-1848x1171.png 1848w, /resources/img/blog/game/game-13-1306x827.png 1306w" sizes="" alt=""></img></p>
<p>Finally, for the remainder of the pixels, we won't be able to do a simple lerp function (which only works in one dimension). We'll have to use Bilinear Interpolation: we'll first make two lerp values for both x-axes, and then one final lerp value for the y-axis. We'll also need four edge points instead of two, because these pixels aren't aligned with our lattice.</p>
<p><img src="/resources/img/blog/game/game-29.png" srcset="/resources/img/blog/game/game-29-1448x1863.png 1448w, /resources/img/blog/game/game-29-1620x2085.png 1620w, /resources/img/blog/game/game-29-1024x1317.png 1024w, /resources/img/blog/game/game-29-724x931.png 724w, /resources/img/blog/game/game-29-1254x1613.png 1254w" sizes="" alt=""></img></p>
<pre><span class="hl-keyword">if</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> % 10 === 0 <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> % 10 === 0) {
    <span class="hl-comment">// …</span>
} <span class="hl-keyword">elseif</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> % 10 === 0) {
    <span class="hl-comment">// …</span>
} <span class="hl-keyword">elseif</span> (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> % 10 === 0) {
    <span class="hl-comment">// …</span>
} <span class="hl-keyword">else</span> {
    <span class="hl-variable">$topLeftPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: (<span class="hl-property">floor</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> / 10) * 10),
        <span class="hl-property">y</span>: (<span class="hl-property">floor</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> / 10) * 10),
    );

    <span class="hl-variable">$topRightPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: (<span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> / 10) * 10),
        <span class="hl-property">y</span>: (<span class="hl-property">floor</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> / 10) * 10),
    );

    <span class="hl-variable">$bottomLeftPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: (<span class="hl-property">floor</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> / 10) * 10),
        <span class="hl-property">y</span>: (<span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> / 10) * 10)
    );

    <span class="hl-variable">$bottomRightPoint</span> = <span class="hl-keyword">new</span> <span class="hl-type">Point</span>(
        <span class="hl-property">x</span>: (<span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> / 10) * 10),
        <span class="hl-property">y</span>: (<span class="hl-property">ceil</span>(<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> / 10) * 10)
    );

    <span class="hl-variable">$a</span> = <span class="hl-property">lerp</span>(
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$topLeftPoint</span>),
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$topRightPoint</span>),
        (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> - <span class="hl-variable">$topLeftPoint</span>-&gt;<span class="hl-property">x</span>) / (<span class="hl-variable">$topRightPoint</span>-&gt;<span class="hl-property">x</span> - <span class="hl-variable">$topLeftPoint</span>-&gt;<span class="hl-property">x</span>),
    );

    <span class="hl-variable">$b</span> = <span class="hl-property">lerp</span>(
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$bottomLeftPoint</span>),
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hash</span>(<span class="hl-variable">$bottomRightPoint</span>),
        (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> - <span class="hl-variable">$bottomLeftPoint</span>-&gt;<span class="hl-property">x</span>) / (<span class="hl-variable">$bottomRightPoint</span>-&gt;<span class="hl-property">x</span> - <span class="hl-variable">$bottomLeftPoint</span>-&gt;<span class="hl-property">x</span>),
    );

    <span class="hl-variable">$noise</span> = <span class="hl-property">lerp</span>(
        <span class="hl-variable">$a</span>,
        <span class="hl-variable">$b</span>,
        (<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> - <span class="hl-variable">$topLeftPoint</span>-&gt;<span class="hl-property">y</span>) / (<span class="hl-variable">$bottomLeftPoint</span>-&gt;<span class="hl-property">y</span> - <span class="hl-variable">$topLeftPoint</span>-&gt;<span class="hl-property">y</span>),
    );
}
</pre>
<p>Note that there's some repetition in our code that we could get rid of. But I prefer explicitly making all four edge points for clarity. Take a look at the result though:</p>
<p><img src="/resources/img/blog/game/game-14.png" srcset="/resources/img/blog/game/game-14-1919x1216.png 1919w, /resources/img/blog/game/game-14-858x543.png 858w, /resources/img/blog/game/game-14-1487x942.png 1487w, /resources/img/blog/game/game-14-1717x1088.png 1717w, /resources/img/blog/game/game-14-1214x769.png 1214w" sizes="" alt=""></img></p>
<p>This looks much smoother! Let's apply our colours:</p>
<p><img src="/resources/img/blog/game/game-15.png" srcset="/resources/img/blog/game/game-15-858x543.png 858w, /resources/img/blog/game/game-15-1919x1216.png 1919w, /resources/img/blog/game/game-15-1487x942.png 1487w, /resources/img/blog/game/game-15-1717x1088.png 1717w, /resources/img/blog/game/game-15-1214x769.png 1214w" sizes="" alt=""></img></p>
<p>Hm. You can probably see where we're going, but I still think these lines are far too… rough. Luckily, there are two more tricks we can apply! First, instead of using a plain lerp function, we can apply a so-called "<a href="https://thebookofshaders.com/05/">shaping function</a>" to our fraction. With this shaping function, we can manipulate our fraction before passing it to the lerp function. By default, our fraction will have a linear value — it's the distance from any given point to the starting edge:</p>
<p><img src="/resources/img/blog/game/game-22.png" srcset="/resources/img/blog/game/game-22-724x234.png 724w, /resources/img/blog/game/game-22-1448x469.png 1448w, /resources/img/blog/game/game-22-1254x406.png 1254w, /resources/img/blog/game/game-22-1024x331.png 1024w, /resources/img/blog/game/game-22-1620x525.png 1620w" sizes="" alt=""></img></p>
<p>But by applying a function to our fraction, we can manipulate it so that the values closer to the edges are even more smooth.</p>
<p><img src="/resources/img/blog/game/game-23.png" srcset="/resources/img/blog/game/game-23-1254x406.png 1254w, /resources/img/blog/game/game-23-724x234.png 724w, /resources/img/blog/game/game-23-1024x331.png 1024w, /resources/img/blog/game/game-23-1448x469.png 1448w, /resources/img/blog/game/game-23-1619x524.png 1619w" sizes="" alt=""></img></p>
<p>We could use whatever function we'd want. For our case I'll use a shaping function called <code>smoothstep</code>, which smooths edges.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">smooth</span>(<span class="hl-injection"><span class="hl-type">float</span> $a, <span class="hl-type">float</span> $b, <span class="hl-type">float</span> $fraction</span>): <span class="hl-type">float</span>
{
    <span class="hl-variable">$smoothstep</span> = <span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">float</span> $fraction</span>): <span class="hl-type">float</span> {
        <span class="hl-variable">$v1</span> = <span class="hl-variable">$fraction</span> * <span class="hl-variable">$fraction</span>;
        <span class="hl-variable">$v2</span> = 1.0  - (1.0 - <span class="hl-variable">$fraction</span>) * (1.0 -<span class="hl-variable">$fraction</span>);

        <span class="hl-keyword">return</span> <span class="hl-property">lerp</span>(<span class="hl-variable">$v1</span>, <span class="hl-variable">$v2</span>, <span class="hl-variable">$fraction</span>);
    };

    <span class="hl-keyword">return</span> <span class="hl-property">lerp</span>(<span class="hl-variable">$a</span>, <span class="hl-variable">$b</span>, <span class="hl-variable">$smoothstep</span>(<span class="hl-variable">$fraction</span>));
}
</pre>
<p>The difference is subtle, but it's a little bit better.</p>
<p><img src="/resources/img/blog/game/game-16.png" srcset="/resources/img/blog/game/game-16-858x543.png 858w, /resources/img/blog/game/game-16-1487x942.png 1487w, /resources/img/blog/game/game-16-1717x1088.png 1717w, /resources/img/blog/game/game-16-1919x1216.png 1919w, /resources/img/blog/game/game-16-1214x769.png 1214w" sizes="" alt=""></img></p>
<p>The second trick is to apply a new layer of noise. This one shouldn't be as random as our first one though. We'll use a simple circular pattern, and apply it as a height map on our existing noise. The further a pixel is from the center, the smaller its value:</p>
<pre><span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">circularNoise</span>(<span class="hl-injection"><span class="hl-type">int</span> $totalWidth, <span class="hl-type">int</span> $totalHeight, <span class="hl-type">Point</span> $point</span>): <span class="hl-type">float</span>
{
    <span class="hl-variable">$middleX</span> = <span class="hl-variable">$totalWidth</span> / 2;
    <span class="hl-variable">$middleY</span> = <span class="hl-variable">$totalHeight</span> / 2;

    <span class="hl-variable">$distanceFromMiddle</span> = <span class="hl-property">sqrt</span>(
        <span class="hl-property">pow</span>((<span class="hl-variable">$point</span>-&gt;<span class="hl-property">x</span> - <span class="hl-variable">$middleX</span>), 2)
        + <span class="hl-property">pow</span>((<span class="hl-variable">$point</span>-&gt;<span class="hl-property">y</span> - <span class="hl-variable">$middleY</span>), 2)
    );

    <span class="hl-variable">$maxDistanceFromMiddle</span> = <span class="hl-property">sqrt</span>(
        <span class="hl-property">pow</span>((<span class="hl-variable">$totalWidth</span> - <span class="hl-variable">$middleX</span>), 2)
        + <span class="hl-property">pow</span>((<span class="hl-variable">$totalHeight</span> - <span class="hl-variable">$middleY</span>), 2)
    );

    <span class="hl-keyword">return</span> 1 - (<span class="hl-variable">$distanceFromMiddle</span> / <span class="hl-variable">$maxDistanceFromMiddle</span>) + 0.3;
}
</pre>
<p>This is the pattern on its own:</p>
<p><img src="/resources/img/blog/game/game-17.png" srcset="/resources/img/blog/game/game-17-1214x769.png 1214w, /resources/img/blog/game/game-17-1717x1088.png 1717w, /resources/img/blog/game/game-17-1919x1216.png 1919w, /resources/img/blog/game/game-17-858x543.png 858w, /resources/img/blog/game/game-17-1487x942.png 1487w" sizes="" alt=""></img></p>
<p>And now we combine this pattern with our existing noise, which is as easy as multiplying them:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Noise</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">int</span> <span class="hl-property">$seed</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">generate</span>(<span class="hl-injection"><span class="hl-type">Point</span> $point</span>): <span class="hl-type">float</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">baseNoise</span>(<span class="hl-variable">$point</span>) 
             * <span class="hl-variable">$this</span>-&gt;<span class="hl-property">circularNoise</span>(<span class="hl-variable">$point</span>);
    }
}
</pre>
<p>Here's the result:</p>
<p><img src="/resources/img/blog/game/game-18.png" srcset="/resources/img/blog/game/game-18-1487x942.png 1487w, /resources/img/blog/game/game-18-1214x769.png 1214w, /resources/img/blog/game/game-18-1717x1088.png 1717w, /resources/img/blog/game/game-18-1919x1216.png 1919w, /resources/img/blog/game/game-18-858x543.png 858w" sizes="" alt=""></img></p>
<p>This looks a lot better! Thanks to our circular pattern, the middle portion of our map is raised, while the outer portions are lowered. It creates a neat island look. Let's try out some seeds to see the difference between them:</p>
<p><img src="/resources/img/blog/game/game-24.png" srcset="/resources/img/blog/game/game-24-1919x1216.png 1919w, /resources/img/blog/game/game-24-1214x769.png 1214w, /resources/img/blog/game/game-24-1487x942.png 1487w, /resources/img/blog/game/game-24-1717x1088.png 1717w, /resources/img/blog/game/game-24-858x543.png 858w" sizes="" alt=""></img>
<img src="/resources/img/blog/game/game-26.png" srcset="/resources/img/blog/game/game-26-1214x769.png 1214w, /resources/img/blog/game/game-26-1717x1088.png 1717w, /resources/img/blog/game/game-26-858x543.png 858w, /resources/img/blog/game/game-26-1487x942.png 1487w, /resources/img/blog/game/game-26-1919x1216.png 1919w" sizes="" alt=""></img>
<img src="/resources/img/blog/game/game-25.png" srcset="/resources/img/blog/game/game-25-858x543.png 858w, /resources/img/blog/game/game-25-1717x1088.png 1717w, /resources/img/blog/game/game-25-1487x942.png 1487w, /resources/img/blog/game/game-25-1919x1216.png 1919w, /resources/img/blog/game/game-25-1214x769.png 1214w" sizes="" alt=""></img></p>
<p>Pretty nice! But we're far from done: we'll want to add different areas on our map: forests, plains, mountains, vegetation, …. Simply using a <code>match</code> in our <code>drawPixel</code> method won't suffice anymore.</p>
<h2 id="improved-drawing"><a href="#improved-drawing" class="heading-anchor">#</a> Improved drawing</h2>
<p>Let's make an interface <code>Biome</code>, which will determine our pixel color, and can determine what kind of vegetation should be added. We'll also represent pixels as a proper value object.</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">Biome</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPixelColor</span>(<span class="hl-injection"><span class="hl-type">Pixel</span> $pixel</span>): <span class="hl-type">string</span>;
}
</pre>
<p>Let's add seas and plains first.</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">SeaBiome</span> <span class="hl-keyword">implements</span><span class="hl-type"> Biome
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPixelColor</span>(<span class="hl-injection"><span class="hl-type">Pixel</span> $pixel</span>): <span class="hl-type">string</span>
    {
        <span class="hl-variable">$base</span> = <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span>;

        <span class="hl-keyword">while</span> (<span class="hl-variable">$base</span> &lt; 0.25) {
            <span class="hl-variable">$base</span> += 0.01;
        }

        <span class="hl-variable">$r</span> = <span class="hl-property">hex</span>(<span class="hl-variable">$base</span> / 3);
        <span class="hl-variable">$g</span> = <span class="hl-property">hex</span>(<span class="hl-variable">$base</span> / 3);
        <span class="hl-variable">$b</span> = <span class="hl-property">hex</span>(<span class="hl-variable">$base</span>);

        <span class="hl-keyword">return</span> &quot;<span class="hl-value">#{$r}{$g}{$b}</span>&quot;;
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">PlainsBiome</span> <span class="hl-keyword">implements</span><span class="hl-type"> Biome
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPixelColor</span>(<span class="hl-injection"><span class="hl-type">Pixel</span> $pixel</span>): <span class="hl-type">string</span>
    {
        <span class="hl-variable">$g</span> = <span class="hl-property">hex</span>(<span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span>);
        <span class="hl-variable">$b</span> = <span class="hl-property">hex</span>(<span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> / 4);

        <span class="hl-keyword">return</span> &quot;<span class="hl-value">#00{$g}{$b}</span>&quot;;
    }
}
</pre>
<p>Depending on a pixel's biome, we'll use its noise to generate a different kind of color.
In our <code>drawPixel</code> function, we can now make some changes:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">drawPixel</span>(<span class="hl-injection"><span class="hl-type">Pixel</span> $pixel</span>): <span class="hl-type">string</span>
{
    <span class="hl-variable">$biome</span> = <span class="hl-type">BiomeFactory</span>::<span class="hl-keyword">for</span>(<span class="hl-variable">$pixel</span>);
    
    <span class="hl-variable">$color</span> = <span class="hl-variable">$biome</span>-&gt;<span class="hl-property">getPixelColor</span>(<span class="hl-variable">$pixel</span>);
    
    <span class="hl-keyword">return</span> &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">HTML</span></span><span class="hl-injection">
    &lt;<span class="hl-keyword">div</span> <span class="hl-property">style</span>=&quot;<span class="hl-keyword">
        --x: </span>{$x};<span class="hl-keyword"> 
        --y: </span>{$y};<span class="hl-keyword">
        --pixel-color: </span>{$color};
    &quot;&gt;&lt;/<span class="hl-keyword">div</span>&gt;
    </span><span class="hl-property"><span class="hl-property">HTML</span></span>;
}
</pre>
<p>For now, our <hljs type>BiomeFactory</hljs> will only take a pixel's value into account to determine the biome. We could add other conditions later.</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BiomeFactory</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-keyword">for</span>(<span class="hl-injection"><span class="hl-type">Pixel</span> $pixel</span>): <span class="hl-type">Biome</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-keyword">true</span>) {
            <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> &lt; 0.6 =&gt; <span class="hl-keyword">new</span> <span class="hl-type">SeaBiome</span>(),
            <span class="hl-keyword">default</span> =&gt; <span class="hl-keyword">new</span> <span class="hl-type">PlainsBiome</span>(),
        };
    }
}
</pre>
<p>It still works:</p>
<p><img src="/resources/img/blog/game/game-27.png" srcset="/resources/img/blog/game/game-27-858x543.png 858w, /resources/img/blog/game/game-27-1717x1088.png 1717w, /resources/img/blog/game/game-27-1487x942.png 1487w, /resources/img/blog/game/game-27-1919x1216.png 1919w, /resources/img/blog/game/game-27-1214x769.png 1214w" sizes="" alt=""></img></p>
<p>Let's go ahead and add all biomes now:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BiomeFactory</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">make</span>(<span class="hl-injection"><span class="hl-type">Pixel</span> $pixel</span>): <span class="hl-type">Biome</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-keyword">true</span>) {
            <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> &lt; 0.4 =&gt; <span class="hl-keyword">new</span> <span class="hl-type">SeaBiome</span>(),
            <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> &gt;= 0.4 <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> &lt; 0.44 =&gt; <span class="hl-keyword">new</span> <span class="hl-type">BeachBiome</span>(),
            <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> &gt;= 0.6 <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> &lt; 0.8 =&gt; <span class="hl-keyword">new</span> <span class="hl-type">ForestBiome</span>(),
            <span class="hl-variable">$pixel</span>-&gt;<span class="hl-property">value</span> &gt;= 0.8 =&gt; <span class="hl-keyword">new</span> <span class="hl-type">MountainBiome</span>(),
            <span class="hl-keyword">default</span> =&gt; <span class="hl-keyword">new</span> <span class="hl-type">PlainsBiome</span>(),
        };
    }
}
</pre>
<p>Note that I also decided to change the sea level: from 0.6 to 0.4, so the map looks a bit different now. Take a look:</p>
<p><img src="/resources/img/blog/game/game-28.png" srcset="/resources/img/blog/game/game-28-1487x942.png 1487w, /resources/img/blog/game/game-28-1717x1088.png 1717w, /resources/img/blog/game/game-28-1214x769.png 1214w, /resources/img/blog/game/game-28-858x543.png 858w, /resources/img/blog/game/game-28-1919x1216.png 1919w" sizes="" alt=""></img></p>
<p>Not bad, right? But this is far from a finished game — in fact, this is only the very first step: we'll need a way of interacting with this map, we'll need to define some form of gameplay. Maybe you remember the intro? I mentioned resource gathering. I imagine this game to be some kind of cookie-clicker style game: the more resources you gather, the more you can advance in the tech tree, the more resources you can gather, …</p>
<p>Anyway, I've done a lot more work on this game already: I actually started this project as an experiment to explore the limits of <a href="https://laravel-livewire.com/">Laravel Livewire</a>, so interactivity and gameplay were the primary focus. I've explained the basic concepts already <a href="https://www.youtube.com/watch?v=lnWrM6RXNak">on my YouTube channel</a> in two videos. I'm also working on a third video where I discuss how I added interaction to this particular game board, as well as the problems I ran in to (there are a bunch of caveats I haven't mentioned yet in this blog post).</p>
<p>So, if you want to follow along, make sure to <a href="https://www.youtube.com/@phpannotated">subscribe on YouTube</a> — I hope to make the third and final video of this series soon. Alternatively, you can <a href="/mail">subscribe to my mailing list</a>, where I'll send you an update as well.</p>
<p>In the meantime, you can watch the first two parts of this series; and don't forget to subscribe!</p>
<p>
    <iframe width="560" height="400" 
        src="https://www.youtube.com/embed/lnWrM6RXNak" 
        frameborder="0" 
        allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
        allowfullscreen>
    </iframe>
</p>
 ]]></summary>

                <updated>2023-05-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Things considered harmful ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/things-considered-harmful"/>

                <id>https://www.stitcher.io/blog/things-considered-harmful</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Someone on the internet shared their concerns about Laravel. They made a post on /r/php, a subreddit I moderate. They titled it "<a href="https://www.reddit.com/r/PHP/comments/131t2k1/laravel_considered_harmful/">Laravel considered harmful</a>", and currently it's the fifth most upvoted post of all-time on /r/php. We can talk all day about the arguments this person is making against Laravel — I agree with a handful of them, and disagree with another handful. But I'll let you join the discussion on Reddit, if you want to.</p>
<p>I do want to write about the underlying mindset of these kinds of posts, and of the people upvoting — that mindset of calling something "harmful". I can understand that someone doesn't like a framework, an ecosystem, the community or some individuals of that community. But calling something "<em>harmful</em>"? As if it's proven that Laravel hurts? Hurts what exactly? The PHP community? PHP's reputation? Laravel's competing frameworks? A programmer's "best practices"?</p>
<p>For what it's worth, I'd say that Laravel has done mostly good to the PHP community: it seems that <em>a lot</em> of people are able to make a living thanks to it; it seems that Laravel is widely known and praised within the programming community; in what way could it be considered "<em>harmful</em>"?</p>
<p>"It creates unmaintainable projects and doesn't teach best practices" — people say.</p>
<p>The argument of "best practices" baffles me. What defines a "best practice"? Aren't "best practices" meant to help you in building successful software? And hasn't Laravel proven to be able to do exactly that: build successful software? Shouldn't our assumptions of what defines a "best practice" be redefined if the most popular PHP framework doesn't seem to fit those assumptions?</p>
<p>Unmaintainable? To what extent? There are huge projects running Laravel in production — they have been for years? Some people will point towards failed Laravel projects, trying to prove their point. Well, let me show you success stories. Now what? Let me show you some failed Symfony projects. Who's right? Who's wrong?</p>
<p>This kind of mindset isn't uncommon in the programming world: we're used to doing things a certain way, and we're comfortable doing so. Whenever something comes along that doesn't fit our way of doing things, we experience friction. However, instead of questioning ourselves, too often do we point towards the thing that's causing friction, blaming it for everything that's wrong in the world. The safety of the internet makes it even more profound: we can write whatever we want with little to no consequences.</p>
<p>I would say that the inability to self-reflect, to adapt, and to question ourselves, is probably way more harmful than Laravel will ever be.</p>
 ]]></summary>

                <updated>2023-05-02T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Limited by committee ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/limited-by-committee"/>

                <id>https://www.stitcher.io/blog/limited-by-committee</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Camels are weird. Granted, they <em>do</em> manage to survive in some of the harshest environments on our planet, so, obviously, they are doing something right. But, I mean, look at them:</p>
<p><img src="/resources/img/blog/committee/camel3.jpg" srcset="/resources/img/blog/committee/camel3-447x280.jpg 447w, /resources/img/blog/committee/camel3-774x485.jpg 774w, /resources/img/blog/committee/camel3-1000x627.jpg 1000w, /resources/img/blog/committee/camel3-632x396.jpg 632w, /resources/img/blog/committee/camel3-894x560.jpg 894w" sizes="" alt=""></img></p>
<p>It looks like someone combined a horse with a giraffe, and kept adding stuff until they met the requirement of "being able to survive in the desert". Who came up with that?  Don't get me wrong: camels <em>do</em> work, so they must have gotten something right. But honestly, the finishing touches are far from ideal:</p>
<p><img src="/resources/img/blog/committee/camel4.jpg" srcset="/resources/img/blog/committee/camel4-774x595.jpg 774w, /resources/img/blog/committee/camel4-447x343.jpg 447w, /resources/img/blog/committee/camel4-632x486.jpg 632w, /resources/img/blog/committee/camel4-1000x769.jpg 1000w, /resources/img/blog/committee/camel4-894x687.jpg 894w" sizes="" alt=""></img></p>
<p>PHP is like a camel: there's little to say when it comes to beauty or elegance, but it does seem to survive many harsh conditions. So, who am I to judge? Coincidentally, PHP was originally inspired by PERL, whose logo is a camel; so maybe there <em>is</em> a deeper connection still? But let's not go too deep down the <span style="text-decoration:line-through">camel</span> rabbit hole; instead, let's talk about how programming languages are designed.</p>
<p>PHP is one of those programming languages that's not backed by a big company or a group of people whose job it is to work on it. PHP is mostly driven by a group of volunteers. A year ago, we got the <a href="https://thephp.foundation/">PHP Foundation</a> which employs a handful of developers to work on the language, but it's not like they have any ownership. They have to submit their ideas, and are at the mercy of "PHP Internals" to decide what goes in the language, and what not.</p>
<p>So about that <em>group of volunteers</em>: PHP Internals are a group of people who discuss and vote on what gets added into the language. Part of that group consists of core developers, and then there are some prominent PHP community members, release managers, past contributors, docs maintainers, and probably a bunch of other people. We're talking somewhere around 200 members — probably, but there aren't any public numbers, as far as I know.</p>
<p>That group is the perfect example of a committee: they all come together to decide on how PHP should evolve next. They don't have a unified plan or vision, but all of them bring their own agenda. While a core programmer might favor cleaning up PHP's internal code (even when it brings some breaking changes), a prominent community member might push forward ideas that help with the development of a PHP framework or package.</p>
<p>This phenomenon — designing a language with such a large group — is called "<a href="https://en.wikipedia.org/wiki/Design_by_committee">design by committee</a>". At first glance, it might sound like a very democratic approach to software design where everyone can pitch an idea, and if enough people vote for it, it gets added. However, because there's such a large diversity of opinions, a committee rarely achieves excellence.</p>
<p>Say you want to add a feature in PHP that benefits you — a prominent framework developer. Then you'll have to convince enough people to vote for it. First, you request Internals to share their comments on your idea — an RFC (request for comments). Naturally, you'll make compromises, trying to get as many people on your side as possible before voting starts. On top of that: people can lobby others to influence their vote and, in the end, the result. Suddenly you're playing a game of politics, instead of proper software design.</p>
<p>And so, design by committee often leads to average results at best; or (in many cases) no result, because people couldn't find consensus. Camels were probably designed by a committee as well. Sure, they work, but they are far from excellence and full of compromise.</p>
<p><img src="/resources/img/blog/committee/camel5.jpg" srcset="/resources/img/blog/committee/camel5-774x646.jpg 774w, /resources/img/blog/committee/camel5-447x373.jpg 447w, /resources/img/blog/committee/camel5-1000x835.jpg 1000w, /resources/img/blog/committee/camel5-632x527.jpg 632w, /resources/img/blog/committee/camel5-894x746.jpg 894w" sizes="" alt=""></img></p>
<p>The alternative to design by committee is called "design by dictator" or having a "benevolent dictator for life". It might sound rather negative at first, but hear me out. A benevolent dictator (or group of benevolent dictators) don't want to push their own agenda; they want the best for their product. It's <em>their</em> product — they have full ownership. And exactly because it is <em>their</em> product, they <em>will</em> listen to "the masses". Because, their product is nothing, without their people.</p>
<p>In the end though, a dictator <em>will</em> make decisions, even when those decisions aren't agreed upon within the community as a whole. There's much less need for compromise, and so, more room for excellence.</p>
<p>Maybe you are skeptical of the idea? Well, don't take my word for it, there are quite a lot of open source projects applying this technique. You might even recognise a couple:</p>
<ul>
<li>Rust</li>
<li>Laravel</li>
<li>Ruby</li>
<li>Linux</li>
<li>Ruby on Rails</li>
<li>Ubuntu</li>
<li>Vue.js</li>
<li>
<a href="https://en.wikipedia.org/wiki/Benevolent_dictator_for_life">And more</a>
</li>
</ul>
<p>I think it's fair to say that all of these projects are a huge success. I believe much of their success comes from that one person in charge, leading the way, having a clear vision. These leaders still listen to their audience, and they often allow for voting on features. But, in the end, there's one person carrying the ownership. There's one leader to look up to.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>When people trust a benevolent dictator, much more becomes possible than when they settle with a committee.</p>
<p>PHP will never change its leadership model; the committee would have to give up its power which, of course, they don't want to. I think this is one of the reasons I'm excited about the idea of a superset for PHP: it could be an independent project, led by one person or a company, regardless of what the committee wants. If that person or company gained my trust, I would be fine with them make the decisions to move the language forward, rather than settling with average.</p>
 ]]></summary>

                <updated>2023-03-22T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Cloning readonly properties in PHP 8.3 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/cloning-readonly-properties-in-php-83"/>

                <id>https://www.stitcher.io/blog/cloning-readonly-properties-in-php-83</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8.3 adds the possibility of overwriting readonly property values while cloning an object. Don't be mistaken though: you're not able to clone any object and overwrite their readonly values from any place. This feature only addresses a very specific (but important) edge case.</p>
<p>Let's take a look!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>In an ideal world, we'd be able to clone classes with readonly properties, based on a user-defined set of values. The so called <code>clone with</code> syntax (which doesn't exist):</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$author</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTime</span> <span class="hl-property">$createdAt</span>,
    </span>) {}
}

<span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(
    <span class="hl-property">title</span>: '<span class="hl-value">Hello World</span>',
    <span class="hl-comment">// …</span>
);

 <span class="hl-comment">// This isn't possible!</span>
<span class="hl-variable">$updatedPost</span> = <span class="hl-keyword">clone</span> <span class="hl-variable">$post</span> with {
    <span class="hl-property">title</span>: '<span class="hl-value">Another One!</span>',
};
</pre>
<p>Reading the title of the current <a href="https://wiki.php.net/rfc/readonly_amendments">RFC</a>: "Readonly properties can be reinitialized during cloning" — you might think something like <code>clone with</code> this is now possible. However… it isn't. The RFC allows only allows for one specific operation: to overwrite readonly values in the magic <code>__clone</code> method:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$author</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTime</span> <span class="hl-property">$createdAt</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__clone</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">createdAt</span> = <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>(); 
        <span class="hl-comment">// This is allowed,</span>
        <span class="hl-comment">// even though `createdAt` is a readonly property.</span>
    }
}
</pre>
<p>Is this useful? It is! Say you want to clone objects with nested objects — a.k.a. making "deep clones"; then this RFC allows you to clone those nested objects as well, and overwrite them in your newly created clone — even when they are readonly properties.</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__clone</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">createdAt</span> = <span class="hl-keyword">clone</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">createdAt</span>; 
        <span class="hl-comment">// Creates a new DateTime object,</span>
        <span class="hl-comment">// instead of reusing the reference</span>
    }
}
</pre>
<p>Without this RFC, you'd be able to clone <code>$post</code>, but it would still hold a reference to the original <code>$createdAt</code> object. Say you'd make changes to that object (which is possible since <code>readonly</code> only prevents the property assigned from changing, not from its inner values being changed):</p>
<pre><span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(<span class="hl-comment">/* … */</span>);

<span class="hl-variable">$otherPost</span> = <span class="hl-keyword">clone</span> <span class="hl-variable">$post</span>;

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">createdAt</span>-&gt;<span class="hl-property">add</span>(<span class="hl-keyword">new</span> <span class="hl-type">DateInterval</span>('<span class="hl-value">P1D</span>'));

<span class="hl-variable">$otherPost</span>-&gt;<span class="hl-property">createdAt</span> === <span class="hl-variable">$post</span>-&gt;<span class="hl-property">createdAt</span>; <span class="hl-comment">// true :(</span>
</pre>
<p>Then you'd end up with the <code>$createdAt</code> date changed on both objects!</p>
<p>Thanks to this RFC, we can make real clones, with all their nested properties cloned as well, even when these properties are readonly:</p>
<pre><span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(<span class="hl-comment">/* … */</span>);

<span class="hl-variable">$otherPost</span> = <span class="hl-keyword">clone</span> <span class="hl-variable">$post</span>;

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">createdAt</span>-&gt;<span class="hl-property">add</span>(<span class="hl-keyword">new</span> <span class="hl-type">DateInterval</span>('<span class="hl-value">P1D</span>'));

<span class="hl-variable">$otherPost</span>-&gt;<span class="hl-property">createdAt</span> === <span class="hl-variable">$post</span>-&gt;<span class="hl-property">createdAt</span>; <span class="hl-comment">// false :)</span>
</pre>
<h2 id="on-a-personal-note"><a href="#on-a-personal-note" class="heading-anchor">#</a> On a personal note</h2>
<p>I think it's good that PHP 8.3 makes it possible deep cloning readonly properties. However, I <em>have</em> mixed feelings about this implementation. Imagine for a second that <code>clone with</code> existed in PHP, then all of the above would have been unnecessary. Take a look:</p>
<pre><span class="hl-comment">// Again, this isn't possible!</span>
<span class="hl-variable">$updatedPost</span> = <span class="hl-keyword">clone</span> <span class="hl-variable">$post</span> with { 
    <span class="hl-property">createdAt</span>: <span class="hl-keyword">clone</span> <span class="hl-variable">$post</span>-&gt;<span class="hl-property">createdAt</span>,
};
</pre>
<p>Now imagine that <code>clone with</code> gets added in PHP 8.4 — pure speculation, of course. It means we'd have two ways of doing the same thing in PHP. I don't know about you, but I don't like it when languages or frameworks offer <a href="https://www.youtube.com/watch?v=yBLVBwiAfrM&amp;ab_channel=CodeStyle">several ways of doing the same thing</a>. As far as I'm concerned, that's suboptimal language design at best.</p>
<p>This is, of course, assuming that <code>clone with</code> would be able to automatically map values to properties without the need of manually implementing mapping logic in <code>__clone</code>. I'm also assuming that <code>clone with</code> can deal with property visibility: only able to change public properties from the outside, but able to change protected and private properties when used inside a class.</p>
<p>Awhile ago, I wrote about <a href="/blog/thoughts-on-asymmetric-visibility">how PHP internals seem to be divided</a>, one group comes up with one solution, while another group wants to take another approach. To me, it's a clear drawback of <a href="https://marketoonist.com/2017/10/committee.html">designing by committee</a>.</p>
<p>Full disclosure — the RFC mentions <code>clone with</code> as a future scope:</p>
<blockquote>
<p>None of the envisioned ideas for the future collide with the proposals in this RFC. They could thus be considered separately later on.</p>
</blockquote>
<p>But I tend to disagree with this statement, at least assuming that <code>clone with</code> would work without having to implement any userland code. If we'd follow the trend of this current RFC, I could imagine someone suggesting to add <code>clone with</code> only as a way to pass data into <code>__clone</code>, and have users deal with it themselves:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__clone</span>(<span class="hl-injection">...$properties</span>)
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$properties</span> <span class="hl-keyword">as</span> <span class="hl-variable">$name</span> =&gt; <span class="hl-variable">$value</span>) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-variable">$name</span> = <span class="hl-variable">$value</span>;
        }
    }
}
</pre>
<p>However, I really hope this isn't the way <code>clone with</code> gets implemented; because you'd have to add a <code>__clone</code> implementation on every readonly class.</p>
<p>So, assuming the best case where <code>clone with</code> gets added, and where it is able to automatically map values; then the functionality of this current RFC gets voided, and makes it so that we have two ways of doing the same thing. It will confuse users because it faces them with yet another a decision when coding. I think PHP has grown confusing enough as is, and I'd like to see that change.</p>
<p>On the other hand, I do want to mention that I don't oppose this RFC on its own. I think Nicolas and Máté did a great job coming up with a solid solution to a real-life problem.</p>
<hr />
<p>PS: in case someone wants to make the argument for the current RFC because you only need to implement <code>__clone</code> once per object and not worry about it on call-site anymore. There's one very important details missing from these examples in isolation: deep copying doesn't happen with a simple <code>clone</code> call. Most of the time, packages like <a href="https://packagist.org/packages/myclabs/deep-copy">deep-copy</a> are used, and thus, the potential overhead that comes with my <code>clone with</code> example is already taken care off by those packages and don't bother end users.</p>
 ]]></summary>

                <updated>2023-03-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Thank you, Kinsta ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/thank-you-kinsta"/>

                <id>https://www.stitcher.io/blog/thank-you-kinsta</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>A couple of weeks ago, I shared a bit about <a href="/blog/sponsors">the financial side of running stitcher.io</a>. I explained how I would like stitcher.io to be break-even after a large sponsor deal had ended.</p>
<p>Today I want to thank <a href="https://kinsta.com/">Kinsta</a> in particular for stepping in and helping out! They've committed to a generous monthly sponsorship, which is getting me closer to achieving that break-even goal.</p>
<p>If you haven't heard of Kinsta before, they are a cloud platform targeted towards companies and dev teams to help them ship and manage their web projects. What I like about companies like Kinsta is that they are always on the lookout for helping out the community members like they did with my sponsor issue. They contacted me out of the blue saying they wanted to help, which I really appreciate!</p>
<p>So big thanks to Kinsta for helping me work on stitcher.io in my free time!</p>
 ]]></summary>

                <updated>2023-03-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Slashdash ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/slashdash"/>

                <id>https://www.stitcher.io/blog/slashdash</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>A year or so ago, I stumbled upon a website for yet another document language similar to YAML, JSON or XML; it was called <a href="https://kdl.dev/">KDL</a>. I don't know what became of it, but it had one little feature that stood out: something they called "slashdash comments": <code>/-</code>. You can use it to mark code as comments, but it is scope aware.</p>
<p>For example, you can use it to comment out individual keywords and statements like <code>final</code> or <code>implements X</code>:</p>
<pre>/-final class Foo /-implements Bar
</pre>
<p>But you could also use the <code>/--</code> variant to comment out a whole section based on its scope:</p>
<pre>/--public function fromInterface(int $i): int {
    return $i + 1;
}
</pre>
<p>It's just a small thing, but when I saw it, it immediately clicked. Especially in a language like PHP where "dump and die debugging" is the de-facto standard, it would be nice to have a slightly shorter and more convenient way to comment out code.</p>
<pre>/-final class Foo /-implements Bar
{
    public /-readonly string $prop;
    
    /--public function fromInterface(int $i): int {
        return $i + 1;
    }
}
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
 ]]></summary>

                <updated>2023-02-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ I&#039;m a light schemer ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/light-colour-schemes"/>

                <id>https://www.stitcher.io/blog/light-colour-schemes</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><iframe width="560" height="422" src="https://www.youtube.com/embed/udjZ7VUOrzw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>I’ve been laughed at and ridiculed. But don’t worry, I won’t give in. I will keep using a <strong>light colour scheme</strong>.</p>
<p>I know I’m a minority, and people do ask me why I keep using light colours schemes. Well, I’ve got three reasons to do so, and I think they make a pretty good point for everyone to switch.</p>
<p>First, people have been doing research into text readability. Studies show that our eyes can more easily distinguish a dark foreground from a light background, than the other way around. I will leave some links in the footnotes if you want to read about it. I find it a compelling first reason for light colour schemes: they are easier to read.</p>
<p>Second: the majority of websites and UIs are still made with a light colour scheme first, so switching between dark code and light applications becomes tiring after a while, especially if you’re doing it day in, day out. Granted, more and more applications support dark mode, but then we’re back to reason one: they are more difficult to read.</p>
<p>Third, and this is probably the thing most people think about: there’s this misconception that “light colour schemes” hurt your eyes, especially in dark rooms. Let me tell you: sitting in an all dark room programming isn’t good for your eyes anyways, regardless of the colour scheme you’re using. If you feel that a light colour scheme hurts your eyes, it might be better to lower the brightness of your screen and make sure your room is properly lit because — a dark theme isn’t the solution.</p>
<p>When I first learned about the real arguments for light colour schemes, I couldn’t do anything else but to use them. I’ve got decades to go in front of a screen, and I really need to do all I can to make it as easy as possible for my eyes.</p>
<p>Here’s my challenge: use a light colour scheme for a week, but do it in a properly lit room, and with proper screen brightness. Come back here after a week, and let me know your thoughts.</p>
<p><iframe width="560" height="422" src="https://www.youtube.com/embed/udjZ7VUOrzw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
 ]]></summary>

                <updated>2023-02-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ I&#039;m a code folder ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/code-folding"/>

                <id>https://www.stitcher.io/blog/code-folding</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><iframe width="560" height="422" src="https://www.youtube.com/embed/aGspz-sBkyI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>I know it looks strange the first time you see it, but hear me out for a minute: I am a code folder.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">TwitterSyncCommand</span> <span class="hl-keyword">extends</span> <span class="hl-type">Command</span>
{
    <span class="hl-keyword">protected</span> <span class="hl-property">$signature</span> = '<span class="hl-value">twitter:sync {--clean}</span>';

    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\Illuminate\Database\Eloquent\Collection&lt;<span class="hl-generic">Mute</span>&gt; </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-type">Collection</span> <span class="hl-property">$mutes</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection"><span class="hl-type">Twitter</span> $twitter</span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">syncFromList</span>(<span class="hl-injection"><span class="hl-type">Twitter</span> $twitter</span>): <span class="hl-type">void</span> { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">syncFromSearch</span>(<span class="hl-injection"><span class="hl-type">Twitter</span> $twitter</span>): <span class="hl-type">void</span> { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">storeTweets</span>(<span class="hl-injection"><span class="hl-type">array</span> $tweets, <span class="hl-type">TweetFeedType</span> $feedType</span>): <span class="hl-type">void</span> { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">shouldBeRejected</span>(<span class="hl-injection"><span class="hl-type">Tweet</span> $tweet</span>): <span class="hl-type">?RejectionReason</span> { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>I hide most of my code, most of the time. I have keyboard shortcuts to easily show and hide blocks of code; and when I open a file, all method and function bodies are collapsed by default.</p>
<p>The reason? I’m not a superhuman speed reader that understands dozens of lines of code at one glance. And… I also don’t have a two-metre-high screen.</p>
<p>I just can’t read and understand all of this — you know?</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">TwitterSyncCommand</span> <span class="hl-keyword">extends</span> <span class="hl-type">Command</span>
{
    <span class="hl-keyword">protected</span> <span class="hl-property">$signature</span> = '<span class="hl-value">twitter:sync {--clean}</span>';

    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\Illuminate\Database\Eloquent\Collection&lt;<span class="hl-generic">Mute</span>&gt; </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-type">Collection</span> <span class="hl-property">$mutes</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection"><span class="hl-type">Twitter</span> $twitter</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">mutes</span> = <span class="hl-type">Mute</span>::<span class="hl-property">query</span>()-&gt;<span class="hl-property">select</span>('<span class="hl-value">text</span>')-&gt;<span class="hl-property">get</span>();

        <span class="hl-keyword">if</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">option</span>('<span class="hl-value">clean</span>')) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">error</span>('<span class="hl-value">Truncating tweets!</span>');

            <span class="hl-type">Tweet</span>::<span class="hl-property">truncate</span>();
        }

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">syncFromSearch</span>(<span class="hl-variable">$twitter</span>);

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">syncFromList</span>(<span class="hl-variable">$twitter</span>);

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">info</span>('<span class="hl-value">Done</span>');
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">syncFromList</span>(<span class="hl-injection"><span class="hl-type">Twitter</span> $twitter</span>): <span class="hl-type">void</span>
    {
        <span class="hl-keyword">do</span> {
            <span class="hl-variable">$lastTweet</span> = <span class="hl-type">Tweet</span>::<span class="hl-property">query</span>()
                -&gt;<span class="hl-property">where</span>('<span class="hl-value">feed_type</span>', <span class="hl-type">TweetFeedType</span>::<span class="hl-property">LIST</span>)
                -&gt;<span class="hl-property">orderByDesc</span>('<span class="hl-value">tweet_id</span>')
                -&gt;<span class="hl-property">first</span>();

            <span class="hl-variable">$tweets</span> = <span class="hl-variable">$twitter</span>-&gt;<span class="hl-property">request</span>('<span class="hl-value">lists/statuses.json</span>', '<span class="hl-property">GET</span>', [
                '<span class="hl-value">list_id</span>' =&gt; <span class="hl-property">config</span>('<span class="hl-value">services.twitter.list_id</span>'),
                '<span class="hl-value">since_id</span>' =&gt; <span class="hl-variable">$lastTweet</span>?-&gt;<span class="hl-property">tweet_id</span>,
                '<span class="hl-value">count</span>' =&gt; 200,
                '<span class="hl-value">tweet_mode</span>' =&gt; '<span class="hl-value">extended</span>',
            ]);

            <span class="hl-variable">$count</span> = <span class="hl-property">count</span>(<span class="hl-variable">$tweets</span>);

            <span class="hl-keyword">if</span> (<span class="hl-variable">$count</span> === 0) {
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">comment</span>('<span class="hl-value">No more new tweets</span>');
            } <span class="hl-keyword">else</span> {
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">comment</span>(&quot;<span class="hl-value">Syncing {$count} tweets from list</span>&quot;);

                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">storeTweets</span>(<span class="hl-variable">$tweets</span>, <span class="hl-type">TweetFeedType</span>::<span class="hl-property">LIST</span>);
            }
        } <span class="hl-keyword">while</span> (<span class="hl-variable">$tweets</span> !== []);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">syncFromSearch</span>(<span class="hl-injection"><span class="hl-type">Twitter</span> $twitter</span>): <span class="hl-type">void</span>
    {
        <span class="hl-keyword">do</span> {
            <span class="hl-variable">$lastTweet</span> = <span class="hl-type">Tweet</span>::<span class="hl-property">query</span>()
                -&gt;<span class="hl-property">where</span>('<span class="hl-value">feed_type</span>', <span class="hl-type">TweetFeedType</span>::<span class="hl-property">SEARCH</span>)
                -&gt;<span class="hl-property">orderByDesc</span>('<span class="hl-value">tweet_id</span>')
                -&gt;<span class="hl-property">first</span>();

            <span class="hl-variable">$tweets</span> = <span class="hl-variable">$twitter</span>-&gt;<span class="hl-property">request</span>('<span class="hl-value">/search/tweets.json</span>', '<span class="hl-property">GET</span>', [
                '<span class="hl-value">q</span>' =&gt; '<span class="hl-value">phpstorm</span>',
                '<span class="hl-value">since_id</span>' =&gt; <span class="hl-variable">$lastTweet</span>?-&gt;<span class="hl-property">tweet_id</span>,
                '<span class="hl-value">count</span>' =&gt; 200,
                '<span class="hl-value">tweet_mode</span>' =&gt; '<span class="hl-value">extended</span>',
            ])-&gt;<span class="hl-property">statuses</span>;

            <span class="hl-variable">$count</span> = <span class="hl-property">count</span>(<span class="hl-variable">$tweets</span>);

            <span class="hl-keyword">if</span> (<span class="hl-variable">$count</span> === 0) {
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">comment</span>('<span class="hl-value">No more new tweets</span>');
            } <span class="hl-keyword">else</span> {
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">comment</span>(&quot;<span class="hl-value">Syncing {$count} tweets from search</span>&quot;);

                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">storeTweets</span>(<span class="hl-variable">$tweets</span>, <span class="hl-type">TweetFeedType</span>::<span class="hl-property">SEARCH</span>);
            }
        } <span class="hl-keyword">while</span> (<span class="hl-variable">$tweets</span> !== []);
    }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">storeTweets</span>(<span class="hl-injection"><span class="hl-type">array</span> $tweets, <span class="hl-type">TweetFeedType</span> $feedType</span>): <span class="hl-type">void</span>
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$tweets</span> <span class="hl-keyword">as</span> <span class="hl-variable">$tweet</span>) {
            <span class="hl-variable">$subject</span> = <span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">retweeted_status</span> ?? <span class="hl-variable">$tweet</span>;

            <span class="hl-variable">$tweet</span> = <span class="hl-type">Tweet</span>::<span class="hl-property">updateOrCreate</span>([
                '<span class="hl-value">tweet_id</span>' =&gt; <span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">id</span>,
            ], [
                '<span class="hl-value">state</span>' =&gt; <span class="hl-type">TweetState</span>::<span class="hl-property">PENDING</span>,
                '<span class="hl-value">feed_type</span>' =&gt; <span class="hl-variable">$feedType</span>,
                '<span class="hl-value">text</span>' =&gt; <span class="hl-variable">$subject</span>-&gt;<span class="hl-property">full_text</span> ,
                '<span class="hl-value">user_name</span>' =&gt; <span class="hl-variable">$subject</span>-&gt;<span class="hl-property">user</span>-&gt;<span class="hl-property">screen_name</span>,
                '<span class="hl-value">retweeted_by_user_name</span>' =&gt; <span class="hl-keyword">isset</span>(<span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">retweeted_status</span>)
                    <span class="hl-comment">/** <span class="hl-value">@phpstan</span>-ignore-next-line  */</span>
                    <span class="hl-operator">?</span> <span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">user</span>-&gt;<span class="hl-property">screen_name</span>
                    : <span class="hl-keyword">null</span>,
                '<span class="hl-value">created_at</span>' =&gt; <span class="hl-type">Carbon</span>::<span class="hl-property">make</span>(<span class="hl-variable">$subject</span>-&gt;<span class="hl-property">created_at</span>),
                '<span class="hl-value">payload</span>' =&gt; <span class="hl-property">json_encode</span>(<span class="hl-variable">$tweet</span>),
            ]);

            <span class="hl-keyword">if</span> (<span class="hl-variable">$reason</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">shouldBeRejected</span>(<span class="hl-variable">$tweet</span>)) {
                <span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">update</span>([
                    '<span class="hl-value">state</span>' =&gt; <span class="hl-type">TweetState</span>::<span class="hl-property">REJECTED</span>,
                    '<span class="hl-value">rejection_reason</span>' =&gt; <span class="hl-variable">$reason</span>-&gt;<span class="hl-property">message</span>,
                ]);
            }

            (<span class="hl-keyword">new</span> <span class="hl-type">ParseTweetText</span>)(<span class="hl-variable">$tweet</span>);
        }
    }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">shouldBeRejected</span>(<span class="hl-injection"><span class="hl-type">Tweet</span> $tweet</span>): <span class="hl-type">?RejectionReason</span>
    {
        <span class="hl-keyword">if</span> (<span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">isRetweet</span>() <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">feed_type</span> === <span class="hl-type">TweetFeedType</span>::<span class="hl-property">SEARCH</span>) {
            <span class="hl-keyword">return</span> <span class="hl-type">RejectionReason</span>::<span class="hl-property">retweetedFromSearch</span>();
        }

        <span class="hl-comment">// Reject tweets containing a specific word</span>
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">mutes</span> <span class="hl-keyword">as</span> <span class="hl-variable">$mute</span>) {
            <span class="hl-keyword">if</span> (<span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">containsPhrase</span>(<span class="hl-variable">$mute</span>-&gt;<span class="hl-property">text</span>)) {
                <span class="hl-keyword">return</span> <span class="hl-type">RejectionReason</span>::<span class="hl-property">mute</span>(<span class="hl-variable">$mute</span>-&gt;<span class="hl-property">text</span>);
            }
        }

        <span class="hl-comment">// Reject replies</span>
        <span class="hl-keyword">if</span> (<span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">getPayload</span>()-&gt;<span class="hl-property">in_reply_to_status_id</span>) {
            <span class="hl-keyword">return</span> <span class="hl-type">RejectionReason</span>::<span class="hl-property">isReply</span>();
        }

        <span class="hl-comment">// Reject mentions</span>
        <span class="hl-keyword">if</span> (<span class="hl-property">str_starts_with</span>(<span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">text</span>, '<span class="hl-value">@</span>')) {
            <span class="hl-keyword">return</span> <span class="hl-type">RejectionReason</span>::<span class="hl-property">isMention</span>();
        }

        <span class="hl-comment">// Reject non-english tweets</span>
        <span class="hl-variable">$language</span> = <span class="hl-variable">$tweet</span>-&gt;<span class="hl-property">getPayload</span>()-&gt;<span class="hl-property">lang</span>;

        <span class="hl-keyword">if</span> (<span class="hl-variable">$language</span> !== '<span class="hl-value">en</span>') {
            <span class="hl-keyword">return</span> <span class="hl-type">RejectionReason</span>::<span class="hl-property">otherLanguage</span>(<span class="hl-variable">$language</span>);
        }

        <span class="hl-keyword">return</span> <span class="hl-keyword">null</span>;
    }
}
</pre>
<p>I feel overwhelmed looking at all that code, especially when I’m searching for one specific method.</p>
<p>Now, when I create a new file, it’s all fine, it’s a blank slate, and I’ve got control. But code grows rapidly, and real life projects more often than not include work in existing files instead of blank slates. So I really need a way to reduce cognitive load, I can’t “take it all in at once”. And that’s why I’ve grown to like code folding so much.</p>
<p>Give yourself a week to get used to it. Configure your IDE to automatically fold method bodies and functions, and assign proper key bindings to show and hide blocks. I promise you, you’ll like it.</p>
<p><iframe width="560" height="422" src="https://www.youtube.com/embed/aGspz-sBkyI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
 ]]></summary>

                <updated>2023-02-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Acronyms ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/acronyms"/>

                <id>https://www.stitcher.io/blog/acronyms</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm suspicious of acronyms. Think about it: is it a coincidence that the five most important principles in programming just <em>happen</em> to line up to form the word "SOLID"?</p>
<p>I'm suspicious of acronyms because there's always <em>someone</em>, <em>somewhere</em>, making compromises to make them work. Whether it is by omitting equally (or more) important elements because they don't fit the acronym; whether less important elements are <em>included</em> to make it work; or whether names are changed, their meaning obfuscated, so that they'd fit perfectly.</p>
<p>Acronyms are of course a great choice to market your ideas because, well, people tend to remember them. SOLID is the perfect example.</p>
 ]]></summary>

                <updated>2023-01-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Fonts matter ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/fonts-matter"/>

                <id>https://www.stitcher.io/blog/fonts-matter</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <style>
.fonts-01 code {
    font-size: 12px;
    line-height: 1.1em;
    font-family: "Courier New", monospace;
}

.fonts-02 code {
    line-height: 1.1em;
    font-family: "Courier New", monospace;
}

.fonts-03 code {
    line-height: 1.2em;
}
</style>
<p><iframe width="560" height="422" src="https://www.youtube.com/embed/1UxQX00BZug" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>I like to think of my code as a book. Not just any book, I think of it as a precious, beautifully designed work of art. Something I want to <em>WANT</em> to read. You know why? Because programming is so much more about reading and understanding code, than it is about writing.</p>
<p>I would say that “writing code” is only the lesser part of my programming life. So naturally, I have much to gain by making the “reading part” as pleasant as possible.</p>
<p>So, let's work from an example:</p>
<div class="fonts-01">
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">CodeController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-keyword">private</span> <span class="hl-type">MarkdownConverter</span> <span class="hl-property">$markdown</span></span>) {}

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">string</span> $slug</span>)
    {
        <span class="hl-variable">$code</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">markdown</span>-&gt;<span class="hl-property">convert</span>(<span class="hl-property">file_get_contents</span>(<span class="hl-property">__DIR__</span> . &quot;<span class="hl-value">/code/{$slug}.md</span>&quot;))-&gt;<span class="hl-property">getContent</span>();

        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">code</span>', [
            '<span class="hl-value">code</span>' =&gt; <span class="hl-variable">$code</span>,
        ]);
    }
}
</pre>
</div>
<p>First things first, I choose a large font. My brain can only read so many characters per second, so I don’t need to try and fit as much code as possible on screen, at all times.</p>
<div class="fonts-02">
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">CodeController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-keyword">private</span> <span class="hl-type">MarkdownConverter</span> <span class="hl-property">$markdown</span></span>) {}

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">string</span> $slug</span>)
    {
        <span class="hl-variable">$code</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">markdown</span>-&gt;<span class="hl-property">convert</span>(<span class="hl-property">file_get_contents</span>(<span class="hl-property">__DIR__</span> . &quot;<span class="hl-value">/code/{$slug}.md</span>&quot;))-&gt;<span class="hl-property">getContent</span>();

        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">code</span>', [
            '<span class="hl-value">code</span>' =&gt; <span class="hl-variable">$code</span>,
        ]);
    }
}
</pre>
</div>
<p>I choose a font that’s pleasant to read, modern fonts suit me better than the ones that originated back in the 80s or 90s.</p>
<div class="fonts-03">
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">CodeController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-keyword">private</span> <span class="hl-type">MarkdownConverter</span> <span class="hl-property">$markdown</span></span>) {}

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">string</span> $slug</span>)
    {
        <span class="hl-variable">$code</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">markdown</span>-&gt;<span class="hl-property">convert</span>(<span class="hl-property">file_get_contents</span>(<span class="hl-property">__DIR__</span> . &quot;<span class="hl-value">/code/{$slug}.md</span>&quot;))-&gt;<span class="hl-property">getContent</span>();

        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">code</span>', [
            '<span class="hl-value">code</span>' =&gt; <span class="hl-variable">$code</span>,
        ]);
    }
}
</pre>
</div>
<p>I increase the line height, because it gives my code some room to breathe, and makes it even easier to read.</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">CodeController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-keyword">private</span> <span class="hl-type">MarkdownConverter</span> <span class="hl-property">$markdown</span></span>) {}

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">string</span> $slug</span>)
    {
        <span class="hl-variable">$code</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">markdown</span>-&gt;<span class="hl-property">convert</span>(<span class="hl-property">file_get_contents</span>(<span class="hl-property">__DIR__</span> . &quot;<span class="hl-value">/code/{$slug}.md</span>&quot;))-&gt;<span class="hl-property">getContent</span>();

        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">code</span>', [
            '<span class="hl-value">code</span>' =&gt; <span class="hl-variable">$code</span>,
        ]);
    }
}
</pre>
<p>Finally, I make sure that my code isn’t too wide. The less I need to move my eyes from left to right, the easier it is.</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">CodeController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">MarkdownConverter</span> <span class="hl-property">$markdown</span>,
    </span>) {}

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">string</span> $slug</span>)
    {
        <span class="hl-variable">$path</span> = <span class="hl-property">file_get_contents</span>(<span class="hl-property">__DIR__</span> . &quot;<span class="hl-value">/code/{$slug}.md</span>&quot;);
        
        <span class="hl-variable">$code</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">markdown</span>
            -&gt;<span class="hl-property">convert</span>(<span class="hl-variable">$path</span>)
            -&gt;<span class="hl-property">getContent</span>();

        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">code</span>', [
            '<span class="hl-value">code</span>' =&gt; <span class="hl-variable">$code</span>,
        ]);
    }
}
</pre>
<p>Looking at typography guidelines, the maximum advised length is somewhere between 60 and 80 characters. I think somewhere between 80 and 100 works well, because code also includes lots of tabs.</p>
<p>Have you considered typography when programming? Give it a try, it’ll make a lasting impression.</p>
<p><iframe width="560" height="422" src="https://www.youtube.com/embed/1UxQX00BZug" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
 ]]></summary>

                <updated>2023-01-28T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ My top-10 favourite functions in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/my-10-favourite-php-functions"/>

                <id>https://www.stitcher.io/blog/my-10-favourite-php-functions</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>More than once, I've been amazed by what's actually built-into PHP. Here are some of my personal favourite functions.</p>
<h2 id="levenshtein"><a href="#levenshtein" class="heading-anchor">#</a> Levenshtein</h2>
<p>"Levenshtein" is the name of an algorithm to determine the difference — aka "distance" — between two strings. The name comes — unsurprisingly — from its inventor: Vladimir Levenshtein.</p>
<p>It's a pretty cool function to determine how similar two related words or phrases are. For example: passing in <code>&quot;PHP is awesome&quot;</code> twice, will result in a "distance" of <code>0</code>:</p>
<pre><span class="hl-property">levenshtein</span>(&quot;<span class="hl-value">PHP is awesome</span>&quot;, &quot;<span class="hl-value">PHP is awesome</span>&quot;); <span class="hl-comment">// 0</span>
</pre>
<p>However, passing in two different phrases will result in a larger distance:</p>
<pre><span class="hl-property">levenshtein</span>(&quot;<span class="hl-value">Dark colour schemes</span>&quot;, &quot;<span class="hl-value">are awesome</span>&quot;); <span class="hl-comment">// 13</span>
</pre>
<p>Unsurprisingly, given how incompatible above two statements are 😉</p>
<h2 id="easter-dates"><a href="#easter-dates" class="heading-anchor">#</a> Easter dates</h2>
<p>PHP has — believe it or not — a built-in function to determine the date of Easter for any given year. Given that Easter's date is determined by
"the <strong>first Sunday</strong> after <strong>the full Moon</strong> that occurs on or <strong>after the spring equinox</strong>", I'm in awe of PHP being able to calculate it for me.</p>
<p>Or maybe it simply is hard coded?</p>
<pre><span class="hl-property">date</span>('<span class="hl-value">Y-m-d</span>', <span class="hl-property">easter_date</span>(2023)); <span class="hl-comment">// 2023-04-08</span>
</pre>
<h2 id="forks"><a href="#forks" class="heading-anchor">#</a> Forks</h2>
<p>Did you know PHP can be async? CLI versions of PHP have access to the <code>pcntl</code> functions, including the <code>pcntl_fork</code> function. This function is basically a wrapper for creating process forks, allowing one PHP process to spawn and manage several!</p>
<p>Here's a simple example using sockets to create an async child process in PHP:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">async</span>(<span class="hl-injection"><span class="hl-type">Process</span> $process</span>): <span class="hl-type">Process</span> {
    <span class="hl-property">socket_create_pair</span>(<span class="hl-property">AF_UNIX</span>, <span class="hl-property">SOCK_STREAM</span>, 0, <span class="hl-variable">$sockets</span>);
    [<span class="hl-variable">$parentSocket</span>, <span class="hl-variable">$childSocket</span>] = <span class="hl-variable">$sockets</span>;

    <span class="hl-keyword">if</span> ((<span class="hl-variable">$pid</span> = <span class="hl-property">pcntl_fork</span>()) == 0) {
        <span class="hl-property">socket_close</span>(<span class="hl-variable">$childSocket</span>);
        <span class="hl-property">socket_write</span>(<span class="hl-variable">$parentSocket</span>, <span class="hl-property">serialize</span>(<span class="hl-variable">$process</span>-&gt;<span class="hl-property">execute</span>()));
        <span class="hl-property">socket_close</span>(<span class="hl-variable">$parentSocket</span>);
        <span class="hl-keyword">exit</span>;
    }

    <span class="hl-property">socket_close</span>(<span class="hl-variable">$parentSocket</span>);

    <span class="hl-keyword">return</span> <span class="hl-variable">$process</span>
        -&gt;<span class="hl-property">setStartTime</span>(<span class="hl-property">time</span>())
        -&gt;<span class="hl-property">setPid</span>(<span class="hl-variable">$pid</span>)
        -&gt;<span class="hl-property">setSocket</span>(<span class="hl-variable">$childSocket</span>);
}
</pre>
<p>I actually wrote a little package that wraps everything in an easy-to-use API: <a href="https://github.com/spatie/async">spatie/async</a>.</p>
<h2 id="metaphone?"><a href="#metaphone?" class="heading-anchor">#</a> Metaphone?</h2>
<p>Similar to <code>levenshtein</code>, <code>methaphone</code> can generate a phonetic representation of a given string:</p>
<pre><span class="hl-property">metaphone</span>(&quot;<span class="hl-value">Light color schemes!</span>&quot;); <span class="hl-comment">// LFTKLRSXMS</span>
<span class="hl-property">metaphone</span>(&quot;<span class="hl-value">Light colour schemes!</span>&quot;); <span class="hl-comment">// LFTKLRSXMS</span>
</pre>
<h2 id="built-in-dns"><a href="#built-in-dns" class="heading-anchor">#</a> Built-in DNS</h2>
<p>PHP understands DNS, apparently. It has a built-in function called <code>dns_get_record</code>, which does as its name implies: it gets a DNS record.</p>
<pre><span class="hl-property">dns_get_record</span>(&quot;<span class="hl-value">stitcher.io</span>&quot;);

{
    [&quot;<span class="hl-value">host</span>&quot;] =&gt; &quot;<span class="hl-value">stitcher.io</span>&quot;
    [&quot;<span class="hl-value">class</span>&quot;] =&gt; &quot;<span class="hl-property">IN</span>&quot;
    [&quot;<span class="hl-value">ttl</span>&quot;] =&gt; 539
    [&quot;<span class="hl-value">type</span>&quot;] =&gt; &quot;<span class="hl-property">NS</span>&quot;
    [&quot;<span class="hl-value">target</span>&quot;] =&gt; &quot;<span class="hl-value">ns1.ichtushosting.com</span>&quot;
}

<span class="hl-comment">// …</span>
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="recursive-array-merging"><a href="#recursive-array-merging" class="heading-anchor">#</a> Recursive array merging</h2>
<p>I mainly wanted to include <code>array_merge_recursive</code> because, for a long time, I misunderstood what it did. I used to think you'd have to use it for merging multidimensional arrays, but that's not true!</p>
<p>It might be better to let <a href="/blog/merging-multidimensional-arrays-in-php">past-me explain it</a> but, in summary, it works like this:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">key</span>' =&gt; '<span class="hl-value">original</span>'
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">key</span>' =&gt; '<span class="hl-value">override</span>'
];

<span class="hl-property">array_merge_recursive</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>);

{
    [&quot;<span class="hl-value">key</span>&quot;] =&gt; {
        &quot;<span class="hl-value">original</span>&quot;,
        &quot;<span class="hl-value">override</span>&quot;,
    }
}
</pre>
<h2 id="mail"><a href="#mail" class="heading-anchor">#</a> Mail</h2>
<p>PHP has a mail function. A function to send mail. I wouldn't use it, but it's there:</p>
<pre><span class="hl-property">mail</span>(
    string <span class="hl-variable">$to</span>,
    string <span class="hl-variable">$subject</span>,
    string <span class="hl-variable">$message</span>,
    array|string <span class="hl-variable">$additional_headers</span> = [],
    string <span class="hl-variable">$additional_params</span> = &quot;<span class="hl-value"></span>&quot;
): <span class="hl-type">bool</span>
</pre>
<h2 id="dl"><a href="#dl" class="heading-anchor">#</a> DL</h2>
<p>Apparently, there's a function in PHP that allows you to dynamically load extensions, <em>while</em> your script is running!</p>
<pre><span class="hl-keyword">if</span> (! <span class="hl-property">extension_loaded</span>('<span class="hl-value">sqlite</span>')) {
    <span class="hl-keyword">if</span> (<span class="hl-property">strtoupper</span>(<span class="hl-property">substr</span>(<span class="hl-property">PHP_OS</span>, 0, 3)) === '<span class="hl-property">WIN</span>') {
        <span class="hl-property">dl</span>('<span class="hl-value">php_sqlite.dll</span>');
    } <span class="hl-keyword">else</span> {
        <span class="hl-property">dl</span>('<span class="hl-value">sqlite.so</span>');
    }
}
</pre>
<h2 id="blob…-i-mean-glob"><a href="#blob…-i-mean-glob" class="heading-anchor">#</a> Blob… I mean glob</h2>
<p><code>glob</code> is a seriously awesome function: it finds pathnames according to a pattern. It's pretty easy to explain, but it's oh so useful:</p>
<pre><span class="hl-property">glob</span>(<span class="hl-property">__DIR__</span> . '<span class="hl-value">/content/blog/*.md</span>');
<span class="hl-property">glob</span>(<span class="hl-property">__DIR__</span> . '<span class="hl-value">/content/*/*.md</span>');

{
    /path/to/content/blog/foo.md,
    /path/to/content/other/bar.md,
    …
}
</pre>
<h2 id="sun-info"><a href="#sun-info" class="heading-anchor">#</a> Sun info</h2>
<p>Finally, PHP not only knows about Easter, it also knows about when the sun rises and sets, for any given date! It also requires a longitude and latitude, which of course makes sense because the sunrise and sunset times depend on your location:</p>
<pre><span class="hl-property">date_sun_info</span>(
    <span class="hl-property">timestamp</span>: <span class="hl-property">strtotime</span>('<span class="hl-value">2023-01-27</span>'), 
    <span class="hl-property">latitude</span>: 50.278809, 
    <span class="hl-property">longitude</span>: 4.286095,
)

{
  [&quot;<span class="hl-value">sunrise</span>&quot;] =&gt; 1674804140
  [&quot;<span class="hl-value">sunset</span>&quot;] =&gt; 1674836923
  [&quot;<span class="hl-value">transit</span>&quot;] =&gt; 1674820532
  [&quot;<span class="hl-value">civil_twilight_begin</span>&quot;] =&gt; 1674802111
  [&quot;<span class="hl-value">civil_twilight_end</span>&quot;] =&gt; 1674838952
  [&quot;<span class="hl-value">nautical_twilight_begin</span>&quot;] =&gt; 1674799738
  [&quot;<span class="hl-value">nautical_twilight_end</span>&quot;] =&gt; 1674841325
  [&quot;<span class="hl-value">astronomical_twilight_begin</span>&quot;] =&gt; 1674797441
  [&quot;<span class="hl-value">astronomical_twilight_end</span>&quot;] =&gt; 1674843622
}
</pre>
<hr />
<p>What's your favourite PHP function? Let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a>!</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2023-01-27T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Why curly brackets go on new lines ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/why-curly-brackets-go-on-new-lines"/>

                <id>https://www.stitcher.io/blog/why-curly-brackets-go-on-new-lines</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><iframe width="560" height="422" src="https://www.youtube.com/embed/763ogjW2Fk0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>This is a curly bracket, or brace: <code>{</code>.</p>
<p>It’s rarely used as a punctuation mark, but it is one of the most used symbols in programming languages, where they are used to group code and create scopes. It’s also one of the more debated topics when it comes to code styles.</p>
<p>The question is simple: should an opening brace go on a new line or not? You might think: it’s all personal preference; but I would say: it’s not.</p>
<p>Take a look at this code snippet:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">string</span> $publicDirectory, <span class="hl-type">string</span> $configurationFile, <span class="hl-type">PageParser</span> $pageParser, <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>It’s a constructor that takes a couple of arguments. So what's wrong with this code? Well first of all, you probably have to scroll sideways to read it. That's a bad thing. Scrolling requires an extra interaction with your code. You'll have to consciously search for information about the arguments of this method. That time distracts you from focusing on the application code.</p>
<p>Second, if you're into web development, you probably know that people don't read text, they scan. Usually from left to right and top to bottom. This is especially true for websites, but the same goes for reading code. Putting important information to the right makes it more difficult to find.</p>
<p>In case of this argument list, all arguments are equally important; yet a lot of useful information is pushed to that right, blurry side, where our focus isn’t by default.</p>
<p>So how do we pull useful information more to the left?</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">string</span> $publicDirectory,
                            <span class="hl-type">string</span> $configurationFile,
                            <span class="hl-type">PageParser</span> $pageParser,
                            <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>This could be the first solution you think about. But it doesn't really scale. As soon as you're refactoring a method name, the alignment breaks. Say we want to make this a static constructor instead of a normal one.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">create</span>(<span class="hl-injection"><span class="hl-type">string</span> $publicDirectory,
                            <span class="hl-type">string</span> $configurationFile,
                            <span class="hl-type">PageParser</span> $pageParser,
                            <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>See the alignment breaking?</p>
<p>Another issue is that arguments are still pushed rather far to the right; so let's take a look at another approach.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $publicDirectory, <span class="hl-type">string</span> $configurationFile,
    <span class="hl-type">PageParser</span> $pageParser, <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>The advantage here is that our alignment issue is solved. However, how will you decide how many arguments should go on one line? Will you make some styling guidelines about this? How will you enforce them? This example has four arguments, but what if it had three or five?</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $publicDirectory, <span class="hl-type">string</span> $configurationFile, 
    <span class="hl-type">string</span> $cachePath, <span class="hl-type">PageParser</span> $pageParser, 
    <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>Consistency is key. If we can find a consistent rule, we don't have to think about it anymore. And like I said before, if we don't have to think about it, there's room in our heads for more important things.</p>
<p>So let's continue our search for consistency.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $publicDirectory,
    <span class="hl-type">string</span> $configurationFile,
    <span class="hl-type">PageParser</span> $pageParser,
    <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publicDirectory</span> = <span class="hl-property">rtrim</span>(<span class="hl-variable">$publicDirectory</span>, '<span class="hl-value">/</span>');
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">configurationFile</span> = <span class="hl-variable">$configurationFile</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageParser</span> = <span class="hl-variable">$pageParser</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageRenderer</span> = <span class="hl-variable">$pageRenderer</span>;
}
</pre>
<p>By giving each argument its own line, we solve all our problems. But we also created a new one: it's now more difficult to distinguish between the argument list and the method body.</p>
<p>I can illustrate it for you. Let's replace all characters in this code with X's:</p>
<pre>XXXXXX XXXXXXXX __XXXXXXXXX(
    XXXXXX XXXXXXXXXXXXXXXX,
    XXXXXX XXXXXXXXXXXXXXXXXX,
    XXXXXXXXXX XXXXXXXXXXX,
    XXXXXXXXXXXX XXXXXXXXXXXXX) {
    XXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXX = XXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXX;
}
</pre>
<p>Can you see how difficult it becomes to spot where the argument list ends and the method body starts?</p>
<p>You might say "there's still the curly bracket on the right indicating the end". But that’s not where our focus is! We want to keep the important information to the left. How do we solve it? It turns out there is one true place where to put your curly brackets:</p>
<pre>XXXXXX XXXXXXXX __XXXXXXXXX(
    XXXXXX XXXXXXXXXXXXXXXX,
    XXXXXX XXXXXXXXXXXXXXXXXX,
    XXXXXXXXXX XXXXXXXXXXX,
    XXXXXXXXXXXX XXXXXXXXXXXXX
) {
    XXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXX = XXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXX;
}
</pre>
<p>On a new line. Placing curly brackets on new lines gives our code space to breathe. It creates a visual boundary between argument lists and method bodies, it helps us to focus on things that matter.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $publicDirectory,
    <span class="hl-type">string</span> $configurationFile,
    <span class="hl-type">PageParser</span> $pageParser,
    <span class="hl-type">PageRenderer</span> $pageRenderer
</span>) {
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publicDirectory</span> = <span class="hl-property">rtrim</span>(<span class="hl-variable">$publicDirectory</span>, '<span class="hl-value">/</span>');
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">configurationFile</span> = <span class="hl-variable">$configurationFile</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageParser</span> = <span class="hl-variable">$pageParser</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageRenderer</span> = <span class="hl-variable">$pageRenderer</span>;
}
</pre>
<p><iframe width="560" height="422" src="https://www.youtube.com/embed/763ogjW2Fk0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
 ]]></summary>

                <updated>2023-01-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Sponsors ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/sponsors"/>

                <id>https://www.stitcher.io/blog/sponsors</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Hi! I usually don't write about the financial side of managing this blog and my newsletters, and yet, here we are. I must admit it feels a little awkward, so let's just get to the point first; I'll provide some backstory if you're interested in it as well.</p>
<p>I work on stitcher.io and my newsletters solely in my free time. I used to have a large company sponsoring me for two years, but that partnership has ended. I'm now looking into other ways to get stitcher.io to break even again, and one of the options is to try out GitHub sponsors. If you're a regular reader and if my content helps you, I kindly want to ask you to consider <a href="https://github.com/sponsors/brendt/">sponsoring me on GitHub</a>.</p>
<p>Finally, if you're a company looking into dedicated ad placements on my blog or newsletters, you can <a href="mailto:brendt@stitcher.io">contact me via email</a>.</p>
<h3 id="backstory"><a href="#backstory" class="heading-anchor">#</a> Backstory</h3>
<p>I've been working on stitcher.io as a hobby project for over five years now, and I've been enjoying it tremendously. In the beginning, stitcher.io was just a static blog that I hosted on a cheap $5 digital ocean droplet (in fact, my previous employer provided it for free, thanks <a href="https://spatie.be/">Spatie</a>!).</p>
<p>Over time though, costs began to grow. I got a long-term sponsor contract, meaning I had a couple of hundred euros extra monthly income. It also meant I was now legally required to start a side business in my name, which of course, increased my monthly costs: paying an accountant, social security fees, paying taxes on that newly created income, …</p>
<p>I also started sending out a regular newsletter, meaning I had to upscale my cheap droplet, had to deal with mailing providers, etc. I managed to always break even thanks to that long-term sponsor contract, but I always knew that if they decided to pull the plug, I'd have to search for other solutions. I am still running carbon ads, but honestly, they earn too little to rely on: $50 a month on average.</p>
<p>So here we are: I've got a monthly cost of around 250 euros for hosting, mailing, accounting, and software, which doesn't take into account any yearly or biyearly costs such as social security costs, taxes, domain names, and of course all the time I spend on it.</p>
<p>Now, to be clear: I don't want to turn my blog and newsletters into a profitable business. And I will keep working on it regardless of whether it's making any profit. Though, it would be nice to be able to break even again. I also did consider other ways to finance this project, like, for example, by writing a new book, but I have to admit that my family situation right now (2 kids, a third is on the way) doesn't permit such a time investment in something that I don't know will work.</p>
<p>So, long story short: stitcher.io right now is making a loss, I'm fine with it, but I would like to see it break even. I feel a bit awkward writing about it, but on the other hand: lots of other people do it, so I figured I'd give it a chance. If you benefit from my work and want to help out on a one-time or recurring basis, you can check out my <a href="https://aggregate.stitcher.io/links/27b1f2b4-2cde-4e8f-8857-491bd3bccee4">GitHub Sponsors page</a>. If you're a company looking into dedicated ad placements on my blog or newsletters, you can <a href="mailto:brendt@stitcher.io">contact me via email</a>.</p>
<p>Thanks!</p>
 ]]></summary>

                <updated>2023-01-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Tabs are better ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/tabs-are-better"/>

                <id>https://www.stitcher.io/blog/tabs-are-better</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><iframe width="560" height="422" src="https://www.youtube.com/embed/w5sPf2fhnxE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>Do you want to know something dangerous?</p>
<p>Habits.</p>
<p>Not the kind where you practise long and hard to make something a habit. No, I’m talking about the kind where you’ve taught yourself something without noticing. The kind of habit that has been “there” for years, but you can’t remember how it came to be.</p>
<p>I’m not impeccable myself. I have several such habits, and I even have a couple that I know are wrong and should be changed.</p>
<p>For example: I use spaces instead of tabs for indentation.</p>
<p>We could talk about preference all day, but in the end we should ask: what are the rational arguments for tabs and spaces?</p>
<p>For tabs, there’s one big argument: accessibility. First and foremost, the size of a tab is configurable, it doesn’t have to be a fixed width of x spaces. Say there are two visually impaired people working on the same codebase. One person has to use a really large font size, so their tab length should be shorter than the default; and the other one prefers much larger tabs on a very wide monitor so that the difference between nested levels of code is more clear. Just like colour schemes or fonts, each developer can choose what style fits them best.</p>
<p>On top of that: blind people also code. They often use braille displays. These displays show a fixed number of characters, and every space wastes one. Say you’ve got 4 spaces per indentation level, and want to read something that’s nested 3 levels deep; then we’re talking about 12 braille characters being wasted on an already limited display. Compare that to only three when you’d use tabs.</p>
<p>But let’s not jump to early conclusions and look at the rational arguments for using spaces as well: Someone decided it would be the best. That’s it. “Consistency” is often coined as an argument because different editors might show different tab lengths, and some programmers… don’t like that?</p>
<p>A huge part of the programming community — including myself — has gotten used to spaces. Not because there are any good arguments for them, but because it has grown into a habit — a habit so big that popular code styles force users to write spaces, without any good reason.</p>
<p>So maybe we should rethink that habit? I would say that accessibility and writing more inclusive code is a very good argument. But unfortunately, as we all know: breaking habits is hard.</p>
<p><iframe width="560" height="422" src="https://www.youtube.com/embed/w5sPf2fhnxE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
 ]]></summary>

                <updated>2023-01-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP in 2023 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-in-2023"/>

                <id>https://www.stitcher.io/blog/php-in-2023</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>From its humble beginnings as a personal project in the mid-90s, PHP has grown to become one of the most popular languages for web development, powering everything from small blogs to large enterprise applications.</p>
<iframe width="560" height="420" src="https://www.youtube.com/embed/ZDZDvMB-O74" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>It's a language that has seen an astonishing transformation over the course of almost three decades. Even within the last 10 years, PHP has transformed in ways we couldn't imagine.</p>
<p>Every year, I write a post about the current state of PHP, where I look back and forward. Let's begin!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="the-php-foundation"><a href="#the-php-foundation" class="heading-anchor">#</a> The PHP Foundation</h2>
<p>I usually start these posts with a summary of the latest PHP version, but this time I want focus on the PHP Foundation first. It's been a little over a year since the foundation was created: a collective of 10 volunteers and 6 developers being paid to work on PHP, the language.</p>
<p><a href="/blog/php-in-2022">Last year</a>, I wrote this:</p>
<blockquote>
<p>I'm a little worried now that Nikita has stepped down. He's definitely not the only person capable of working on PHP's core, but he <em>did</em> a tremendous amount of work these past years with PHP 8.0 and 8.1. I hope the PHP Foundation will be up to speed soon and that there are enough core developers who have time to work on PHP next year. PHP 8.2 is <a href="https://wiki.php.net/rfc#php_82">already in development</a>, although there aren't many RFCs drafted yet.</p>
<p>I don't think 2022 will be the most mind blowing year for PHP, but rather a year of adding stability. Nothing wrong with that.</p>
</blockquote>
<p>I think it's fair to say that the Foundation has delivered. They recently published <a href="https://thephp.foundation/blog/2022/11/22/transparency-and-impact-report-2022/">their 2022 report</a>, and it shows some pretty impressive numbers:</p>
<ul>
<li>In total, <strong>$580,000</strong> was raised in 2022</li>
<li>The Foundation pays <strong>6 developers</strong> to work on PHP</li>
<li>Foundation members made <strong>almost half of all commits</strong> in php-src</li>
<li>They created <strong>8 new RFCs</strong>, only one of those RFCs didn't make it</li>
</ul>
<p>I think the Foundation is one of the best things to happen to PHP in a long time, and I hope they'll be able to improve the language even more in 2023. If you're working at a company that uses PHP, I'd highly recommend you <a href="https://thephp.foundation/">consider donating</a>.</p>
<h2 id="php-8.2"><a href="#php-8.2" class="heading-anchor">#</a> PHP 8.2</h2>
<p>Moving on to PHP 8.2. It's generally regarded as a smaller release, but nevertheless it has a bunch of nice features. Just to name a couple:</p>
<p><a href="/blog/readonly-classes-in-php-82">Readonly classes</a>:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">PostData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$author</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$createdAt</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">PostState</span> <span class="hl-property">$state</span>,
    </span>) {}
}
</pre>
<p>A brand new randomizer:</p>
<pre><span class="hl-variable">$rng</span> = <span class="hl-variable">$is_production</span>
    <span class="hl-operator">?</span> <span class="hl-keyword">new</span> <span class="hl-type">Random\Engine\Secure</span>()
    : <span class="hl-keyword">new</span> <span class="hl-type">Random\Engine\Mt19937</span>(1234);
 
<span class="hl-variable">$randomizer</span> = <span class="hl-keyword">new</span> <span class="hl-type">Random\Randomizer</span>(<span class="hl-variable">$rng</span>);

<span class="hl-variable">$randomizer</span>-&gt;<span class="hl-property">shuffleString</span>('<span class="hl-value">foobar</span>');
</pre>
<p>Standalone <code>null</code>, <code>true</code> and <code>false</code>:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">alwaysFalse</span>(): <span class="hl-keyword">false</span>
{
    <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
}
</pre>
<p>Disjunctive normal form types:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">generateSlug</span>(<span class="hl-injection"><span class="hl-type">(HasTitle&amp;HasId)|null</span> $post</span>) 
{ <span class="hl-comment">/* … */</span> }
</pre>
<p>Redacted parameters:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">connect</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $user,
    #[\SensitiveParameter] <span class="hl-type">string</span> $password
</span>) {
    <span class="hl-comment">// …</span>
}
</pre>
<p><a href="/blog/new-in-php-82">And more</a>.</p>
<p>It's kind of crazy to realise how much PHP has evolved over the years. I made a little video comparison that clearly shows the difference:</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/x9bSUo6TGgY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="the-ecosystem"><a href="#the-ecosystem" class="heading-anchor">#</a> The ecosystem</h2>
<p>Just like every year, I should mention <a href="https://packagist.org/">Packagist</a>, PHP's package manager: it now lists 361,000 packages; 60,000 more than last year:</p>
<p><a href="/resources/img/blog/php-in-2023/01.png"><img src="/resources/img/blog/php-in-2023/01.png" srcset="/resources/img/blog/php-in-2023/01-1487x625.png 1487w, /resources/img/blog/php-in-2023/01-1214x510.png 1214w, /resources/img/blog/php-in-2023/01-1717x722.png 1717w, /resources/img/blog/php-in-2023/01-1920x808.png 1920w, /resources/img/blog/php-in-2023/01-858x361.png 858w" sizes="" alt=""></img></a></p>
<p>One impressive number is the total amount of installations. Last year I mentioned this:</p>
<blockquote>
<p>Oh, by the way, just recently Packagist passed the milestone of having handled over more than 50 billion installs. Congrats Packagist!</p>
</blockquote>
<p>I just checked, and we're now at <strong>74,492,061,634 installs</strong>. That's an increase of 24 billion installs in one year, <strong>2 billion installs per month</strong>. All of that to say: the PHP ecosystem is growing a lot.</p>
<hr />
<p>Twice a year, I publish my <a href="/blog/php-version-stats-january-2023">version stats</a> post. In these posts, I analyze PHP version usage across the community based on Packagist's data. I wanted to share a graph from that post again: the timeline between 2013 and now, showing the per-version usage history.</p>
<p><a href="/resources/img/blog/version-stats/2023-jan-02.svg"><img src="/resources/img/blog/version-stats/2023-jan-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p>While it's great to see PHP 8.* usage rise steeply, there's also <strong>a big chunk of people still stuck on older, slow and insecure PHP versions</strong>. My hope for 2023 is to see those old version numbers decline even more rapidly. I wrote it like this in my version stats post:</p>
<blockquote>
<p>This data beautifully visualizes the division within the PHP community: one part is keeping up with modern PHP, while another one stays helplessly behind.</p>
</blockquote>
<p>Speaking of upgrades, I want to mention one tool in particular: <a href="https://github.com/rectorphp/rector">Rector</a>. Rector is a free automation tool that helps upgrade your PHP codebase. All it takes is a tiny amount of configuration, and it'll do a huge amount of work for you.</p>
<p>I recently used it to <a href="https://www.youtube.com/watch?v=z0Tzb6SVwr4">update</a> my community-driven content aggregator, <a href="https://aggregate.stitcher.io/">Aggregate</a> to PHP 8.2, and it was really fun and easy to use.</p>
<p>When, after publishing my version stats post, several people told me they hadn't updated yet and were stuck on PHP 7.*, I asked them why. They told me it was simply too much manual work. Interestingly enough, no one had even tried to use tools like Rector to help them…</p>
<p>I firmly believe that a "programming language" is so much more than a compiler: it's the tools and ecosystem that play an equal part in defining that "programming language", and I really think lots of people, projects and businesses would benefit if they looked into using automation tools like Rector.</p>
<hr />
<p>Since I'm talking about the ecosystem, I can't go without mentioning PHP's two largest frameworks: <a href="https://laravel.com/">Laravel</a> and <a href="https://symfony.com/">Symfony</a>.</p>
<p>Over the past years, Laravel has grown tremendously. They now employ <a href="https://laravel.com/team">8 full time developers</a> to work on the framework and its ecosystem. On top of that, JetBrains' dev survey reports that <strong><a href="https://www.jetbrains.com/lp/devecosystem-2021/php/#PHP_which-php-frameworks-and-platforms-do-you-regularly-use-if-any">67% of PHP developers work with Laravel</a></strong>.</p>
<p>While Symfony as a framework might be less popular compared to Laravel these days, it's still one of the most mature and stable frameworks within the PHP community. It's more often used for enterprise app development, but its standalone components are popular throughout the whole PHP ecosystem — Laravel also has a couple of dependencies on Symfony components. No surprise that more than a handful of Symfony packages make it into <a href="https://packagist.org/explore/popular">Packagist's top package list</a>.</p>
<p>I should also mention WordPress. I'll be honest, I have a love/hate relationship with it. As a user, WordPress is great. It's so easy to install and use, and I think it has earned every bit of its popularity over the years.
As a developer though, WordPress makes me sad. The inability to stay up to date with modern and safe PHP versions casts a shadow on the whole PHP community.</p>
<p>Right now, WordPress only has <a href="https://make.wordpress.org/core/handbook/references/php-compatibility-and-wordpress-versions/">beta support for PHP 8.0</a>. Now, to be clear: PHP 8.0 was released in 2020, and is now end of life, three years later — and WordPress doesn't yet support it…</p>
<p>Of course, there are reasons for not properly supporting newer PHP versions. Up to you to decide whether they are good or not. My personal opinion is that the decision to hold on to backwards compatibility as much as WordPress does is mostly business driven: a big part of WordPress is the commercial part, and a big part of their customer base is running old PHP versions. It's a vicious circle where both parties are holding each other back and, by extent, hold back the PHP community as a whole.</p>
<p>On the other hand, we should recognise the fact that not many software projects are able to stay as popular and relevant as WordPress after almost 20 years, so maybe their strategy about backwards compatibility is the right one?</p>
<h2 id="superset"><a href="#superset" class="heading-anchor">#</a> Superset</h2>
<p>Finally, I can't help but mention my long-term dream for PHP. I <a href="/blog/we-dont-need-runtime-type-checks">write about it</a>, I <a href="https://www.youtube.com/watch?v=kVww3uk7HMg">speak about it</a>, and I hope that one day it'll become true: a superset of PHP, <em>with</em> proper IDE and static analyser support.</p>
<p>There are a bunch of reasons why I want it to happen, you can read and hear about them if you want to; but I really hope it'll become a reality. I doubt we'll get to see a widely accepted and supported superset in 2023, but some baby steps are already being made. I'm definitely keeping a close eye on <a href="https://pxplang.org/">PXP</a>, which might take things in the right direction.</p>
<hr />
<p>With all of that being said, I hope that you'll enjoy 2023! And just in case you're new here: I'm Brent, developer advocate at JetBrains, I write and vlog about PHP; and I'd really appreciate it if you checked out <a href="https://aggregate.stitcher.io/links/6e1546fa-4650-4db0-9ca0-9f99ec27acfb">the YouTube channel</a> I've been working on lately. Take a look, and maybe consider subscribing? Thanks!</p>
<p>If you're not into videos but still want to follow me, you can <a href="https://stitcher.io/newsletter/subscribe">join 15k newsletter subscribers</a> instead, I hope to see you there!</p>
 ]]></summary>

                <updated>2023-01-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP version stats: January, 2023 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-version-stats-january-2023"/>

                <id>https://www.stitcher.io/blog/php-version-stats-january-2023</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's that time again: my biyearly summary of which PHP versions are used across the community. You can read the previous edition <a href="/blog/php-version-stats-july-2022">here</a>.</p>
<p>As always, it's important to note that I'm working with the data available to us. That means that these charts are not a 100% accurate representation of the PHP community as a whole, but they <em>are</em> an accurate representation of one of the most prominent parts of PHP: the <a href="https://packagist.org/php-statistics">packagist ecosystem</a>.</p>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<h2 id="usage-statistics"><a href="#usage-statistics" class="heading-anchor">#</a> Usage Statistics</h2>
<p>Let's start with the percentage of PHP versions being used today, and compare it to the previous three editions, note that I've omitted all versions that don't have more than 1% usage:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2021-07</td>
    <td>2022-01</td>
    <td>2022-07</td>
    <td>2023-01</td>
</tr>
<tr>
    <td>8.2</td>
    <td>0.0%</td>
    <td>0.0%</td>
    <td>0.0%</td>
    <td>4.7%</td>
</tr>
<tr>
    <td>8.1</td>
    <td>0.1%</td>
    <td>9.1%</td>
    <td>24.5%</td>
    <td>38.8%</td>
</tr>
<tr>
    <td>8.0</td>
    <td>14.7%</td>
    <td>23.9%</td>
    <td>20.6%</td>
    <td>16.2%</td>
</tr>
<tr>
    <td>7.4</td>
    <td>46.8%</td>
    <td>43.9%</td>
    <td>38.4%</td>
    <td>27.7%</td>
</tr>
<tr>
    <td>7.3</td>
    <td>19.2%</td>
    <td>12.0%</td>
    <td>8.0%</td>
    <td>5.3%</td>
</tr>
<tr>
    <td>7.2</td>
    <td>10.4%</td>
    <td>6.6%</td>
    <td>5.1%</td>
    <td>4.3%</td>
</tr>
<tr>
    <td>7.1</td>
    <td>3.8%</td>
    <td>2.4%</td>
    <td>1.9%</td>
    <td>1.8%</td>
</tr>
</table>
</div>
<p>Visualizing this data looks like this:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2023-jan-01.svg"><img src="/resources/img/blog/version-stats/2023-jan-01.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2023-jan-01.svg">Evolution of version usage</a></em></p>
<p>We can see a decent growth for PHP 8.* versions, I think that's great news! It's also great to see PHP 8.0 usage already declining: PHP 8.0 went into <a href="https://www.php.net/supported-versions.php">security fixes only mode</a> at the end of last year, and I hope to see its usage decline a lot more this year. Keep in mind that <strong>PHP 8.0 will reach end of life on November 26, 2023</strong>. So it's crucial that projects start preparing to upgrade in the coming months.</p>
<p>PHP 7.4 reached end of life last year, so at the same time it's worrying that more than 25% of projects are still using it! Let's hope to see this number decline soon.</p>
<p>This data beautifully visualizes the division within the PHP community: one part is keeping up with modern PHP, while another one stays helplessly behind. I know there are many reasons to stay behind — often driven by business requirements and constraints — but it's crucial to realise that a lot of PHP projects are in fact running insecure and slow versions in production because of it.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>Moving on to the all-time overview chart, here you can see the evolution of version usage across time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2023-jan-02.svg"><img src="/resources/img/blog/version-stats/2023-jan-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2023-jan-02.svg">All time evolution</a></em></p>
<p>Like I said: the decline of 7.4 is going too slow to my liking. Compare it to the much steeper decline of PHP 5.5 back in 2015 when PHP 7.0 was released: I would have liked to see the same happen with PHP 7.4 and have people move to PHP 8.0, but unfortunately that's not the case.</p>
<p>I feel like I'm repeating myself every year, but I really hope that people upgrade their projects sooner in the future. I'm curious to learn how this part of the PHP community can be helped. I feel that tools like <a href="https://getrector.org/">Rector</a> to automate upgrades have so much potential, if only people started using it.</p>
<h2 id="required-versions"><a href="#required-versions" class="heading-anchor">#</a> Required versions</h2>
<p>Next, I used Nikita's <a target="_blank" href="https://github.com/nikic/popular-package-analysis">popular package analyzer</a> to download the 1000 most popular composer packages. I used a little script to get their minimum required version. Here are the results:</p>
<div class="table-container">
<table>
<tr class="table-head">
    <td>Version</td>
    <td>2021-07</td>
    <td>2022-01</td>
    <td>2022-07</td>
    <td>2023-01</td>
</tr>
<tr>
    <td>8.2</td>
    <td>-</td>
    <td>-</td>
    <td>-</td>
    <td>-</td>
</tr>
<tr>
    <td>8.1</td>
    <td>-</td>
    <td>-</td>
    <td>125</td>
    <td>129</td>
</tr>
<tr>
    <td>8.0</td>
    <td>117</td>
    <td>160</td>
    <td>94</td>
    <td>103</td>
</tr>
<tr>
    <td>7.4</td>
    <td>56</td>
    <td>69</td>
    <td>86</td>
    <td>98</td>
</tr>
<tr>
    <td>7.3</td>
    <td>133</td>
    <td>116</td>
    <td>104</td>
    <td>106</td>
</tr>
<tr>
    <td>7.2</td>
    <td>142</td>
    <td>133</td>
    <td>130</td>
    <td>144</td>
</tr>
<tr>
    <td>7.1</td>
    <td>182</td>
    <td>190</td>
    <td>153</td>
    <td>159</td>
</tr>
<tr>
    <td>7.0</td>
    <td>31</td>
    <td>29</td>
    <td>29</td>
    <td>30</td>
</tr>
<tr>
    <td>5.6</td>
    <td>61</td>
    <td>49</td>
    <td>42</td>
    <td>43</td>
</tr>
<tr>
    <td>5.5</td>
    <td>43</td>
    <td>42</td>
    <td>35</td>
    <td>37</td>
</tr>
<tr>
    <td>5.4</td>
    <td>41</td>
    <td>43</td>
    <td>40</td>
    <td>40</td>
</tr>
<tr>
    <td>5.3</td>
    <td>97</td>
    <td>83</td>
    <td>77</td>
    <td>78</td>
</tr>
<tr>
    <td>5.2</td>
    <td>12</td>
    <td>10</td>
    <td>10</td>
    <td>10</td>
</tr>
</table>
</div>
<p>There are two important notes to make here.</p>
<ol>
<li>This tables shows the <strong>minimum required version</strong>. It makes sense that none of the 1000 packages already supports PHP 8.2, since it's been only here for a month.</li>
<li>If you count the numbers, you'll notice there are some differences between each year. Not every package lists a version, so not all 1000 packages can be parsed.</li>
</ol>
<br>
<p>Instead of comparing absolute numbers, it's best to plot this data into a chart for a relative comparison, so that we can see changes over time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2023-jan-03.svg"><img src="/resources/img/blog/version-stats/2023-jan-03.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2023-jan-03.svg">Minimal PHP requirement over time</a></em></p>
<p>You can see there's a <em>slight</em> increase in PHP 7.* requirements. It's a good evolution, but still very slow compared to how fast PHP is moving forward.</p>
<p>In my opinion, package authors should push more to require only supported PHP versions. I think it's the only way for PHP to keep moving forward at a decent rate, and for the community to keep up. On top of that: yearly upgrades are much easier to do than to stay on, for example, PHP 7.4 and try to make the jump directly to PHP 8.2.</p>
<p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/z0Tzb6SVwr4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</p>
<p><div class="author packagist">

    <img src="https://packagist.com/img/logo-right.svg" alt="">
    <span>
    This blog post was sponsored by <a href="https://aggregate.stitcher.io/links/3c95f238-9205-4a25-a928-1a1a5405f133">Private Packagist</a> - the private Composer repository from the creators and maintainers of Composer & Packagist.
    </span>
</div>

</p>
<p>In closing, if you take one thing away from this post, I hope it's that it's time to upgrade to at least PHP 8.1, preferably PHP 8.2. It's not as difficult as you might think, and it's <a href="/blog/a-storm-in-a-glass-of-water">definitely worth your time</a>.</p>
<p>What are your thoughts on these stats? Are you using <a href="/blog/new-in-php-82">PHP 8.2</a>? Let me know your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> and subscribe to <a href="/newsletter/subscribe">my newsletter</a> if you want to be kept up-to-date about these posts!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2023-01-11T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Upgrading to PHP 8.2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/upgrading-to-php-82"/>

                <id>https://www.stitcher.io/blog/upgrading-to-php-82</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In this video I talk you through how I upgraded <a href="https://aggregate.stitcher.io/">Aggregate</a> to PHP 8.2.</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/z0Tzb6SVwr4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 ]]></summary>

                <updated>2023-01-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ All I want for Christmas… ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/all-i-want-for-christmas"/>

                <id>https://www.stitcher.io/blog/all-i-want-for-christmas</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>Note: this post was first published as part of PHP's "<a href="https://24daysindecember.net/2022/12/01/all-i-want-for-christmas/">24 Days in December</a>" Advent event.</em></p>
<p>Let's set aside all practical concerns for a moment — it's Christmas, after all. If you could choose — freely choose: what would you change about PHP?</p>
<p>Would you want generics or the pipe operator? Maybe you'd like to see consistent function signatures or get rid of the dollar sign. Type aliases, scalar objects, autoloading for namespaced functions, improved performance, less breaking changes, more breaking changes — the list goes on.</p>
<p>But what if I told you, you had to pick one, and only one. What would it be?</p>
<p>My number one feature isn't in this list. Even worse: my number one wish for PHP will probably never happen. But like I said at the beginning: let's set aside all practical concerns. Let's dream for a moment, not because we believe all dreams come true; but because dreams, in themselves, are valuable and give hope — it <em>is</em> Christmas, after all.</p>
<hr />
<p>Let me tell you the story of another programming language. A language that, just like PHP, had been the underdog for decades. It didn't have sexy syntax, it was a poor performer, it had messy methods and confusing classes. It was… JavaScript.</p>
<p>It was a language that — legend says — was written in two weeks. Yet it grew to be the most popular programming language people had ever seen, almost by accident.</p>
<p>Indeed, for years, developers were stuck with JavaScript: it was the only option to do any kind of frontend programming at all. And despite everyone mocking poor JavaScript, there simply were no other alternatives, so they had to use it.</p>
<p>That is: until a bunch of smart people started thinking out of the box. The idea was simple: what if we don't write JavaScript anymore, but instead write a program in another language, and convert that code to JavaScript? That way our programs could still work in the browser, but we didn't have to put up with JavaScript's ugliness and quirkiness.</p>
<p>And so history was written: we compiled languages like C to a subset of JavaScript — an optimised subset that was much more performant. It was called asm.js. It allowed us to run existing game engines in the browser. We compiled JavaScript to JavaScript with Babel: newer syntax that wasn't available in browsers was "transpiled" to older JavaScript versions. Supersets like CoffeeScript came into existence. They added better and more convenient syntax.</p>
<p>More and more, the JavaScript community transformed into a host of languages, with JavaScript simply being a compilation target.</p>
<p>Sure, compiling JavaScript meant adding a build step, but it seemed like developers got used to it. First and foremost: build steps were optimised for performance, and second: you could suddenly add a lot of static functionality to your language: tasks that were performed only when compiling your program but not while running it. TypeScript was created, and static type checking became a thing. It turned out: computers were awfully good at detecting mistakes, as long as we provide them with just enough information — types.</p>
<p>And everyone marvelled at JavaScript: it grew from a small frontend scripting language to the number 1 programming language in the world.</p>
<hr />
<p>Let's talk about PHP. I've been writing it for more than a decade now. I love the PHP community, I love the ecosystem, I love how the language has managed to evolve over the years. At the same time I believe there's room for PHP to grow — lots of room. And so I dream.</p>
<p>I dream of a world where PHP follows in JavaScript footsteps. Where it becomes more than just PHP. I dream of a TypeScript for PHP: a language that's still 100% compatible with all PHP code out there, but one that adds generics and proper static type checking — without having to worry about runtime performance costs. I dream of a language that has all (or most) modern-day language features, that are compiled to plain, old, boring — but working — PHP.</p>
<p>But dreams seldom come true.</p>
<p>Someone once said: "For JavaScript to become as popular as it is today, there had to be two things: it had to suck, and it had to be the only viable option available". And here's the thing: unlike JavaScript, PHP isn't the <em>only</em> option available for backend programming. I also dare to say that it's way better than JavaScript back in the day. These two main components that were needed for JavaScript to grow into something more than itself, aren't equally present in PHP.</p>
<p>And that's ok. It means my dream is probably unrealistic, but it also means something much more important.</p>
<p>My realisation recently is that PHP is already awesome. People are already building great things with it. Sure, maybe PHP is boring compared to the latest and greatest programming languages, and sure you might need to use another language if you're building something for those 0.1% of edge cases that need insane performance. My dream of a superset of PHP might be one of many approaches, but it sure isn't the only viable path forward.</p>
<p>Even without that dream of mine: PHP is doing great. It's not because of how its designed, it's not because of its syntax. It's not because of its top-notch performance and it's not because of its incredible type system. It's because people like <em>you</em> are building amazing things with it. Whether you're using PHP 8.2 or not; whether your running it serverless or asynchronous or not; whether you're writing OOP, FP, DDD, ES, CQRS, Serverless or whatever term you want to throw at it — <em>you</em> are building awesome things. It turns out a language is rarely the bottleneck, because it's merely a tool. But "PHP" is so much more than just a language, it's so much more than just a tool. That's because of <em>you</em>.</p>
<p>Thank you for being part of what makes PHP great. Happy holidays.</p>
 ]]></summary>

                <updated>2023-01-03T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ You cannot find me on Mastodon ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/you-cannot-find-me-on-mastodon"/>

                <id>https://www.stitcher.io/blog/you-cannot-find-me-on-mastodon</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I started this blog originally on Medium — did you know that? That was 7 years ago. I managed to build a small audience over there — it felt large at the time but numbers are of course relative. Medium changed a lot in that period though, and while I can't remember the final trigger, at one point I decided I wanted to take full control and ownership of my content. And so I created a static blog — nothing fancy, but it worked for me.</p>
<p>I've never felt any regrets for that decision. On the contrary: I believe that if I stuck with Medium, I would have never been able to grow my blog to where it is today. It's because of my blog that I was able to join my current and previous job — it's safe to say this has been life defining for me and my family. Full control meant taking ownership and responsibility, I started caring for my content in another way and that paid off.</p>
<p>It's been five years since I took ownership of my content, but I didn't do the same with my audience. My audience is spread across different places on the web (Reddit, RSS, other blogs, Twitter, HackerNews, …), with Twitter being the largest by far.</p>
<p>With all the Twitter drama these past weeks, I realised how dependent I am — once again — on a platform that's totally out of my control.</p>
<p>I've managed to build a following of 15k people on Twitter. That's small for many people but it's larger than what I imagined a couple of years ago. And while I have 15k followers (that's maybe 1k of real people actually seeing my tweets), if Twitter shuts down tomorrow, those people are gone. To me that would mean all the time and effort I put into my Twitter audience will simply be… gone.</p>
<p>Now, I'm not making any predictions about Twitter's future, and I don't believe anyone talking about it actually has a clue. But, I also won't move to the next platform anymore. At least not for building an audience like I did on Twitter. Instead, I've managed to build a decent <a href="https://stitcher.io/newsletter/subscribe">newsletter</a> audience of 17k people by now. That are around 5k actual readers, despite double opt-in (email is weird 🙄). But at least it's in my control: my newsletter is <a href="https://mailcoach.app/">self hosted</a> and I keep full control over my audience. No one can pull the plug but me.</p>
<p>Now the Mastodon fans will tell me how Mastodon is decentralized and safe and how they are in full control, but that's simply not true. You're not owning your Mastodon servers — at least not the ones that are actually large enough to matter: <a href="https://phpc.social/about">phpc.social</a> for example (that's where my audience is), is hosted on <a href="https://masto.host/">masto.host</a>.</p>
<p>Remember how WhatsApp was considered the "safe and encrypted messaging app" once? Remember how everyone and their mother encouraged you to migrate to Signal or Telegram a couple of years later, which also turned out to have <a href="https://www.theverge.com/22249391/signal-app-abuse-messaging-employees-violence-misinformation">privacy</a> and <a href="https://nordvpn.com/blog/is-telegram-safe/">security</a> flaws on their own? You're never in control.</p>
<p>I'm not saying I won't use any of those platforms — if Twitter goes down I probably will join the PHP community on Mastodon. But I won't build and rely on it like I did with Twitter. I'll take full control of my audience from this point forward, meaning you can either follow me via <a href="https://stitcher.io/newsletter/subscribe">my newsletter</a> or via <a href="https://stitcher.io/rss">RSS</a>, whatever works best for you.</p>
 ]]></summary>

                <updated>2022-11-19T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What&#039;s new in PHP 8.2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-in-php-82"/>

                <id>https://www.stitcher.io/blog/new-in-php-82</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><strong>PHP 8.2 is released on <a href="https://wiki.php.net/todo/php82">December 8, 2022</a>.</strong> In this post, we'll go through all features, performance improvements, changes and deprecations one by one.</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/KBcZIY_v9VQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h3 id="readonly-classes-rfc"><a href="#readonly-classes-rfc" class="heading-anchor">#</a> Readonly classes <small><a target="_blank" href="https://wiki.php.net/rfc/readonly_classes">RFC</a></small></h3>
<p>Readonly properties were <a href="/blog/php-81-readonly-properties">introduced in PHP 8.1</a>. This RFC builds on top of them, and adds syntactic sugar to make all class properties readonly at once. Instead of writing this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>, 
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">Author</span> <span class="hl-property">$author</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">DateTime</span> <span class="hl-property">$publishedAt</span>,
    </span>) {}
}
</pre>
<p>You can now write this:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>, 
        <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$author</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTime</span> <span class="hl-property">$publishedAt</span>,
    </span>) {}
}
</pre>
<p>Functionally, making a class readonly is entirely the same as making every property readonly; but it will also prevent dynamic properties being added on a class:</p>
<pre><span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(<span class="hl-comment">/* … */</span>);

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">unknown</span> = '<span class="hl-value">wrong</span>';

<span class="hl-type">Uncaught</span> <span class="hl-property">Error</span>: Cannot create dynamic property <span class="hl-type">Post</span>::<span class="hl-property">$unknown</span>
</pre>
<p>Note that you can only extend from readonly classes if the child class is readonly as well.</p>
<p>PHP has changed quite a lot, and readonly classes are a welcome addition. You can take a look at my video about PHP's evolution if you want to as well:</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/x9bSUo6TGgY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<hr />
<h3 id="deprecate-dynamic-properties-rfc"><a href="#deprecate-dynamic-properties-rfc" class="heading-anchor">#</a> Deprecate dynamic properties <small><a target="_blank" href="https://wiki.php.net/rfc/deprecate_dynamic_properties">RFC</a></small></h3>
<p>I'd say this is a change for the better, but it will hurt a little bit. Dynamic properties are deprecated in PHP 8.2, and will throw an <code>ErrorException</code> in PHP 9.0:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>;
}

<span class="hl-comment">// …</span>

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>';
</pre>
<p>Keep in mind that classes implementing <code>__get</code> and <code>__set</code> will still work as intended:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$properties</span> = [];
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__set</span>(<span class="hl-injection"><span class="hl-type">string</span> $name, <span class="hl-type">mixed</span> $value</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">properties</span>[<span class="hl-variable">$name</span>] = <span class="hl-variable">$value</span>;
    }
}

<span class="hl-comment">// …</span>

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>';
</pre>
<p>If you want to learn more about why deprecations are useful and how to deal with them, you can read this followup post on <a href="/blog/deprecated-dynamic-properties-in-php-82">how to deal with deprecations</a>, or you can check out my vlog:</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/9Kox9HQnLUg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<hr />
<h3 id="new-random-extension-rfc"><a href="#new-random-extension-rfc" class="heading-anchor">#</a> New random extension <small><a href="https://wiki.php.net/rfc/rng_extension">RFC</a></small></h3>
<p>PHP 8.2 adds a new random number generator that fixes a lot of problems with the previous one: it’s more performant, more secure, it’s easier to maintain, and doesn’t rely on global state; eliminating a range of difficult to detect bugs when using PHP’s random functions.</p>
<p>There’s a new class called <code>Randomizer</code>, which accepts a randomizer engine. Now you can change that engine, depending on your needs. For example, to differentiate between a production and testing environment.</p>
<pre><span class="hl-variable">$rng</span> = <span class="hl-variable">$is_production</span>
    <span class="hl-operator">?</span> <span class="hl-keyword">new</span> <span class="hl-type">Random\Engine\Secure</span>()
    : <span class="hl-keyword">new</span> <span class="hl-type">Random\Engine\Mt19937</span>(1234);
 
<span class="hl-variable">$randomizer</span> = <span class="hl-keyword">new</span> <span class="hl-type">Random\Randomizer</span>(<span class="hl-variable">$rng</span>);
<span class="hl-variable">$randomizer</span>-&gt;<span class="hl-property">shuffleString</span>('<span class="hl-value">foobar</span>');
</pre>
<hr />
<h3 id="null,--true,-and-false-as-standalone-types-rfc"><a href="#null,--true,-and-false-as-standalone-types-rfc" class="heading-anchor">#</a> <code>null</code>,  <code>true</code>, and <code>false</code> as standalone types <small><a target="_blank" href="https://wiki.php.net/rfc/null-false-standalone-types">RFC</a></small></h3>
<p>PHP 8.2 adds three new types — or something that looks like it. We'll avoid going down the rabbit hole of <a href="https://stitcher.io/blog/liskov-and-type-safety">type safety</a> in this post, but technically <code>null</code>, <code>true</code>, and <code>false</code> could be considered valid types on their own. Common examples are PHP's built-in functions, where <code>false</code> is used as the return type for when an error occurs. For example in <code>file_get_contents</code>:</p>
<pre><span class="hl-property">file_get_contents</span>(<span class="hl-comment">/* … */</span>): <span class="hl-type">string|false</span>
</pre>
<p>Before PHP 8.2, you could already use <code>false</code> together with other types as a union; but now it can be used as a standalone type as well:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">alwaysFalse</span>(): <span class="hl-keyword">false</span>
{
    <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
}
</pre>
<p>The same now also goes for <code>true</code> and <code>null</code>.</p>
<hr />
<h3 id="disjunctive-normal-form-types-rfc"><a href="#disjunctive-normal-form-types-rfc" class="heading-anchor">#</a> Disjunctive Normal Form Types <small><a href="https://wiki.php.net/rfc/dnf_types">RFC</a></small></h3>
<p>DNF types allow us to combine <a href="/blog/new-in-php-8#union-types-rfc">union</a> and <a href="/blog/new-in-php-81#pure-intersection-types-rfc">intersection</a> types, following a strict rule: when combining union and intersection types, intersection types must be grouped with brackets.
In practice, that looks like this:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">generateSlug</span>(<span class="hl-injection"><span class="hl-type">(HasTitle&amp;HasId)|null</span> $post</span>) 
{
    <span class="hl-keyword">if</span> (<span class="hl-variable">$post</span> === <span class="hl-keyword">null</span>) {
        <span class="hl-keyword">return</span> '<span class="hl-value"></span>';
    }

    <span class="hl-keyword">return</span> 
        <span class="hl-property">strtolower</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">getTitle</span>()) 
        . <span class="hl-variable">$post</span>-&gt;<span class="hl-property">getId</span>();
}
</pre>
<p>In this case, <code>(HasTitle&amp;HasId)|null</code> is the DNF type.</p>
<p>It's a nice addition, especially since it means that we can now have nullable intersection types, which is probably the most important use case for this feature.</p>
<hr />
<h3 id="constants-in-traits-rfc"><a href="#constants-in-traits-rfc" class="heading-anchor">#</a> Constants in traits <small><a href="https://wiki.php.net/rfc/constants_in_traits">RFC</a></small></h3>
<p>You can now use constants in traits:</p>
<pre><span class="hl-keyword">trait</span> <span class="hl-type">Foo</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">CONSTANT</span> = 1;
 
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>(): <span class="hl-type">int</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-type">self</span>::<span class="hl-property">CONSTANT</span>;
    }
}
</pre>
<p>You won't be able to access the constant via the trait's name, either from outside the trait, or from inside it.</p>
<pre><span class="hl-keyword">trait</span> <span class="hl-type">Foo</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">CONSTANT</span> = 1;
 
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>(): <span class="hl-type">int</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-type">Foo</span>::<span class="hl-property">CONSTANT</span>;
    }
}

<span class="hl-type">Foo</span>::<span class="hl-property">CONSTANT</span>;
</pre>
<p>You can however access the constant via the class that uses the trait, given that it's public:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyClass</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">Foo</span>;
}

<span class="hl-type">MyClass</span>::<span class="hl-property">CONSTANT</span>; <span class="hl-comment">// 1</span>
</pre>
<hr />
<h3 id="redact-parameters-in-back-traces-rfc"><a href="#redact-parameters-in-back-traces-rfc" class="heading-anchor">#</a> Redact parameters in back traces <small><a target="_blank" href="https://wiki.php.net/rfc/redact_parameters_in_back_traces">RFC</a></small></h3>
<p>A common practice in any codebase is to send production errors to a service that keeps track of them, and will notify developers when something goes wrong. This practice often involves sending stack traces over the wire to a third party service. There are cases however where those stack traces can include sensitive information such as environment variables, passwords or usernames.</p>
<p>PHP 8.2 allows you to mark such "sensitive parameters" with an attribute, so that you don't need to worry about them being listed in your stack traces when something goes wrong.
Here's an example from the RFC:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">login</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $user,
    #[\SensitiveParameter] <span class="hl-type">string</span> $password
</span>) {
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">Exception</span>('<span class="hl-value">Error</span>');
}
 
<span class="hl-property">login</span>('<span class="hl-value">root</span>', '<span class="hl-value">root</span>');
 
<span class="hl-comment">//Fatal error: Uncaught Exception: Error in login.php:8</span>
<span class="hl-comment">//Stack trace:</span>
<span class="hl-comment">//#0 login.php(11): login('root', Object(SensitiveParameterValue))</span>
<span class="hl-comment">//#1 {main}</span>
<span class="hl-comment">//  thrown in login.php on line 8</span>
</pre>
<hr />
<h3 id="fetch-properties-of-enums-in-const-expressions-rfc"><a href="#fetch-properties-of-enums-in-const-expressions-rfc" class="heading-anchor">#</a> Fetch properties of enums in const expressions <small><a href="https://wiki.php.net/rfc/fetch_property_in_const_expressions">RFC</a></small></h3>
<p>From the RFC:</p>
<blockquote>
<p>This RFC proposes to allow the use of <code>-&gt;</code>/<code>?-&gt;</code> to fetch properties of enums in constant expressions. The primary motivation for this change is to allow fetching the name and value properties in places where enum objects aren't allowed, like array keys</p>
</blockquote>
<p>That means that the following code is now valid:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">A</span>: <span class="hl-type">string</span> 
{
    <span class="hl-keyword">case</span> <span class="hl-property">B</span> = '<span class="hl-property">B</span>';
    
    <span class="hl-keyword">const</span> <span class="hl-property">C</span> = [<span class="hl-type">self</span>::<span class="hl-property">B</span>-&gt;<span class="hl-property">value</span> =&gt; <span class="hl-type">self</span>::<span class="hl-property">B</span>];
}
</pre>
<hr />
<h3 id="return-type-changes-for-datetime::createfromimmutable()-and-datetimeimmutable::createfrommutable()-breaking"><a href="#return-type-changes-for-datetime::createfromimmutable()-and-datetimeimmutable::createfrommutable()-breaking" class="heading-anchor">#</a> Return type changes for <code>DateTime::createFromImmutable()</code> and <code>DateTimeImmutable::createFromMutable()</code> <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING#L22-L26">breaking</a></small></h3>
<p>Previously, these methods looked like this:</p>
<pre><span class="hl-type">DateTime</span>::<span class="hl-property">createFromImmutable</span>(): <span class="hl-type">DateTime</span>
<span class="hl-type">DateTimeImmutable</span>::<span class="hl-property">createFromMutable</span>(): <span class="hl-type">DateTimeImmutable</span>
</pre>
<p>In PHP 8.2 those method signatures are changed like so:</p>
<pre><span class="hl-type">DateTime</span>::<span class="hl-property">createFromImmutable</span>(): <span class="hl-keyword">static</span>
<span class="hl-type">DateTimeImmutable</span>::<span class="hl-property">createFromMutable</span>(): <span class="hl-keyword">static</span>
</pre>
<p>This change makes a lot more sense, as it improves static insight possibilities for classes extending from <code>DateTime</code> and <code>DateTimeImmutable</code>. However, technically, this is a breaking change that might affect custom implementations that extend from either of those two classes.</p>
<hr />
<h3 id="utf8_encode()-and-utf8_decode()-deprecations-rfc"><a href="#utf8_encode()-and-utf8_decode()-deprecations-rfc" class="heading-anchor">#</a> <code>utf8_encode()</code> and <code>utf8_decode()</code> deprecations <small><a href="https://wiki.php.net/rfc/remove_utf8_decode_and_utf8_encode">RFC</a></small></h3>
<p>In PHP 8.2, using either <code>utf8_encode()</code> or <code>utf8_decode()</code> will trigger these deprecation notices:</p>
<pre>Deprecated: Function utf8_encode() is deprecated
Deprecated: Function utf8_decode() is deprecated
</pre>
<p>The RFC argues that these functions have a inaccurate name that often causes confusion: these functions only convert between <code>ISO-8859-1</code> and <code>UTF-8</code>, while the function name suggest a more broader use. There's a more detailed explanation about the reasoning in the <a href="https://wiki.php.net/rfc/remove_utf8_decode_and_utf8_encode">RFC</a>.</p>
<p>The alternative? The RFC suggests using <code>mb_convert_encoding()</code> instead.</p>
<hr />
<h3 id="locale-insensitive-strtolower()-and-strtoupper()-breaking-rfc"><a href="#locale-insensitive-strtolower()-and-strtoupper()-breaking-rfc" class="heading-anchor">#</a> Locale-insensitive <code>strtolower()</code> and <code>strtoupper()</code> <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING#L41-L47">breaking</a></small> <small><a target="_blank" href="https://wiki.php.net/rfc/strtolower-ascii">RFC</a></small></h3>
<p>Both <code>strtolower()</code> and <code>strtoupper()</code> are no longer locale-sensitive. You can use <code>mb_strtolower()</code> if you want localized case conversion.</p>
<hr />
<h3 id="signature-changes-to-several-spl-methods-breaking"><a href="#signature-changes-to-several-spl-methods-breaking" class="heading-anchor">#</a> Signature changes to several SPL methods <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING#L49-L60">breaking</a></small></h3>
<p>Several methods of SPL classes have been changed to properly enforce their correct type signature:</p>
<pre><span class="hl-type">SplFileInfo</span>::<span class="hl-property">_bad_state_ex</span>()
<span class="hl-type">SplFileObject</span>::<span class="hl-property">getCsvControl</span>()
<span class="hl-type">SplFileObject</span>::<span class="hl-property">fflush</span>()
<span class="hl-type">SplFileObject</span>::<span class="hl-property">ftell</span>()
<span class="hl-type">SplFileObject</span>::<span class="hl-property">fgetc</span>()
<span class="hl-type">SplFileObject</span>::<span class="hl-property">fpassthru</span>()
<span class="hl-type">SplFileObject</span>::<span class="hl-property">hasChildren</span>()
<span class="hl-type">SplFileObject</span>::<span class="hl-property">getChildren</span>()
</pre>
<hr />
<h3 id="new-n-modifier-in-pcre-upgrading"><a href="#new-n-modifier-in-pcre-upgrading" class="heading-anchor">#</a> New <code>n</code> modifier in PCRE <small><a href="https://github.com/php/php-src/blob/master/UPGRADING#L95-L100">upgrading</a></small></h3>
<p>You can now use the <code>n</code> modifier (<code>NO_AUTO_CAPTURE</code>) in <code>pcre*</code> functions.</p>
<hr />
<h3 id="odbc-username-and-password-escaping-breaking"><a href="#odbc-username-and-password-escaping-breaking" class="heading-anchor">#</a> ODBC username and password escaping <small class="breaking"><a href="https://github.com/php/php-src/blob/master/UPGRADING#L28-L39">breaking</a></small></h3>
<p>From the <a href="https://github.com/php/php-src/blob/master/UPGRADING#L28-L39">UPGRADING</a> guide:</p>
<blockquote>
<p>The <code>ODBC</code> extension now escapes the username and password for the case when
both a connection string and username/password are passed, and the string
must be appended to.</p>
</blockquote>
<p>The same applies to <code>PDO_ODBC</code>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<hr />
<h3 id="deprecate-${}-string-interpolation-rfc"><a href="#deprecate-${}-string-interpolation-rfc" class="heading-anchor">#</a> Deprecate <code>${}</code> string interpolation <small><a target="_blank" href="https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation">RFC</a></small></h3>
<p>PHP has several ways of embedding variables in strings. This RFC deprecates two ways of doing so, since they are rarely used, and often lead to confusion:</p>
<pre>&quot;<span class="hl-value">Hello ${world}</span>&quot;;
<span class="hl-comment">//Deprecated: Using ${} in strings is deprecated</span>
 
&quot;<span class="hl-value">Hello ${(world)}</span>&quot;;
<span class="hl-comment">//Deprecated: Using ${} (variable variables) in strings is deprecated</span>
</pre>
<p>To be clear: the two popular ways of string interpolation still work:</p>
<pre>&quot;<span class="hl-value">Hello {$world}</span>&quot;;
&quot;<span class="hl-value">Hello $world</span>&quot;;
</pre>
<hr />
<h3 id="deprecate-partially-supported-callables-rfc"><a href="#deprecate-partially-supported-callables-rfc" class="heading-anchor">#</a> Deprecate partially supported callables <small><a target="_blank" href="https://wiki.php.net/rfc/deprecate_partially_supported_callables">RFC</a></small></h3>
<p>Another change, although one with a slightly smaller impact, is that partially supported callables are now deprecated as well. Partially supported callables are callables which can be called using <code>call_user_func($callable)</code>, but not by calling <code>$callable()</code> directly. The list of these kinds of callables is rather short, by the way:</p>
<pre>&quot;<span class="hl-value">self::method</span>&quot;
&quot;<span class="hl-value">parent::method</span>&quot;
&quot;<span class="hl-value">static::method</span>&quot;
[&quot;<span class="hl-value">self</span>&quot;, &quot;<span class="hl-value">method</span>&quot;]
[&quot;<span class="hl-value">parent</span>&quot;, &quot;<span class="hl-value">method</span>&quot;]
[&quot;<span class="hl-value">static</span>&quot;, &quot;<span class="hl-value">method</span>&quot;]
[&quot;<span class="hl-value">Foo</span>&quot;, &quot;<span class="hl-value">Bar::method</span>&quot;]
[<span class="hl-keyword">new</span> <span class="hl-type">Foo</span>, &quot;<span class="hl-value">Bar::method</span>&quot;]
</pre>
<p>The reason for doing this? It's a step in the right direction towards being able to use <code>callable</code> for typed properties. Nikita explains it very well in the RFC:</p>
<blockquote>
<p>all of these callables are context-dependent. The method that "self::method" refers to depends on which class the call or callability check is performed from. In practice, this usually also holds for the last two cases, when used in the form of [new Foo, "parent::method"].</p>
<p>Reducing the context-dependence of callables is the secondary goal of this RFC. After this RFC, the only scope-dependence still left is method visibility: "Foo::bar" may be visible in one scope, but not another. If callables were to be limited to public methods in the future (while private methods would have to use first-class callables or Closure::fromCallable() to be made scope-independent), then the callable type would become well-defined and could be used as a property type. However, changes to visibility handling are not proposed as part of this RFC.</p>
</blockquote>
<hr />
<p>That's all there is for now, I'll keep this list updated throughout the year. You can subscribe to <a href="/mail">my newsletter</a> if you want to receive occasional updates!</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-12-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP Annotated, the YouTube channel ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-annotated"/>

                <id>https://www.stitcher.io/blog/php-annotated</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Some very exciting news today! If you're a regular reader of this blog, you know that I've been working on my <a href="https://stitcher.io/yt">YouTube channel</a> for the past years as a hobby project. You might also know that I've been a <a href="https://www.youtube.com/watch?v=UsURiWAd6eI">developer advocate at JetBrains</a> for half a year now.</p>
<p>Today, these two blend together! My personal channel will now be known as "PHP Annotated", and I'll be able to work on it as part of my job!</p>
<p>I'm really excited about this, especially since the goal of the channel will stay exactly the same: creating quality content, focussed on the PHP community. So don't worry: the channel won't become a "marketing channel", it'll still be me, doing the same things I was already doing — but now more and better!</p>
<p>If you're curious what I've been doing, you can watch my brand new "What's new in PHP 8.2" video right now!</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/KBcZIY_v9VQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>I hope you're excited, and would love for you to spread the word! Also make sure to subscribe if you want to be kept in the loop. If you've got any questions, you can reach me — as always — via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2022-11-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Deprecating spatie/data-transfer-object ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/deprecating-spatie-dto"/>

                <id>https://www.stitcher.io/blog/deprecating-spatie-dto</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's been four years since I published the first version of <a href="https://github.com/spatie/data-transfer-object">spatie/data-transfer-object</a> together with my then-colleagues at Spatie.</p>
<p>Back then, PHP 7.3 was just around the corner and the package started out as a way to add complex runtime type checks for class properties. It gave programmers certainty about whether they were actually dealing with the right data in a typed way:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostData</span> <span class="hl-keyword">extends</span> <span class="hl-type">DataTransferObject</span>
{
    <span class="hl-comment">/**
     * Built in types: 
     *
     * <span class="hl-value">@var</span> string 
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * Classes with their FQCN: 
     *
     * <span class="hl-value">@var</span> \App\Models\Author
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * Lists of types: 
     *
     * <span class="hl-value">@var</span> \App\Models\Author[]
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * Iterator of types: 
     *
     * <span class="hl-value">@var</span> iterator&lt;\App\Models\Author&gt;
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * Union types: 
     *
     * <span class="hl-value">@var</span> string|int
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * Nullable types: 
     *
     * <span class="hl-value">@var</span> string|null
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * Mixed types: 
     *
     * <span class="hl-value">@var</span> mixed|null
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * Any iterator: 
     *
     * <span class="hl-value">@var</span> iterator
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
    
    <span class="hl-comment">/**
     * No type, which allows everything
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$property</span>;
}
</pre>
<p>Fast forward a year to PHP 7.4, and typed properties were added. From the very start I said that one of the package's goal was to become obsolete in the future, and it seemed like we were one step closer to achieving it.</p>
<p>However, another (accidental) feature of the package started to gain popularity: the ability to cast raw data into nested DTOs. So a DTO like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostData</span> <span class="hl-keyword">extends</span> <span class="hl-type">DataTransferObject</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">AuthorData</span> <span class="hl-property">$author</span>;
}
</pre>
<p>Could be created from this input:</p>
<pre><span class="hl-variable">$postData</span> = <span class="hl-keyword">new</span> <span class="hl-type">PostData</span>([
    '<span class="hl-value">author</span>' =&gt; [
        '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">Foo</span>',
    ],
]);
</pre>
<p>So while typed properties were now a thing, we decided to continue the package, albeit in a slightly other form.</p>
<p>Next came along PHP 8.0 with attributes and named properties, allowing for even more functionality to be added:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyDTO</span> <span class="hl-keyword">extends</span> <span class="hl-type">DataTransferObject</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">OtherDTO</span> <span class="hl-property">$otherDTO</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">OtherDTOCollection</span> <span class="hl-property">$collection</span>;
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">CastWith</span>(<span class="hl-type">ComplexObjectCaster</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-type">ComplexObject</span> <span class="hl-property">$complexObject</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">ComplexObjectWithCast</span> <span class="hl-property">$complexObjectWithCast</span>;
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">NumberBetween</span>(1, 100)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$a</span>;
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">MapFrom</span>('<span class="hl-value">address.city</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$city</span>;
}
</pre>
<p>At this point though, we were far away from the problem the package initially set out to solve. It did no more runtime type checking: in part because of PHP's improved type system, in part because I believe static analysis is a much better approach to solving type-related problems these days.</p>
<p>On top of that, there are better solutions to "data mapping" than what this package does: there's <a href="https://github.com/spatie/laravel-data">spatie/laravel-data</a> with an incredible Laravel-specific approach to mapping data between requests, databases, views, etc; there's <a href="https://github.com/CuyZ/Valinor">cuyz/valinor</a> which offers much more functionality than our package; and there is <a href="https://symfony.com/doc/current/components/serializer.html">symfony/serializer</a> which is a little more bare-bones, but more powerful as well.</p>
<p>And so, the question that has been on my mind for two years, has been answered: it <em>is</em> time to deprecate <code>spatie/data-transfer-object</code>.</p>
<p>I of course discussed the matter with my ex-colleagues at Spatie, as well as with Aidan who has helped maintaining the package for a couple of years now. We all agreed that this is a good time:</p>
<ul>
<li>PHP has evolved a lot, meaning that the original goal of the package has been fulfilled.</li>
<li>There are great alternatives out there, both Laravel-specific and framework agnostic.</li>
<li>It's better to give the package a worthy ending, than a slow death (which is already happening, kind of).</li>
</ul>
<p>Now, keep in mind that a deprecation doesn't mean the package is gone! The code is still here for you to use, and I don't foresee any issue for the near future.</p>
<p>If you were to have any serious concerns though: don't hesitate to let me know <a href="https://twitter.com/brendt_gd">on Twitter</a>!</p>
 ]]></summary>

                <updated>2022-11-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Upgrade to PHP 8.2 with Homebrew on Mac ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-82-upgrade-mac"/>

                <id>https://www.stitcher.io/blog/php-82-upgrade-mac</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="upgrading-with-homebrew"><a href="#upgrading-with-homebrew" class="heading-anchor">#</a> Upgrading with Homebrew</h2>
<p>Start by making sure brew is up-to-date:</p>
<pre>brew update
</pre>
<p>Next, upgrade PHP. You can either use the built-in php recipe, but I recommend to use the <code>shivammathur/homebrew-php</code> tap.</p>
<h3 id="normal-upgrade"><a href="#normal-upgrade" class="heading-anchor">#</a> Normal upgrade</h3>
<pre>brew upgrade php
</pre>
<h3 id="upgrade-with-shivammathur/homebrew-php"><a href="#upgrade-with-shivammathur/homebrew-php" class="heading-anchor">#</a> Upgrade with <code>shivammathur/homebrew-php</code></h3>
<pre>brew tap shivammathur/php
brew install shivammathur/php/php@8.2
</pre>
<p>To switch between versions, use the following command:</p>
<pre>brew link --overwrite --force php@8.2
</pre>
<p>You can read more in the <a target="_blank" href="https://github.com/shivammathur/homebrew-php">repository</a>.</p>
<h3 id="next-steps"><a href="#next-steps" class="heading-anchor">#</a> Next steps</h3>
<p>Check the current version by running <code>php -v</code>:</p>
<pre>php -v
</pre>
<p>Restart Nginx or Apache, if you're using Laravel Valet you can skip to the next section; you need some extra steps in order for the web server to properly work.</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<p>And make sure that your local web server also uses PHP 8.2 by visiting this script:</p>
<pre># index.php, accessible to your web server

<span class="hl-property">phpinfo</span>();
</pre>
<p><em class="small center">The version should show <code>8.2.x</code>.</em></p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="valet"><a href="#valet" class="heading-anchor">#</a> Valet</h2>
<p>If you're using Laravel Valet, you should do the following steps to upgrade it:</p>
<pre>composer global update
</pre>
<p>You can use <code>valet use</code> to switch between PHP versions:</p>
<pre>valet use php@8.2
valet use php@8.1
</pre>
<h2 id="extensions"><a href="#extensions" class="heading-anchor">#</a> Extensions</h2>
<p>PHP extensions are installed using pecl. I personally use Redis and Xdebug. They can be installed like so:</p>
<pre>pecl install redis
pecl install xdebug
</pre>
<p>You can run <code>pecl list</code> to see which extensions are installed:</p>
<pre>pecl list

# Installed packages, channel pecl.php.net:
# =========================================
# Package Version State
# redis   5.3.4   stable
# xdebug  3.1.1   stable
</pre>
<p>You can search for other extensions using <code>pecl search</code>:</p>
<pre>pecl search pdf

# Retrieving data...0%
# ..
# Matched packages, channel pecl.php.net:
# =======================================
# Package Stable/(Latest) Local
# pdflib  4.1.4 (stable)        Creating PDF on the fly with the PDFlib library
</pre>
<p>Make sure to restart your web server after installing new packages:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<pre>valet restart
</pre>
<p>Make sure all extensions are correctly installed and loaded by checking both your PHP webserver and CLI installs:</p>
<pre>php -i | grep redis
</pre>
<pre><span class="hl-property">var_dump</span>(<span class="hl-property">extension_loaded</span>('<span class="hl-value">redis</span>'));
</pre>
<p>If extensions aren't properly loaded, there are two easy fixes.</p>
<p>First, make sure the extensions are added in the correct ini file. You can run <code>php --ini</code> to know which file is loaded:</p>
<pre>Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.2
Loaded Configuration File:         /opt/homebrew/etc/php/8.2/php.ini
Scan for additional .ini files in: /opt/homebrew/etc/php/8.2/conf.d
Additional .ini files parsed:      /opt/homebrew/etc/php/8.2/conf.d/error_log.ini,
/opt/homebrew/etc/php/8.2/conf.d/ext-opcache.ini,
/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini
</pre>
<p>Now check the ini file:</p>
<pre>extension=&quot;redis.so&quot;
zend_extension=&quot;xdebug.so&quot;
</pre>
<p>Note that if you're testing installed extensions via the CLI, you don't need to restart nginx, apache or Valet when making changes to ini settings.</p>
<p>The second thing you can do, if you're updating from an older PHP version which also used pecl to install extension; is to reinstall every extension individually.</p>
<pre>pecl uninstall redis
pecl install redis
</pre>
<h2 id="last-step"><a href="#last-step" class="heading-anchor">#</a> Last step</h2>
<p>Finally you should test and upgrade your projects for <a href="/blog/new-in-php-82">PHP 8.2 compatibility</a>.</p>
 ]]></summary>

                <updated>2022-11-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Readonly classes in PHP 8.2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/readonly-classes-in-php-82"/>

                <id>https://www.stitcher.io/blog/readonly-classes-in-php-82</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8.2 adds a new way of declaring classes: you can make them readonly. In practice, it means that all properties of that class will be readonly. This is especially useful when you're using <a href="/blog/structuring-unstructured-data">data transfer objects</a> or value objects, where a class only has public <a href="/blog/php-81-readonly-properties">readonly properties</a>.</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/2cyJq08q6xE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>In other words, instead of writing this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
}
</pre>
<p>You can now write this:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
}
</pre>
<p>I've written about readonly properties before, so let's quickly summarise first:</p>
<ul>
<li>readonly properties can only be written once — usually in the constructor;</li>
<li>only typed properties can be made readonly;</li>
<li>they cannot have a default value (unless you're using promoted properties);</li>
<li>the <code>readonly</code> flag cannot be changed during inheritance; and finally</li>
<li>you cannot unset readonly properties.</li>
</ul>
<p>Since readonly classes are merely syntactic sugar for making all properties of that class readonly, it means that the same rules apply to readonly classes as well.</p>
<h3 id="write-once"><a href="#write-once" class="heading-anchor">#</a> Write once</h3>
<p>All properties of a readonly class can only be written once, and can not be unset:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span> { <span class="hl-comment">/* … */</span> }

<span class="hl-variable">$blogData</span> = <span class="hl-keyword">new</span> <span class="hl-type">BlogData</span>(<span class="hl-comment">/* … */</span>);

<span class="hl-variable">$blogData</span>-&gt;<span class="hl-property">title</span> = '<span class="hl-value">other</span>';

<span class="hl-keyword">unset</span>(<span class="hl-variable">$blogData</span>-&gt;<span class="hl-property">title</span>);
</pre>
<h3 id="only-typed-properties"><a href="#only-typed-properties" class="heading-anchor">#</a> Only typed properties</h3>
<p>A readonly class can only have typed properties:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-property">$mixed</span>;
}
</pre>
<h3 id="no-static-properties"><a href="#no-static-properties" class="heading-anchor">#</a> No static properties</h3>
<p>Since readonly properties cannot be static, readonly classes cannot have any static properties:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> string <span class="hl-property">$title</span>;
}
</pre>
<h3 id="no-default-values"><a href="#no-default-values" class="heading-anchor">#</a> No default values</h3>
<p>Properties of a readonly class can not have a default value unless you're using promoted properties:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span> = '<span class="hl-value">default</span>';
}
</pre>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span> = 'default', // This works
   </span>) {}
}
</pre>
<h3 id="no-changes-during-inheritance"><a href="#no-changes-during-inheritance" class="heading-anchor">#</a> No changes during inheritance</h3>
<p>You cannot change the <code>readonly</code> class flag during inheritance:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span> { <span class="hl-comment">/* … */</span> }

<span class="hl-keyword">class</span> <span class="hl-type">NewsItemData</span> <span class="hl-keyword">extends</span> <span class="hl-type">BlogData</span> { <span class="hl-comment">/* … */</span> }
</pre>
<h3 id="no-dynamic-properties"><a href="#no-dynamic-properties" class="heading-anchor">#</a> No dynamic properties</h3>
<p>Readonly classes also don't allow dynamic properties. This won't have a big impact since <a href="/blog/deprecated-dynamic-properties-in-php-82">dynamic properties are deprecated</a> in PHP 8.2 anyway, but means that you cannot add the <code>#[AllowDynamicProperties]</code> attribute to readonly classes:</p>
<pre><span class="hl-attribute">#[<span class="hl-type">AllowDynamicProperties</span>]</span>
<span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span> { <span class="hl-comment">/* … */</span> }
</pre>
<h3 id="reflection"><a href="#reflection" class="heading-anchor">#</a> Reflection</h3>
<p>Finally, there's a new reflection method to determine whether a class is readonly: <code>ReflectionClass::isReadOnly()</code>. You can also use <code>ReflectionClass::getModifiers()</code>, which will include the <code>ReflectionClass::IS_READONLY</code> flag.</p>
<hr />
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
 ]]></summary>

                <updated>2022-10-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.2 in 8 code blocks ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-82-in-8-code-blocks"/>

                <id>https://www.stitcher.io/blog/php-82-in-8-code-blocks</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">PostData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$author</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$createdAt</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">PostState</span> <span class="hl-property">$state</span>,
    </span>) {}
}
</pre>
<p><em class="small center"><a href="/blog/readonly-classes-in-php-82">Readonly classes</a></em></p>
<hr />
<pre><span class="hl-variable">$rng</span> = <span class="hl-variable">$is_production</span>
    <span class="hl-operator">?</span> <span class="hl-keyword">new</span> <span class="hl-type">Random\Engine\Secure</span>()
    : <span class="hl-keyword">new</span> <span class="hl-type">Random\Engine\Mt19937</span>(1234);
 
<span class="hl-variable">$randomizer</span> = <span class="hl-keyword">new</span> <span class="hl-type">Random\Randomizer</span>(<span class="hl-variable">$rng</span>);

<span class="hl-variable">$randomizer</span>-&gt;<span class="hl-property">shuffleString</span>('<span class="hl-value">foobar</span>');
</pre>
<p><em class="small center"><a href="/blog/new-in-php-82#new-random-extension-rfc">New random extension</a></em></p>
<hr />
<pre><span class="hl-keyword">function</span> <span class="hl-property">alwaysFalse</span>(): <span class="hl-keyword">false</span>
{
    <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
}
</pre>
<p><em class="small center"><a href="/blog/new-in-php-82#null,--true,-and-false-as-standalone-types-rfc"><code>null</code>,  <code>true</code>, and <code>false</code> as standalone types</a></em></p>
<hr />
<pre><span class="hl-keyword">function</span> <span class="hl-property">generateSlug</span>(<span class="hl-injection"><span class="hl-type">(HasTitle&amp;HasId)|null</span> $post</span>) 
{ <span class="hl-comment">/* … */</span> }
</pre>
<p><em class="small center"><a href="/blog/new-in-php-82#disjunctive-normal-form-types-rfc">Disjunctive Normal Form Types</a></em></p>
<hr />
<pre><span class="hl-keyword">trait</span> <span class="hl-type">Foo</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">CONSTANT</span> = 1;
 
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>(): <span class="hl-type">int</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-type">self</span>::<span class="hl-property">CONSTANT</span>;
    }
}
</pre>
<p><em class="small center"><a href="/blog/new-in-php-82#constants-in-traits-rfc">Constants in traits</a></em></p>
<hr />
<pre><span class="hl-keyword">function</span> <span class="hl-property">connect</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $user,
    #[\SensitiveParameter] <span class="hl-type">string</span> $password
</span>) {
    <span class="hl-comment">// …</span>
}
</pre>
<p><em class="small center"><a href="/blog/new-in-php-82#redact-parameters-in-back-traces-rfc">Redacted parameters</a></em></p>
<hr />
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span> {}

<span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>();

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span> = '<span class="hl-value">Name</span>';

<span class="hl-comment">// Deprecated: Creation of dynamic property is deprecated</span>
</pre>
<p><em class="small center"><a href="/blog/deprecated-dynamic-properties-in-php-82">Deprecated dynamic properties</a></em></p>
<hr />
<pre><span class="hl-keyword">enum</span> <span class="hl-type">A</span>: <span class="hl-type">string</span> 
{
    <span class="hl-keyword">case</span> <span class="hl-property">B</span> = '<span class="hl-property">B</span>';
    
    <span class="hl-keyword">const</span> <span class="hl-property">C</span> = [<span class="hl-type">self</span>::<span class="hl-property">B</span>-&gt;<span class="hl-property">value</span> =&gt; <span class="hl-type">self</span>::<span class="hl-property">B</span>];
}
</pre>
<p><em class="small center"><a href="/blog/new-in-php-82#fetch-properties-of-enums-in-const-expressions-rfc">Enum properties in const expressions</a></em></p>
<hr />
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
 ]]></summary>

                <updated>2022-10-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Uses ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/uses"/>

                <id>https://www.stitcher.io/blog/uses</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's time. People keep asking me about my setup, so here it is — short and to the point, no life story or sponsored links attached to it.</p>
<h2 id="audio"><a href="#audio" class="heading-anchor">#</a> Audio</h2>
<ul>
<li>
<a href="https://www.shure.com/nl-BE/producten/microfoons/sm7b?variant=SM7B">Shure SM7B</a>
</li>
<li>
<a href="https://www.tritonaudio.com/fethead">Triton FetHead preamp</a>
</li>
<li>
<a href="https://focusrite.com/en/audio-interface/scarlett/scarlett-solo">Focusrite Scarlett Solo</a>
</li>
<li>
<a href="https://rode.com/en/accessories/stands-bars/psa1-plus">Rode PSA1+ boom arm</a>
</li>
</ul>
<h2 id="video"><a href="#video" class="heading-anchor">#</a> Video</h2>
<ul>
<li>
<a href="https://electronics.sony.com/imaging/interchangeable-lens-cameras/aps-c/p/ilce6000l-b">Sony Alpha a6000</a>
</li>
<li>
<a href="https://www.sigma-global.com/en/lenses/c017_16_14/">Sigma 16mm F1.4 DC DN</a>
</li>
<li>
<a href="https://www.elgato.com/en/cam-link-4k">Elgato Cam Link 4k</a>
</li>
<li>
<a href="https://www.elgato.com/en/key-light-air">Elgato Key Light Air</a> (2x)</li>
<li>
<a href="https://www.philips-hue.com/en-us/p/hue-white-and-color-ambiance-go-portable-light--latest-model-/7602031U7">Philips Hue Go</a> (2x)</li>
<li>
<a href="https://rode.com/en/accessories/stands-bars/psa1">Rode PSA boom arm</a>
</li>
<li>
<a href="https://www.pergear.com/products/pergear-th3-pro">Pergear TH3 Pro ball head</a>
</li>
</ul>
<h2 id="recording-and-editing"><a href="#recording-and-editing" class="heading-anchor">#</a> Recording and editing</h2>
<ul>
<li>Apple Quicktime for screen and cam recording — I always record them separately</li>
<li>For cam recording — I always have a script written word by word</li>
<li>
<a href="https://www.jetbrains.com/phpstorm/">PhpStorm</a> for code and blog content</li>
<li>
<a href="https://www.adobe.com/products/premiere.html">Premiere Pro</a> for video editing</li>
<li>
<a href="https://www.adobe.com/products/audition.html">Audition</a> for audio editing</li>
<li>This is my EQ preset (for my voice in my room):</li>
</ul>
<div class="image-noborder"></div>
<p><a href="/resources/img/blog/uses/eq.png"><img src="/resources/img/blog/uses/eq.png" srcset="/resources/img/blog/uses/eq-1596x1032.png 1596w, /resources/img/blog/uses/eq-1009x652.png 1009w, /resources/img/blog/uses/eq-1427x922.png 1427w, /resources/img/blog/uses/eq-1236x799.png 1236w, /resources/img/blog/uses/eq-713x461.png 713w" sizes="" alt=""></img></a></p>
<h2 id="colour-scheme"><a href="#colour-scheme" class="heading-anchor">#</a> Colour scheme</h2>
<ul>
<li>
<a href="https://github.com/brendt/phpstorm-light-lite-theme">Light lite</a>
</li>
</ul>
 ]]></summary>

                <updated>2022-09-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Asymmetric visions ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/thoughts-on-asymmetric-visibility"/>

                <id>https://www.stitcher.io/blog/thoughts-on-asymmetric-visibility</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>There's a new RFC in town called <a href="https://wiki.php.net/rfc/asymmetric-visibility">asymmetric visibility</a>, its aim is to define properties which can be <em>written to</em> from a protected or private scope, but which from the outside — the public scope — can only be <em>read</em>.</p>
<p>It looks something like this:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">private</span>(set) <span class="hl-type">string</span> <span class="hl-property">$title</span>,
    </span>) {}
}
</pre>
<p>There are a couple of things going on here:</p>
<ul>
<li>we're using a <a href="/blog/constructor-promotion-in-php-8">promoted property</a> to define the title; and</li>
<li>we're explicitly saying that <code>$title</code> can only be set (and thus overwritten) within the <code>private</code> scope of <code>Post</code>.</li>
</ul>
<p>In other words, this is allowed:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">private</span>(set) <span class="hl-type">string</span> <span class="hl-property">$title</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">changeTitle</span>(<span class="hl-injection"><span class="hl-type">string</span> $title</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// Do a bunch of checks</span>
        <span class="hl-keyword">if</span> (<span class="hl-property">strlen</span>(<span class="hl-variable">$title</span>) &lt; 30) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">InvalidTitle</span>('<span class="hl-value">Title length should be at least 30</span>');
        }
        
        <span class="hl-comment">// Change the title from within the private scope</span>
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
    }
}
</pre>
<p>While this isn't:</p>
<pre><span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>('<span class="hl-value">Title</span>');

<span class="hl-comment">// Setting $title from the public scope isn't allowed:</span>
<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span> = '<span class="hl-value">Another title</span>';
</pre>
<p>I would say it's a pretty decent proposal, I can come up with a bunch of use cases where you want public readonly access to an object's properties (without the overhead of implementing getters), while still being able to change a property's value from within its class. That class could for example add internal checks to ensure the value adheres to any number of business rules — as a simplified example: ensuring the title of our post is at least 30 characters long.</p>
<p>So all things good, here's hoping the RFC passes.</p>
<p>Right?</p>
<p>Well, I have a problem with it. Actually, not with the RFC <em>itself</em> — I think it's a very good proposal. No, my concern is not with this RFC on its own, but rather with how it's closely related to readonly properties.</p>
<p>Here we have an RFC which scope overlaps with readonly properties (albeit not entirely the same), with a future possibility to replace readonly properties altogether. Here's a quote from the RFC:</p>
<blockquote>
<p>At this time, there are only two possible operations to scope: read and write. In concept, additional operations could be added with their own visibility controls. Possible examples include:</p>
<ul>
<li>…</li>
<li>once - Allows a property to be set only once, and then frozen thereafter. In this case, <strong>public private(once) would be exactly equivalent to readonly</strong>, whereas public protected(once) would be similar but also allow the property to be set from child classes.</li>
</ul>
</blockquote>
<p>It's clear that this RFC and its successors have the potential to replace readonly properties entirely. <a href="/blog/php-81-readonly-properties">Readonly properties</a> — a feature that only has been added one year ago in PHP 8.1, not to mention readonly classes, which are <a href="/blog/new-in-php-82">coming to PHP 8.2</a> later this year.</p>
<p>Despite asymmetric visibility being a great proposal, I'm afraid of what PHP will become if we're adding features only to make them irrelevant three or four years later, as could potentially happen here with readonly properties. We should be very careful and deliberate about how we're changing PHP, and not dismiss existing features too quickly.</p>
<p>If we did, we'd contribute to a lot of uncertainty and instability within the community. Imagine someone adopting readonly properties today, only to hear a year later that by PHP 9.0, they'll probably be deprecated in favor of asymmetric visibility.</p>
<p>Even if readonly properties would stay and coexist with asymmetric visibility, there would be so much room for confusion: when could you use readonly properties? Should you always use asymmetric visibility instead? I would say it's bad language design if a language allows room for these kinds of questions and doubts.</p>
<p>Furthermore, I totally agree with <a href="https://externals.io/message/118353#118382">Marco's sentiment</a> on the matter:</p>
<blockquote>
<p>I use readonly properties aggressively, and I try to make the state as immutable as possible.</p>
<p>In the <strong>extremely</strong> rare cases where <code>public get</code></hljs> and <code>private set</code> are needed, I rely on traditional getters and setters, which are becoming extremely situational anyway, and still work perfectly fine.</p>
<p>[…]</p>
<p>In fact, I'm writing so few getters and setters these days, that I don't see why I'd need getter and setter semantics to creep into the language, especially mutable ones, not even with the reflection improvements.</p>
</blockquote>
<p>Now to be clear: I'm very well aware that asymmetric visibility and readonly properties aren't the same thing. Asymmetric visibility covers a much larger scope and offers much more flexibility. However: Nikita already coined a <a href="https://wiki.php.net/rfc/property_accessors">very similar idea to asymmetric visibility</a> last year, which wasn't pursued in favour of readonly properties. The discussion about whether we want <em>more flexibility</em> has already been had, and the conclusion back then was: no; readonly properties cover 95% of the use cases, and that's good enough.</p>
<p>I would be sad to see PHP become a language that throws out core features every couple of years, for the sake of a little more flexibility. If we wanted more flexibility in this case, we should have decided on that two years ago when readonly properties were discussed in depth; now — in my opinion — is too late.</p>
<hr />
<p>On a final note, if you are worried about cloning objects with new values (a problem this RFC would solve and readonly properties don't): people are already working on <a href="https://wiki.php.net/rfc/readonly_amendments">an RFC to allow rewriting readonly properties while cloning</a>. I'd say it's better to focus our efforts in that area, instead of coming up with an entirely different approach.</p>
<p>Even more: the original example I showed with asymmetric visibility allowing for more functionality (internally guarding business rules) wasn't entirely correct. The same <em>is</em> possible with readonly properties, given that we have a way to overwrite readonly values when cloning them:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">changeTitle</span>(<span class="hl-injection"><span class="hl-type">string</span> $title</span>): <span class="hl-type">self</span>
    {
        <span class="hl-comment">// Do a bunch of checks</span>
        <span class="hl-keyword">if</span> (<span class="hl-property">strlen</span>(<span class="hl-variable">$title</span>) &lt; 30) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">InvalidTitle</span>('<span class="hl-value">Title length should be at least 30</span>');
        }
        
        <span class="hl-keyword">return</span> <span class="hl-keyword">clone</span> <span class="hl-variable">$this</span> with {
            <span class="hl-property">title</span>: <span class="hl-variable">$title</span>,
        }
    }
}
</pre>
<p>Oh, and while the above syntax isn't available yet, it's already possible to overwrite readonly properties while cloning today with some <a href="https://github.com/spatie/php-cloneable">additional userland code</a>:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">Cloneable</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">changeTitle</span>(<span class="hl-injection"><span class="hl-type">string</span> $title</span>): <span class="hl-type">self</span>
    {
        <span class="hl-comment">// Do a bunch of checks</span>
        <span class="hl-keyword">if</span> (<span class="hl-property">strlen</span>(<span class="hl-variable">$title</span>) &lt; 30) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">InvalidTitle</span>('<span class="hl-value">Title length should be at least 30</span>');
        }
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">with</span>(
            <span class="hl-property">title</span>: <span class="hl-variable">$title</span>,
        );
    }
}
</pre>
<hr />
<p>In summary: I think asymmetric visibility is a great feature for <em>some</em> use cases, although there are alternatives as well. All in all, I don't think it's worth adding asymmetric visibility now that we have readonly properties. We decided on readonly properties, we'll have to stick with them for the sake of our users and to prevent ambiguous features from making a mess.</p>
<p>I think <strong>a unified vision and direction for PHP is lacking these days</strong>, and this RFC — great as it is on its own — is a good example of that lacking in practice. I hope that we (PHP internals, that is) can come up with a solution, maybe the <a href="https://opencollective.com/phpfoundation">PHP Foundation</a> has an important role to play in all of this, in the future?</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-08-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What I would change about PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-reimagined-part-2"/>

                <id>https://www.stitcher.io/blog/php-reimagined-part-2</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>If <em>you</em> could change something about PHP, without having to worry about backwards compatibility or breaking changes; what would it be? I know for sure I'd change a thing or two — or ten.</p>
<p>I like thinking about these topics. Not because I believe all of these things necessarily need be added to PHP, but because it's good to challenge our own views and critically think about language design.</p>
<p>I'll keep this list short and to the point, but I'll always link to more in-depth content where relevant. Let's take a look!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="generics-🥺"><a href="#generics-🥺" class="heading-anchor">#</a> Generics 🥺</h2>
<p>The obvious one first. If I'd have to order my wishlist in descending priority, generics are on places one to five, and the rest follows afterwards.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">app</span>(<span class="hl-injection">classString&lt;ClassType&gt; $className</span>): <span class="hl-type">ClassType</span>
{
    <span class="hl-comment">// …</span>
}
</pre>
<p>It's pretty clear however that <a href="https://www.youtube.com/watch?v=BN0L2MBkhNg">generics aren't coming</a> to PHP. That is: as long as we want to validate them at runtime. That's actually what my second wishlist-item is about.</p>
<h2 id="no-more-runtime-type-checks"><a href="#no-more-runtime-type-checks" class="heading-anchor">#</a> No more runtime type checks</h2>
<p>It's not just because of generics, but because it would allow so much more cool stuff, without having a runtime impact: switching to an opt-in, statically analysed compiler.</p>
<p>I actually wrote an in-depth article about <a href="/blog/we-dont-need-runtime-type-checks">not needing runtime type checks</a>. Static analysis is incredibly powerful, and it would benefit PHP's growth a lot if we could get rid of "trying to do everything at runtime".</p>
<p>Keep in mind: it's my opinion, you don't have to agree 😉.</p>
<h2 id="a-superset-of-php"><a href="#a-superset-of-php" class="heading-anchor">#</a> A superset of PHP</h2>
<p>Like TypeScript for JavaScript. Imagine what would be possible if we'd be able to compile a superset language to plain PHP: complex static type checking, lots of cool syntax that would be too difficult to implement with PHP's runtime constraints, generics 🥺, …</p>
<p>There are <em>a lot</em> of caveats and sidenotes to be made here. I made a little <a href="https://www.youtube.com/watch?v=kVww3uk7HMg">vlog</a> about the topic a while ago where I discuss some of the cons, but still I hope that one day this dream may become reality.</p>
<h2 id="cascading-attributes"><a href="#cascading-attributes" class="heading-anchor">#</a> Cascading attributes</h2>
<p>This one might actually be doable: an easy way of getting attributes from parent classes.</p>
<p>So instead of writing this:</p>
<pre><span class="hl-variable">$attributes</span> = [];

<span class="hl-keyword">do</span> {
    <span class="hl-variable">$attributes</span> = <span class="hl-variable">$reflection</span>-&gt;<span class="hl-property">getAttributes</span>(
        <span class="hl-property">name</span>: <span class="hl-type">RouteAttribute</span>::<span class="hl-keyword">class</span>,
        <span class="hl-property">flags</span>: <span class="hl-type">ReflectionAttribute</span>::<span class="hl-property">IS_INSTANCEOF</span>
    );
    
    <span class="hl-variable">$reflection</span> = <span class="hl-variable">$reflection</span>-&gt;<span class="hl-property">getParentClass</span>();
} <span class="hl-keyword">while</span> (<span class="hl-variable">$attributes</span> === [] <span class="hl-operator">&amp;&amp;</span> <span class="hl-variable">$reflection</span>);
</pre>
<p>We could do this:</p>
<pre><span class="hl-variable">$attributes</span> = <span class="hl-variable">$reflection</span>-&gt;<span class="hl-property">getAttributes</span>(
    <span class="hl-property">name</span>: <span class="hl-type">RouteAttribute</span>::<span class="hl-keyword">class</span>,
    <span class="hl-property">flags</span>: <span class="hl-type">ReflectionAttribute</span>::<span class="hl-property">IS_INSTANCEOF</span> 
         | <span class="hl-type">ReflectionAttribute</span>::<span class="hl-property">CASCADE</span>
);
</pre>
<h2 id="scalar-objects"><a href="#scalar-objects" class="heading-anchor">#</a> Scalar objects</h2>
<p>It's not that high up on my list since there are userland implementations available, although it would be nice if scalar objects could have proper names. So <code>String</code> instead of <code>StringHelper</code> (which is how Laravel solves the problem of <code>String</code> being a reserved word).</p>
<pre><span class="hl-variable">$string</span> = <span class="hl-keyword">new</span> <span class="hl-type">String</span>('<span class="hl-value"> hello, world </span>')-&gt;<span class="hl-property">trim</span>()-&gt;<span class="hl-property">explode</span>('<span class="hl-value">,</span>');
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="pipe-operator"><a href="#pipe-operator" class="heading-anchor">#</a> Pipe operator</h2>
<p>There has been <a href="https://wiki.php.net/rfc/pipe-operator-v2">an RFC</a> for it a while ago: the pipe operator. However, it has been inactive for a while now. I actually think Larry Garfield still wants to do it some day, but I'm not sure how concrete the plans are currently.</p>
<p>Anyway, a pipe operator would be cool:</p>
<pre><span class="hl-variable">$result</span> = &quot;<span class="hl-value">Hello World</span>&quot;
    |&gt; <span class="hl-property">htmlentities</span>(...)
    |&gt; <span class="hl-property">str_split</span>(...)
    |&gt; <span class="hl-property">array_map</span>(<span class="hl-property">strtoupper</span>(...), $$)
    |&gt; <span class="hl-property">array_filter</span>($$, <span class="hl-keyword">fn</span>(<span class="hl-injection">$v</span>) =&gt; <span class="hl-variable">$v</span> != '<span class="hl-property">O</span>');
</pre>
<p>Note that I'm taking some creative liberties in how argument placeholders would work with the <code>$$</code> syntax.</p>
<h2 id="unified-function-names"><a href="#unified-function-names" class="heading-anchor">#</a> Unified function names</h2>
<p>"It would be such a breaking change 😱!!!" to finally make all PHP functions follow the same naming convention. No more <code>str_replace</code> and <code>strlen</code>, but rather <code>string_replace</code> and <code>string_length</code>.</p>
<p>It wouldn't be that big of a breaking change though: we could automate the upgrade process with tools like <a href="https://github.com/rectorphp/rector">Rector</a>, and static analysers would tell us about the correct function names while writing code. It would take some getting used to, but at least there would be a consistent API.</p>
<h2 id="stricter-everything"><a href="#stricter-everything" class="heading-anchor">#</a> Stricter everything</h2>
<p>If you weren't yelling at me by now, many of you probably will after reading this section. I'd make PHP much stricter overall. Why? Because <a href="/blog/uncertainty-doubt-and-static-analysis">I like clarity</a> in my code. A stricter language means less room for interpretation or behind-the-scenes-magic that leads to lots of confused moments. So that would include:</p>
<ul>
<li>Final by default</li>
<li>A return type is required</li>
<li>Omitting a return type means void</li>
<li>Everything must be typed</li>
<li>Visibility modifiers are required</li>
</ul>
<p>This will probably never happen, and that's ok; I can enforce most of these things by using PHP CS anyway.</p>
<h2 id="looking-back"><a href="#looking-back" class="heading-anchor">#</a> Looking back</h2>
<p>On a final note, I made a <a href="/blog/php-reimagined">similar list</a> to this one in the past, and I'm actually happy to see that some of the things I wished for back then are implemented in PHP today:</p>
<ul>
<li>
<a href="/blog/php-enums">Enums</a>
</li>
<li>
<a href="/blog/php-81-readonly-properties">Readonly properties</a>
</li>
<li>
<a href="/blog/php-8-named-arguments">Named arguments</a>
</li>
<li>
<a href="/blog/new-in-php-74#improved-type-variance-rfc">Improved type variance</a>
</li>
</ul>
<p>So, who knows! Many more things of this list might end up in PHP after all? Please let it be generics though 🥺!</p>
<p>What would you change about PHP? Let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or send me <a href="mailto:brendt@stitcher.io">e-mail</a>!</p>
 ]]></summary>

                <updated>2022-08-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Deprecated dynamic properties in PHP 8.2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/deprecated-dynamic-properties-in-php-82"/>

                <id>https://www.stitcher.io/blog/deprecated-dynamic-properties-in-php-82</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>As is common with minor releases, <a href="/blog/new-in-php-82">PHP 8.2</a> adds some deprecations. Deprecations often are a source of frustration, though it's important to realise they are actually very helpful. I already wrote about <a href="/blog/dealing-with-deprecations">dealing with deprecations</a> in general, so if you're already feeling frustrated, maybe it's good to take a look at that post first. Today, I want to focus on one deprecation in particular in PHP 8.2: deprecated dynamic properties.</p>
<p>So first things first, what are dynamic properties exactly? Well, they are properties that aren't present on a class' definition, but are set on objects of those classes dynamically, at runtime.</p>
<p>For example this <code>Post</code> class doesn't have a <code>name</code> property, but nevertheless we set it at runtime:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
}

<span class="hl-comment">// …</span>

<span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>();

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>';

<span class="hl-property">var_dump</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span>); <span class="hl-comment">// 'Name'</span>
</pre>
<p>As of PHP 8.2, these dynamic properties will be deprecated:</p>
<pre><span class="hl-comment">// …</span>

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>';
</pre>
<p>You'll see this message: <code>Deprecated: Creation of dynamic property Post::$name is deprecated</code>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="implementing-__get-and-__set-still-works!"><a href="#implementing-__get-and-__set-still-works!" class="heading-anchor">#</a> Implementing <code>__get</code> and <code>__set</code> still works!</h2>
<p>You might be panicking at this point, because dynamic properties are a big part of meta programming in PHP — many frameworks rely on it!</p>
<p>Not to worry: this new deprecation won't affect any class that implements <code>__get</code> and <code>__set</code>. Classes that implement these magic functions will keep working as intended:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$properties</span> = [];
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__set</span>(<span class="hl-injection"><span class="hl-type">string</span> $name, <span class="hl-type">mixed</span> $value</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">properties</span>[<span class="hl-variable">$name</span>] = <span class="hl-variable">$value</span>;
    }
    
    <span class="hl-comment">// …</span>
}

<span class="hl-comment">// …</span>

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>';
</pre>
<p>The same goes for objects of <code>stdClass</code>, they will support dynamic properties just as before:</p>
<pre><span class="hl-variable">$object</span> = <span class="hl-keyword">new</span> <span class="hl-type">stdClass</span>();

<span class="hl-variable">$object</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>'; <span class="hl-comment">// Works fine in PHP 8.2</span>
</pre>
<p>Now some clever readers might wonder: if <code>stdClass</code> still allows dynamic properties, what would happen if you'd extend from it?</p>
<p>Indeed, it <em>is</em> possible to extend from <code>stdClass</code> to prevent the deprecation notice from being shown. However, I'd say this solution is far from ideal:</p>
<pre><span class="hl-comment">// Don't do this</span>

<span class="hl-keyword">class</span> <span class="hl-type">Post</span> <span class="hl-keyword">extends</span> <span class="hl-type">stdClass</span>
{
}

<span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>();

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>'; <span class="hl-comment">// Works in PHP 8.2</span>
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="a-better-alternative"><a href="#a-better-alternative" class="heading-anchor">#</a> A better alternative</h2>
<p>If you <em>really</em> want to use dynamic properties without implementing <code>__get</code> and <code>__set</code>, there is a much better alternative than to extend from <code>stdClass</code>.</p>
<p>The PHP core team has provided a built-in <a href="/blog/attributes-in-php-8">attribute</a> called <code>AllowDynamicProperties</code>. As its name suggests, it allows dynamic properties on classes, without having to rely on sketchy extends:</p>
<pre>#[<span class="hl-type">\AllowDynamicProperties</span>]
<span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
}

<span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>();

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">name</span> = '<span class="hl-value">Name</span>'; <span class="hl-comment">// All fine</span>
</pre>
<h2 id="closing-thoughts"><a href="#closing-thoughts" class="heading-anchor">#</a> Closing thoughts</h2>
<p>PHP used to be a very dynamic language, but has been moving away from that mindset for a while now. Personally I think it's a good thing to embrace stricter rules and rely on static analysis wherever possible, as I find it leads to writing better code.</p>
<p>I can imagine developers who relied on dynamic properties, who are less happy with this change. If you're in that group, you might find it useful to take a closer look into static analysis. You can check out my <a href="https://road-to-php.com/static">Road to PHP: Static Analysis</a> series if you want to learn more!</p>
<p><em>If</em> you're willing to invest some time in figuring out static analysis, I'm fairly certain that most of you won't ever want to return back to the mess that is a dynamic programming language. With PHP we're lucky that both options are available and that you can migrate gradually towards a stricter type system.</p>
<p>So, yes: this deprecation might be a little painful, but I believe it's for the best of the language to do so. And remember that it won't be a fatal error until PHP 9.0, so there's plenty of time to deal with it.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-08-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Light colour schemes are better ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/light-colour-schemes-are-better"/>

                <id>https://www.stitcher.io/blog/light-colour-schemes-are-better</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I just released a video about light colour schemes. I've been encouraging people to try them out for a while now, with pretty good results, actually. I've challenged people to try it out for a week, it certainly doesn't work for everyone, but I've gotten lots of positive reactions on it as well. People actually got rid of persisting headaches because of it, they found their code to be more readable, etc.</p>
<p>Simply switching to a light colour scheme isn't enough though, you need to take some extra steps. And that's exactly the point of this video, to explain what those steps are. I hope you give it a look, and let me know in <a href="https://www.youtube.com/watch?v=mu0HJ0_kprc&amp;ab_channel=BrentRoose">the comments</a> whether you're taking up the one-week light theme challenge!</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/mu0HJ0_kprc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 ]]></summary>

                <updated>2022-07-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP performance across versions ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-performance-across-versions"/>

                <id>https://www.stitcher.io/blog/php-performance-across-versions</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Do you need a reason besides awesome syntax to update to the latest PHP version? Is performance a good one?</p>
<p>I did some casual benchmarks on a WordPress installation from PHP 5.6 to PHP 8.1, here are the results:</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/0KCSrhxlXfw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-07-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The Road to PHP 8.2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/road-to-php-82"/>

                <id>https://www.stitcher.io/blog/road-to-php-82</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm very happy to announce that my Road to PHP series is back! This time you can join <a href="https://road-to-php.com/">The Road to PHP 8.2</a>!</p>
<p>If you're unfamiliar with the concept: the Road to PHP is a newsletter series where you'll receive a daily email teaching you about a new feature of PHP. This time around we'll look at <a href="/blog/new-in-php-82">PHP 8.2</a> — in previous editions we looked at <a href="https://road-to-php.com/php-81">PHP 8.1</a> and <a href="https://road-to-php.com/static">static analysis</a>.</p>
<p>In total, almost 7000 people have followed one of my Road to PHP series, and many have told me they like the format where they can start their day with a 5-minute read, straight to their inbox.</p>
<p>By the way: you won't receive any followup every afterwards: you're automatically unsubscribed, unless you specifically decide to subscribe to <a href="https://stitcher.io/mail">my main newsletter</a> afterwards.</p>
<p>I'd say: give it a try, and <a href="https://road-to-php.com/">join the Road to PHP 8.2</a>!</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
 ]]></summary>

                <updated>2022-07-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Uncertainty, doubt, and static analysis ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/uncertainty-doubt-and-static-analysis"/>

                <id>https://www.stitcher.io/blog/uncertainty-doubt-and-static-analysis</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP is a strange language when it comes to type systems and static analysis. Back when it was created, it was a very dynamic and weakly typed language, but it has been slowly evolving towards a language with a stricter type system — albeit opt-in. Developers can still write dynamic and untyped PHP code if they want to, but more and more people seem to lean towards using PHP's type system regularly.</p>
<p>You can see this trend all throughout the community:</p>
<ul>
<li>PHP's internal team has been creating more and more type-system related features in recent years;</li>
<li>the rise of external static analysis tools like PHPStan, PhpStorm and Psalm; and</li>
<li>frameworks are more and more relying on stricter types and even embracing third-party static analysis syntax like generics in Laravel.</li>
</ul>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>While I think this is a good evolution, I also realise there is a large group within the PHP community that don't want to use a stricter type system or rely on static analysis.</p>
<p>I've had several discussions with that group over the years, and it seems that we cannot get on the same page. I lay out my arguments in favour of stricter type systems and static analysis and as a response I get something like this: <em>sure, but it's way too verbose to write all those types, it makes my code too strict to my liking, and I don't get enough benefit from it.</em></p>
<p>So when working on my latest video about <a href="https://youtu.be/e0tstsbD4Ro">the problem with null</a>, I came up with yet another way to phrase the argument, in hopes to convince some people to at least consider the possibility that types and static analysis — despite their overhead — can still benefit them.</p>
<p>So, here goes. Attempt number I-lost-count:</p>
<p>My main struggle with writing and maintaining code isn't with what patterns to use or which performance optimizations to apply, it isn't about clean code, project structure or what not; it is about uncertainty and doubt. Here's what that looks like:</p>
<ul>
<li>
<em>Will this variable always be an object of interface <code>X</code>?</em>
</li>
<li>
<em>Should I write an extra null check here, to be sure my program won't crash?</em>
</li>
<li>
<em>What order should I pass these parameters in again?</em>
</li>
<li>
<em>What kind of data is in this array?</em>
</li>
<li>
<em>I don't understand what this function does without reading external documentation.</em>
</li>
</ul>
<p>It is those kinds of questions and doubts that I'm bothered by, and it is those kinds of questions that a static analyser answers for me — most of the time.</p>
<p>So no, using a stricter type system and relying on static analysis doesn't slow you down. It increases productivity tenfold, it takes away so much uncertainty and doubt, it's liberating, and I cannot code without it anymore.</p>
<iframe width="560" height="400" src="https://www.youtube.com/embed/e0tstsbD4Ro" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-07-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The evolution of a PHP object throughout the years ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/evolution-of-a-php-object"/>

                <id>https://www.stitcher.io/blog/evolution-of-a-php-object</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>This is just a fun little post I wrote because I wanted to visualise how my <a href="/blog/structuring-unstructured-data">data transfer objects</a> have evolved over the years.</p>
<p>If you prefer, you can watch my 2-minute as well:</p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/x9bSUo6TGgY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="august-2014:-php-5.6"><a href="#august-2014:-php-5.6" class="heading-anchor">#</a> August 2014: PHP 5.6</h2>
<p>Let's start with PHP 5.6, this is what most people without modern-day PHP knowledge probably think PHP code still looks like. I'll just give you the code, and I'll mention what changes in future versions.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$title</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">State </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$state</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\DateTimeImmutable|null </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$publishedAt</span>;
   
   <span class="hl-comment">/**
    * <span class="hl-value">@param</span> <span class="hl-type">string</span> <span class="hl-variable">$title</span> 
    * <span class="hl-value">@param</span> <span class="hl-type">State</span> <span class="hl-variable">$state</span> 
    * <span class="hl-value">@param</span> <span class="hl-type">\DateTimeImmutable|null</span> <span class="hl-variable">$publishedAt</span> 
    */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        $title,
        $state,
        $publishedAt = <span class="hl-keyword">null</span>
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> = <span class="hl-variable">$state</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span> = <span class="hl-variable">$publishedAt</span>;
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">string </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>()
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">State </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getState</span>() 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span>;    
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">\DateTimeImmutable|null </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>() 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<h2 id="december-2015:-php-7.0"><a href="#december-2015:-php-7.0" class="heading-anchor">#</a> December 2015: PHP 7.0</h2>
<p>PHP 7.0 introduced some major new syntax features: scalar types and return types being the most notable here. Nullable types aren't a thing yet, so we still need to use doc block types for our nullable <code>$publishedAt</code>:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$title</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">State </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$state</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\DateTimeImmutable|null </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$publishedAt</span>;
   
   <span class="hl-comment">/**
    * <span class="hl-value">@param</span> <span class="hl-type">\DateTimeImmutable|null</span> <span class="hl-variable">$publishedAt</span> 
    */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title,
        <span class="hl-type">State</span> $state,
        $publishedAt = <span class="hl-keyword">null</span>
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> = <span class="hl-variable">$state</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span> = <span class="hl-variable">$publishedAt</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getState</span>(): <span class="hl-type">State</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span>;    
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">\DateTimeImmutable|null </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>() 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<h2 id="december-2016:-php-7.1"><a href="#december-2016:-php-7.1" class="heading-anchor">#</a> December 2016: PHP 7.1</h2>
<p>With PHP 7.1 finally came nullable types, so we could remove some more doc blocks:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$title</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">State </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$state</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\DateTimeImmutable|null </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$publishedAt</span>;
   
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title,
        <span class="hl-type">State</span> $state,
        <span class="hl-type">?DateTimeImmutable</span> $publishedAt = <span class="hl-keyword">null</span>
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> = <span class="hl-variable">$state</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span> = <span class="hl-variable">$publishedAt</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getState</span>(): <span class="hl-type">State</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>(): <span class="hl-type">?DateTimeImmutable</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<h2 id="november-2017:-php-7.2"><a href="#november-2017:-php-7.2" class="heading-anchor">#</a> November 2017: PHP 7.2</h2>
<p>While there were some exciting features in 7.2 like parameter type widening and the <code>object</code> type, there's nothing we could do to clean up our specific DTO in this release.</p>
<h2 id="december-2018:-php-7.3"><a href="#december-2018:-php-7.3" class="heading-anchor">#</a> December 2018: PHP 7.3</h2>
<p>The same goes for <a href="/blog/new-in-php-73">PHP 7.3</a>, nothing to see here.</p>
<h2 id="november-2019:-php-7.4"><a href="#november-2019:-php-7.4" class="heading-anchor">#</a> November 2019: PHP 7.4</h2>
<p><a href="/blog/new-in-php-74">PHP 7.4</a> is a different story though! There now are <a href="/blog/typed-properties-in-php-74">typed properties</a> — finally!</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span>;
    
    <span class="hl-keyword">private</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span>;
   
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title,
        <span class="hl-type">State</span> $state,
        <span class="hl-type">?DateTimeImmutable</span> $publishedAt = <span class="hl-keyword">null</span>
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> = <span class="hl-variable">$state</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span> = <span class="hl-variable">$publishedAt</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getState</span>(): <span class="hl-type">State</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>(): <span class="hl-type">?DateTimeImmutable</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="november-2020:-php-8.0"><a href="#november-2020:-php-8.0" class="heading-anchor">#</a> November 2020: PHP 8.0</h2>
<p>Another game changer: <a href="/blog/new-in-php-8">PHP 8</a> adds <a href="/blog/constructor-promotion-in-php-8">promoted properties</a>; also, trailing commas in parameter lists are now a thing!</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span>,
        <span class="hl-keyword">private</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getState</span>(): <span class="hl-type">State</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>(): <span class="hl-type">?DateTimeImmutable</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<h2 id="november-2021:-php-8.1"><a href="#november-2021:-php-8.1" class="heading-anchor">#</a> November 2021: PHP 8.1</h2>
<p>Next, we arrive at <a href="/blog/new-in-php-81">PHP 8.1</a>. Readonly properties are a thing, and allow us to write our DTO like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">State</span> <span class="hl-property">$state</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
}
</pre>
<h2 id="november-2022:-php-8.2"><a href="#november-2022:-php-8.2" class="heading-anchor">#</a> November 2022: PHP 8.2</h2>
<p>And finally, we arrive at <a href="/blog/new-in-php-82">PHP 8.2</a> — not released yet.
Whenever a class only has readonly properties, the class itself can be marked as readonly, instead of every individual property:</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">State</span> <span class="hl-property">$state</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
}
</pre>
<p>That's quite the difference, don't you think?</p>
<p>It's interesting to see how the language has evolved over the course of almost a decade. If you had proposed the 8.2 syntax 10 years ago, you'd probably be called a madman. The same is true <a href="/blog/we-dont-need-runtime-type-checks">today</a>, and I'm sure we'll look back at this point, ten years from now and wonder "how did we ever put up with that?".</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-07-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP version stats: July, 2022 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-version-stats-july-2022"/>

                <id>https://www.stitcher.io/blog/php-version-stats-july-2022</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's that time again: my biyearly summary of which PHP versions are used across the community. I know I'm a <em>little</em> early, that's because I had some spare time today and wanted to make sure I got it ready in time. You can read the January edition <a href="/blog/php-version-stats-january-2022">here</a>.</p>
<p>As always, it's important to note that I'm working with the data available to us. That means that these charts are no 100% accurate representation of the PHP community as a whole, but they <em>are</em> an accurate representation of one of the most prominent parts of PHP: the <a href="https://packagist.org/php-statistics">packagist ecosystem</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="usage-statistics"><a href="#usage-statistics" class="heading-anchor">#</a> Usage Statistics</h2>
<p>Let's start with the percentage of PHP versions being used today, and compare it to the previous two editions:</p>
<table>
<tr class="table-head">
    <td>Version</td>
    <td>July, 2021 (%)</td>
    <td>January, 2022 (%)</td>
    <td>July, 2022 (%)</td>
</tr>
<tr>
    <td>8.1</td>
    <td>0.1</td>
    <td>9.1</td>
    <td>24.5</td>
</tr>
<tr>
    <td>8.0</td>
    <td>14.7</td>
    <td>23.9</td>
    <td>20.6</td>
</tr>
<tr>
    <td>7.4</td>
    <td>46.8</td>
    <td>43.9</td>
    <td>38.4</td>
</tr>
<tr>
    <td>7.3</td>
    <td>19.2</td>
    <td>12.0</td>
    <td>8.0</td>
</tr>
<tr>
    <td>7.2</td>
    <td>10.4</td>
    <td>6.6</td>
    <td>5.1</td>
</tr>
<tr>
    <td>7.1</td>
    <td>3.8</td>
    <td>2.4</td>
    <td>1.9</td>
</tr>
</table>
<p>Note that I've omitted all versions that don't have more than 1% usage. Visualizing this data looks something like this:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2022-july-01.svg"><img src="/resources/img/blog/version-stats/2022-july-01.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2022-july-01.svg">Evolution of version usage</a></em></p>
<p>As expected during a year with a minor release instead of a major one: PHP 8.1 is growing, and PHP 8.0's usage is already declining. A good sign that developers are updating! Keep in mind that PHP 8.0 is still actively <a target="_blank" href="https://www.php.net/supported-versions.php">supported for another four months</a>. So if you kept off on updating to PHP 8.1, now is a good time.</p>
<p>Less good news — although not unexpected: more than 50% of developers are still on PHP 7.4 or lower. That's not an insignificant number, considering that PHP 7.4 only receives security updates for 5 more months, and all older versions simply aren't supported anymore.</p>
<p>I did hope to see PHP 8.X adoption to be climbing more rapidly, I've shared some of my thoughts about it <a href="/blog/a-storm-in-a-glass-of-water">here</a>, if you want some more reading.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>Moving on the the all-time overview chart, here you can see the evolution of version usage across time:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2022-july-02.svg"><img src="/resources/img/blog/version-stats/2022-july-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2022-july-02.svg">All time evolution</a></em></p>
<p>It's interesting to compare the 5.5 peak in 2014 to the 7.4 peak two years ago. PHP 5.5 and subsequent versions saw a much faster decline as soon as PHP 7.0 became available, compared to PHP 7.4's decline when PHP 8.0 was released. I'm a little worried that PHP 8.0 wasn't <em>as</em> exciting as PHP 7.0 back in the day.</p>
<p>Fear for upgrading shouldn't be a blocker these days compared to eight years ago: we now have mature tools like <a href="https://github.com/rectorphp/rector">Rector</a> and <a href="https://github.com/squizlabs/PHP_CodeSniffer">PHP CS</a> that take care of almost the whole upgrade path for you.</p>
<p>So why aren't people upgrading to PHP 8.0? Why are more people staying with PHP 7.4 compared to the 5.5 and 5.6 days? I don't have a definitive answer.</p>
<h2 id="required-versions"><a href="#required-versions" class="heading-anchor">#</a> Required versions</h2>
<p>Part of the answer though (I think) lies with the open source community: what are packages requiring as their minimal version? Are they encouraging their users to update, or not?</p>
<p>I used Nikita's <a target="_blank" href="https://github.com/nikic/popular-package-analysis">popular package analyzer</a> to download the 1000 most popular composer packages. Next, I used a little script to get the lowest version each package supports from their <code>composer.json</code> file. Here are the results:</p>
<table>
<tr class="table-head">
    <td>Version</td>
    <td>July, 2021 (#)</td>
    <td>January, 2022 (#)</td>
    <td>July, 2022 (#)</td>
</tr>
<tr>
    <td>8.1</td>
    <td>-</td>
    <td>-</td>
    <td>125</td>
</tr>
<tr>
    <td>8.0</td>
    <td>117</td>
    <td>160</td>
    <td>94</td>
</tr>
<tr>
    <td>7.4</td>
    <td>56</td>
    <td>69</td>
    <td>86</td>
</tr>
<tr>
    <td>7.3</td>
    <td>133</td>
    <td>116</td>
    <td>104</td>
</tr>
<tr>
    <td>7.2</td>
    <td>142</td>
    <td>133</td>
    <td>130</td>
</tr>
<tr>
    <td>7.1</td>
    <td>182</td>
    <td>190</td>
    <td>153</td>
</tr>
<tr>
    <td>7.0</td>
    <td>31</td>
    <td>29</td>
    <td>29</td>
</tr>
<tr>
    <td>5.6</td>
    <td>61</td>
    <td>49</td>
    <td>42</td>
</tr>
<tr>
    <td>5.5</td>
    <td>43</td>
    <td>42</td>
    <td>35</td>
</tr>
<tr>
    <td>5.4</td>
    <td>41</td>
    <td>43</td>
    <td>40</td>
</tr>
<tr>
    <td>5.3</td>
    <td>97</td>
    <td>83</td>
    <td>77</td>
</tr>
<tr>
    <td>5.2</td>
    <td>12</td>
    <td>10</td>
    <td>10</td>
</tr>
<tr>
    <td>5.0</td>
    <td>2</td>
    <td>2</td>
    <td>1</td>
</tr>
</table>
<p>I have mixed feelings about this data. On the one hand it's good to see PHP 8.1 as the minimum required version for 125 packages. However, look at how many packages still require a version lower than PHP 8.0: 707 out of 926 packages analysed. That's more than 75%!</p>
<p>Oh, as a side note: there only are 926 packages because some of the 1000 most popular packages don't specifically require a PHP version.</p>
<p>Let's plot this data into a chart:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2022-july-03.svg"><img src="/resources/img/blog/version-stats/2022-july-03.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2022-july-03.svg">Minimal PHP requirement over time</a></em></p>
<p>I won't say that the open source community is the only responsible factor here, but I do want to encourage you to think carefully about your responsibilities if you are an open source maintainer. We're not just talking about new and shiny PHP features here: we're talking about performance, software security for the most popular programming language on the web, and even about the impact of old PHP versions on electricity usage and server requirements, in Rasmus' words we can help <a href="https://youtu.be/fYTKm2oUzAg?t=617">save the planet</a>.</p>
<hr />
<p>What are your thoughts on these stats? Are you already using <a href="/blog/new-in-php-81">PHP 8.1</a>? Let me know your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> and subscribe to <a href="/newsletter/subscribe">my newsletter</a> if you want to be kept up-to-date about these posts!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-06-27T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Stitcher turns 5 🎉 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/stitcher-turns-5"/>

                <id>https://www.stitcher.io/blog/stitcher-turns-5</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Some exciting news today: Stitcher — this blog — turned 5! In a way, that feels like a long time, although I was also thinking this week: "it feels longer than that". Anyway, it's a reason to celebrate! So first things first: <strong>I'm giving away 5 Stitcher-themed elephpants</strong>, keep on reading if you want one!</p>
<p>Before explaining how you can get an elephpant, let me say how much I appreciate it that you're here. I never imagined my blog to turn out the way it did when I first started it 5 years ago, and that's in large part thanks to you!</p>
<p>So, thank you!</p>
<p>Now, how to get an elephpant: I'm giving them away on Twitter, my newsletter and YouTube. By the time you're reading this, my newsletter is probably already sent, but you can still <a href="https://twitter.com/brendt_gd">follow me on Twitter</a> and <a href="https://www.youtube.com/user/BrenDtRoose">check out YouTube</a> if you want one.</p>
<p>Here's the YouTube video with more instructions:</p>
<p>
<iframe width="560" height="435" src="https://www.youtube.com/embed/kvJDTWH8eoE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</p>
<p>Thanks for reading, and thank you for being here!</p>
<p>Brent</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<!--
                                                                                                                                                      
                                     `,:,.                                                                                                            
                                  .izxxxxxn+:   :*znxxn#i.                                                                                            
                                `*xxxxxxxxxxxzinxxxxxxxxxx#.                                                                                          
                               .zxxx#*i;;i+nxxxxxz+i;i*#nxxxi                                                                                         
                              :nxx#;:::::;+nxxx+,```````,*nxx+                                                                                        
                             ixxn*:;:::;*nxxx*.``````.....,zxx*                                                                                       
                            +xxni:::::izxxx+,````.,:::::::::zxx;       ``````.......,,,,,,,..``                                                       
                          `+xxz;:::;;+xxxz:````,::;;::::::;;;nxxzznnnnnnxxxxxxxxxxxxxxxxxxxxxxnn#+i:`                                                 
                         `#xxn+##znnxxxni````,:::::::::::::::ixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxn+;`                                             
                     `,;*zxxxxxxxxxxxx+.```.::::::::::::::::::#xx+**iiiii;;;;;;::::::::::::;;i*+#znxxxxxx#;`                                          
                  .i#nxxxxxxxxnznxxxn:```.::::::::::::::::::;:;xx+..........,,,,,,,,,,,,,,,,,,,,,,::i+zxxxxx+,                                        
               .izxxxxxxz+*;,.``#xx*.```,::::::;::::;::::;:::;:#xn,.......,,,,,,,,,,,,,,,,,,,,,,,,:::::;*zxxxx#,                                      
             ,#xxxxxz*:.````````:+:```.:;:;:;;:;:;;:;:;;:;:;;::ixxi.....,,,,,,,,,,,,,,,,,,,,,,,,::::::::::;+nxxx+.                                    
           ,#xxxx#i,`````````````````,:::::;;;:;;;;:;;;;:;;;;::;nx#,,,,:::::::::::::;;;;;;;;;;;;;;;:::::::::;+nxxn;                     ,+nxn#:       
         `*xxxn+,`   ``````````````.:::;::;::::;::::;::::;::::::#xn;::::;::::;;;;;;;;;;;;;;;;;iiiiiiiii;;:::::;#xxx#`                 `#xxxxxxx;      
        .zxxx+,` `  ````````..,```,::::;::;::::;::::;::::;::::::*xxi::::;:::;;;;;;;;;;;;;;;;;;iiiiiiiiiiiii;::::izxxz.               :nxxn+*+nxn      
       .nxxz:`  ````````.,:::::..:;:;::;;;;:;;;;:;;;;:;;;;:;;;::;xx+::;;;:;;;;;;;;;;;;;;;;;;iiiiiiiiiiiiiiiiii;::;#xxn,             ;xxx+;;;i#xx`     
      .nxx#.     ````.:::;:;;;::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;nx#::;;;;;;;;;;;;;;;;;;;;;;iiiiiiiiiiiiiii****i;:;*xxx:...........:xxxzznxxxxxx#;`   
     `zxx+.    ````,:;::::::::;;;::::::::::::::::::::::::::::::::zxz:::::;;;;;;;;;;;;;;;;;;iiiiiiiiiiiiiii*******i;;*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxz.  
     *xx#.    ```,:;:::::::::::::::::::::::::::::::::::::::::::::+xn;::::;;;;;;;;;;;;;;;;;iiiiiiiiiiiiiiii*********i;*xxxxxxxxxxxxxxxxxnz++*ii*+zxxn` 
    ,xxz.    ``,:;;;iiii;::::::::::::::::::::::::::::::::::::::::*xx;:::;;;;;;;;;;;;;;;;;;iiiiiiiiiiiiiii************;*xxx#######nxxn*;;;;;;;;;;;+xx, 
    #xx:` ````:;*#nxxxxxxn#;:::::::::::::::::::::::::::::::::::::ixxi:::;;;;;;;;;;;;;;;;iiiiiiiiiiiiiiii**************i+xxnzzzzzznxxxn#+*i;;;;;i+nxx` 
   .xx#`  ```:izxxxn#+***##;:::::::::::::::::::::::::::::::::::::ixx*::;;;;;;;;;;;;;;;;iiiiiiiiiiiiiiii****************izxxxxxxxxxxxxxxxxxxnnnnxxxx;  
   *xx:`````:*xxxn*;;::::::::::::::::::::::::::::::::::::::::::::;xx*:;;;;;;;;;;;;:....,;iiiiiiiiiiiii****************++*nxxnzzzzzznxxxxxxxxxxxxx+,   
   nxz`````:;xxx#;::::::::::::::::::::::;:::;;:::;;:::;;:::;;:::;;xx+:;;;;;;;;;;;:       ;iiiiiiiiiiii****************++++xx*      .nxxzii*+++nxz     
  .xxi````,:ixx#:::::::::::::::::::::::::::::::::::::::::::::::::;nx+:;;;;;;;;;;;`.znnnz ,iiiiiiiiiii****************+++++nxx`      .zxxn#i;;;zxz     
  ;xx,```.:;:i*;;:;;:;::::::;;;;;;;;;;;;;:;:;;:;:;;:;:;;:;:;;:;:;;nx#;;;;;;;;;;;; ;xxxxz ,iiiiiiiiii****************++++++#xx*       `ixxxxnznxx*     
  *xn````:::;:;::;::::;;**;::::::::::::::::;::::;::::;::::;::::;:;nx#;;;;;;;;;;;: *xxxx+ :iiiiiiiii****************++++++++nxn`        .+xxxxxx+`     
  #x#```.:;:;:;;::::;*zxx+:::;;:;:;;:;:;;:;:;;:;:;;:;:;;:;:;;:;:;;nx#;;;;;;;;;;;, zxxxxi ;iiiiiiii*****************++++++++#xx;          `;**i,       
  nx*```,:;;;:;;;::*nxxn*;;;;;;:;;;;:;;;;;;:;;;;:;;;;:;;;;:;;;;:;;nx+::;;;;;;;;;.`xxxxx, ;;;;iiiiii****i;;;;iiiiii*+++++++++nxz                       
 `xxi```::;;;;;;;:*xxxz+*i::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;nxi   `.,;;;;;`,xxxxx`       .,i***i`            `,;*+++++zxx.                      
 .xx:``.:::::::::;nxxn#*+zz;:::::::::::::::::::::::::::::::::::::;xx#*i;,` `:;;; ;xxxxx#****i;:.  :**``i*********i;,` `:++++#xxi                      
 ,xx,``,:::::::::*xxz:`:;,+#:::::::::::::::::::::::::::::::::::;;ixxxxxxxn+. ,;: *xxxxxxxxxxxxxxz, ;i ;xxxxxxxxxxxxxx+. ,++++nx#                      
 ,xx.``,:::::::::+xz, ;xxz:n;:::::::::::::::::::::::::::::::::;;;*xxxxxxxxxn, :, #xxxxxxxxxxxxxxxn``; +xxxxxxxxxxxxxxxx: ;+++zxn`                     
 :xx.``::::::::::+x*` .*x,*zi:::::::::::::::::::::::::::::::::;;;+xxxxxxxxxxz`.. nxxxxxxxxxxxxxxxxi . zxxxxxxxxxxxxxxxxn.`+++#xx,                     
 :xn.``::::::::::ix;  .zx+#n;::::::::::::::::::::::::::::::::;;;;zxz,:*xxxxxx: `.xxxxx*:,,:;+xxxxx#  `xxxxx*,,,,:inxxxxx* i++#xx;                     
 :xn```:::::::::::#i` .nxxx#;::::::::::::::;:::::::::::::::::;;;;xx*`  ,xxxxx+  ;xxxxn  ```  zxxxx#  ,xxxxx`````` `nxxxxn :+##xx*                     
 ;xn``.:::::;::::;;#,` .*zz;:::::::;;:::;:ini:::::::::::::::;;;;*xx*;;. #xxxxz  *xxxx+ :iii: #xxxx+  ;xxxxn :++++; *xxxxx`,+##nx+                     
 ;xn``.::::::::::::i#*;;++;::::::::zz;:::;nx;:::::::::::::;;;;;;nxn;;;: +xxxxz  #xxxxi ;iii, nxxxxi  *xxxx+ ;++++* ixxxxx`,###nxz                     
 ;xn``.::::::::::::::i*i;:;::::::::#xz*;*nx+:::::::::::::;;;;;;+xx+;;;, #xxxx#  nxxxx:`iii*.`xxxxx,  zxxxxi i++++i ixxxxn`,###zxn                     
 ;xn``.:;;;;;;;;;;;;:::::;;;:;;;;:;:+xxxxn+;:;;;::;;;::;;;;;;;ixxn;;;;. nxxxx+ .xxxxx..ii*i`,xxxxx` `xxxxx:`+++++; #xxxxz :###zxn`                    
 ;xn``.:;;;:;:;;:;:;:::::;;;:;;;;:;::;*nn;:::;:;:;;:;:;;::;;;inxxi;;;; ,xxxxx; :xxxxn ,ii*i ixxxxn  ,xxxxx`.+++++.`xxxxx* i###zxx`                    
 ;xn..,:;:;;;;;;;;;;;;;;;;;;;;;;;;;;;;:zn:;;:;;;;:;;;;:;;;;;*xxx*;;;;. +xxxxn` *xxxx# :i**; +xxxx+  ;xxxxn ,++++: ixxxxx,`+###zxx`                    
 ;xn..,:::::;::::;::::;::::;::::;::::;:nz::::;:;::::::::;;*zxxx;.,.`  ;xxxxx*  #xxxxi ;i**, zxxxxi  *xxxx+ ,::.` ,nxxxx# :####zxx`                    
 ;xz..,:::::::::::::::::::::::::::::::;x#::::::::::::;*+zxxxxxi    `:+xxxxxz`  nxxxx: i***.`xxxxx:  zxxxx*    `,*xxxxxx.`+####zxx`                    
 ;xn..,;:::::::::::::::::::::::::::::;ix+::::::::::izxxxxxxxxxnzzznxxxxxxxn.  .xxxxx.`****`,xxxxx`  xxxxxxzzznxxxxxxxx: ;#####zxn                     
 ;xn..,:::::::::::::::::::::::::::::::*x*::::::;:;+xxxxzzxxxxxxxxxxxxxxxxn, , :xxxxn ,***i ;xxxxn  .xxxxxxxxxxxxxxxxn: ,######nxn                     
 ;xz..,:::::::::::::::::::::::::::::::#x;::::::;:*xxn+: *xxxxxxxxxxxxxxx+` ,; ixxxx# :***; +xxxx#  ;xxxxxxxxxxxxxxx#. ,+######nx#                     
 ;xz..,::::::::::::::::::::::::::::::;nz::::::::;nxn;;, #xxxxxxxxxxnz#i. `:i; ixxxx: ;***; *xxxx:  *xxxxxxxxxxxn#*, `;########xx*                     
 ;xz..,::::::::::::::::::::::::::::::*x+::::::::*xx*;;.`nxxxxi````     `,iiii` ```  .****i` ```    #xxxx#````     `:+#########xx:                     
 ;xz..,:::::::::::::::;::::;::::;:::;zx;::;:::::*xx;;;`.xxxxx.`.....,:;iiiiiii,...,:******i,,,,,;, nxxxx: ,,,,,:;*+##########zxx.                     
 ;xz..,:::::::::::::::::::::::::::::*x#:::::::::*xx;;: ;xxxxn .;;iiiiiiiiiiiiiiiii***************`.xxxxx..+++++++############nxz                      
 ;xz..,::::::::::::::::::::::::::::;nn;:::::::::;+*;;: *xxxx# ,;;iiiiiiiiiiiiiii***************** ;xxxxn ,+++++++###########zxx;                      
 ;xz..,::;;:;:;;:;:;;:;:;;:::;::::;zx*;:;:;:;;::;;;;;, #xxxx* :;iiiiiiiiiiiiiiii****************i *xxxx# ;++++++############nxx`                      
 ;xz.,,:::;;;:;;;;:;;:;:;;:::::::;zx#::;;:;::;:;;;;;;. nxxxx: ;;iiiiiiiiiiiiiii*****************; #xxxxi i++++++###########zxxz                       
 ;xz.,::::;;;:;;;;:;;;::;;;;;iii+nx#;::;;;:;;;;;;;;;;, ,;;;, .iiiiiiiiiiiiiiii*****************+i .;;;:`.++++++############znxn                       
 ;xz,,::::::::::::::::::;*#nxxxxxxn+i;::;:;;::;;;;;;;;.`   `.;iiiiiiiiiiiiiiii****************+++;`   `.*++++###############nxn                       
 ;xz,,::::::::::::::::;;zxxxxxxxxxxxxxz*;:zx*;;;;;;;;;;;;;;;;iiiiiiiiiiiiiiii****************++++++++++++++++###############nxn                       
 ;xz,,::::::::::::::;:inxxzi:,.;xxznxxxxxzxx+;;;;;;;;;;;;;;;iiiiiiiiiiiiiiii****************+++++++++++++++++###############nxn                       
 ;xz,,::::::::::::::;;nxx;     .xxi;i+zxxxxx+;;;;;;;;;;;;;;;iiiiiiiiiiiiiii****************+++++++++++++++++################nxn                       
 ;xz,,::::::::::::::;zxx:      .xxi:;::;+zxx+;;;;;;;;;;;;;;;iiiiiiiiiiiiiii****************++++++++++++++++#################nxn                       
 ;xz,,::::::::::::::ixxi       .xxi::::::;xx+;;;;;;;;;;;;;;iiiiiiiiiiiiiii****************++++++++++++++++##################nxn                       
 ;xz,,::::::;::::;::#xn`       .xxi:::::;;xx+;;;;;;;;;;;;;iiiiiiiiiiiiiii*****************+++++++++++++++###################nxn                       
 ;xz,,:;:::::::::::;xx*        .xxi::;::;;xx+;;;;;;;;;;iiiiiiiiiiiiiiiii*****************++++++++++++++++###################nxn                       
 ;xz,,::::;::::;:::*xx,        .xxi;::;;;;xx+;;;;;;;;;;iiiiiiiiiiiiiiiii****************++++++++++++++++####################nxn                       
 ;xz,,:::::::::::::+xn`        .xxi:::;;;;xx+;;;;;;;;;;iiiiiiiiiiiiiii*****************++++++++++++++++#####################nxn                       
 ;xn,,:::;;:;:;;:::#xz         .xxi;:;;;;;xx+;;;;;;;;;;iiiiiiiiiiiiiii****************++++++++++++++++######################nxn                       
 ;xn,,:;;;;:;:;;:::zx+         .xxi;;;;;;;xx+;;;;;;;;;iiiiiiiiiiiiii*****************++++++++++++++++#######################nxn                       
 ;xn,,:::;;;;;;;;::nx*         .xxi;;;;;;;xx+;;;;;;;iiiiiiiiiiiiiiii******+xn********+++++++zn++++++########################nxn                       
 ;xn,:::;;::;:::::;xxi         .xxi;;;;;;;xx+;;;;;;;iiiiiiiiiiiiiii*******#xx******++++++++#xx#++++#########################nxn                       
 ;xn:::::::::::::;;xx;         .xxi;;;;;;;xx+;;;;;;iiiiiiiiiiiiiii********#xx+*****+++++++#zxx#++++#########################nxn                       
 ;xn::::::::::::::ixx,         .xxi;;;;;;;xx+;;;;;iiiiiiiiiiiiiii*********#xxxxnnnnznnnxxxxxxxz+++##########################nxn                       
 ;xn::::::::::::::*xx.         .xxi;;;;;;;xx+;;;;;iiiiiiiiiiiiiii*********#xxxxxxxxxxxxxxxxxxxz++###########################nxn                       
 ;xx::::::::::::::*xx`         .xx*;;;;;;;xx+;;;iiiiiiiiiiiiiiii**********#xx,:i*#xxzzzz####xxz+############################nxn                       
 ;xx:::;::::::::::+xx          .xx*;;;;;;;xx+;;iiiiiiiiiiiiiiii***********#xx    :xx+++++++#xxz#############################nxn                       
 ;xx:::;::::;:::::#xn          .xx*zn+;;;;xx+;;iiiiiiiiiiiiiii************#xx    :xx+zz++++#xxz#############################nxn                       
 ;xx::::;:::::::::#xz          .xxn*:z*;;;xx+;iiiiiiiiiiiiiii*************#xx    :xxn#+n+++#xxz#############################nxn                       
 ;xx:::::::::::::;zx#          .xxz,,;n;;;xx+;iiiiiiiiiiiiiii*************#xx    :xxz;;#z++#xxz#############################nxn                       
 ;xx;:::::::::::::zx+          .xxi,;;#*;;xx+iiiiiiiiiiiiiii**************#xx    :xx*;i*n++#xxz#############################nxn                       
 ;xx;::;;;;:;;;;:;nx*          .xn::;;*#;;xx+iiiiiiiiiiiiii***************#xx    :xniiii#z+#xxz######zzz####################nxn                       
 ;xx;::;:;;;;:;;;;xxi          .x#:;;inni;xx+iiiiii#z+iiii****************#xx    :x#iii*zn+#xxz#####n#*nz###################nxn                       
 ;xx;::;:;:;::::;;xx;          .x*:;;n;izixx+iiiiiz+i##iii****************#xx    :x+ii*n+zz#xxz####n+:,in###################nxn                       
 ;xx;::;:;;:;:;;:ixx:          .xi;;++:;z*xx#iii*#+:,:z+ii***************+#xx    :xiii##;*n#xxz#znnz:,,:+n##################nxn                       
 ;xx;::::::::::::ixx,          ,x;;;z;;;*#xx+i#zzn:,::in****************++#xx    :niiiniiizzxxzzz;#*,:;;;n##################nxn                       
 ;xx;;:::::::::::*xx.          ,n;;;z:;;;nxx###:++,:;;;#+**************+++#xx    :nii*ziii+nxxnz::n:,;;;;+z#################nxn                       
 ;xx;;:::::::::::*xx`          .n;;*#;;;;zxxzn::n;,;;;;*z*************++++#xx    :zii+#iii*xxxxi,*#::;;;;zzn################nxn                       
 ;xx;;:::::::::::+xx           `x;;++;;;;#xxxi,i#::;;;;z#n+***********++++#xx    :nii#+iiiinxxz,:zi:;;;;z*:*n###############nxn                       
 ;xx;;::::::::::;+xn            n*;#*;;;;+xxz::#*:;;;;#*:;n**********+++++#xx    .x*iz*iiiizxx*:;n;:;;;*z::;zz##############nxn                       
 ;xx;;:::::::::;:#xz            +n;#*;;;;+xx*:;n;:;;;iz::;+#********++++++#xx     n#iz*iiiizxx:;iz:;;;;zi:;;*n##############nxn                       
 ;xx;;::::::;::;:zx#            ,xz##;;;;zxx;;;z;;;;;#*:;;;n********++++++#xx     ix+z+iiiinxz:;*+:;;;;n:;;;;n##############nxn                       
 ;xx;:;::::::::::zx+             *xxxi;;*zxn:;i#:;;;;n;;;;;z+*******++++++zxx     `nxnziii+nx#;;++;;;;*#:;;;;#z#############nxz                       
 ;xx;::::::::::::nx*             `#xxn##n*nz;;*+;;;;iz;;;;;+#*****++++++++zxn      :xxxz*+nzx+;;#*;;;;#*;;;;;*n#############xx+                       
 ,xx*;;;;;;;;;;:ixxi              `+xxxx#*zz;;++;;;;++;;;;;iz****+++++++++nx#       :xxxxxz#nz;;+*;;;;zi;;;;;in############zxx;                       
  zxn;;::::::::;zxx.                :zxxxxxn;;*#;;;;#*;;;;;;n****++++++++#xxi        .zxxxxnnxi;*#;;;;zi;;;;;in############nxn`                       
  :xxn+;:::::;*nxx*                   :#xxxx*;iz;;;;#*;;;;;;n***+++++++++nxn`          :#xxxxxn;;n;;;;zi;;;;;in###########nxx;                        
   ;xxxxnzzznxxxx+                      `:i#x*;ni;;;+*;;;;;;n***++++++++nxxi             .i+nxxn+z+;;;++;;;;;+z#########znxx+                         
    .+xxxxxxxxxz:                           *xzz#;;;*z;;;;;+z**+++++++#nxx+                  `,zxxx*;;;ni;;;in########znxxx+`                         
      `:i*+*i;.                              *xxx#;;;z*;;;in+*++++++znxxx*                     `ixxx#*i#n*i*nz##zzznnxxxxn;                           
                                              ,zxxn+*#x#*+n#+###zznxxxxz:                        .*nxxxxxxxxxxxxxxxxxxxzi`                            
                                                :+xxxxxxxxxxxxxxxxxxx#:                             ,i#nxxxxxxxxxxxz+i.                               
                                                  `:i+znxxxxxxxxz#i:`                                   `.,,:::,,.`                                   
                                                        ``....`                                                                     



Oh, hi there! So you want one? Good job on checking the source of this blog post! Well, if you're the first to discover this, you'll get one! Take a screenshot and send it to brendt@stitcher.io! Good luck :)                                                                                                                                      
-->
 ]]></summary>

                <updated>2022-06-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Clean and minimalistic PhpStorm ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/clean-and-minimalistic-phpstorm"/>

                <id>https://www.stitcher.io/blog/clean-and-minimalistic-phpstorm</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>This is a list of things I do when setting up PhpStorm from scratch. I prefer a clean and minimalistic look, which takes less than 5 minutes to set up. You can watch the full video, or scroll through the sections on this page!</p>
<iframe width="560" height="420" src="https://www.youtube.com/embed/jVTk-F3g9XM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="hide-all-toolbars"><a href="#hide-all-toolbars" class="heading-anchor">#</a> Hide all toolbars</h2>
<p>I only use keyboard shortcuts and the actions menu, so I hide all toolbars.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short%20toolbars-hidden.mp4?raw=true" type="video/mp4">
</video>
<h2 id="light-colour-schemes"><a href="#light-colour-schemes" class="heading-anchor">#</a> Light colour schemes</h2>
<p>Light colour schemes are better. That's not just an opinion, it <a href="/blog/why-light-themes-are-better-according-to-science">is</a> <a href="https://tidbits.com/2019/05/31/the-dark-side-of-dark-mode/">a</a> <a href="http://tecfa.unige.ch/tecfa/maltt/cosys-2/textes/hall04.pdf">fact</a>. I prefer a colour scheme that might be less cool and fancy, but forces me to properly light my room and put less strains on my eyes.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short%20color-scheme.mp4?raw=true" type="video/mp4">
</video>
<h2 id="increased-font-size"><a href="#increased-font-size" class="heading-anchor">#</a> Increased font size</h2>
<p>Similar to light colour schemes, pick a font size and line height that works on your monitor, make sure you don't have to squint your eyes in order to read code.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short editor-font-size.mp4?raw=true" type="video/mp4">
</video>
<h2 id="code-folding"><a href="#code-folding" class="heading-anchor">#</a> Code folding</h2>
<p>I enable code folding for method bodies by default. It gives me a proper overview of classes, without too much noise. I've learned to use my keyboard for navigation and managing folds, so that it doesn't impact my performance.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short code-folding.mp4?raw=true" type="video/mp4">
</video>
<h2 id="tabs-at-the-bottom"><a href="#tabs-at-the-bottom" class="heading-anchor">#</a> Tabs at the bottom</h2>
<p>For some reason, placing tabs at the bottom of my screen feels way more natural and less intrusive.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short tabs-bottom.mp4?raw=true" type="video/mp4">
</video>
<h2 id="undocked-sidebar"><a href="#undocked-sidebar" class="heading-anchor">#</a> Undocked sidebar</h2>
<p>Instead of moving sidebars to the right, I undock it, so that it slides on top of my code without moving that code around.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short sidebar-undocked.mp4?raw=true" type="video/mp4">
</video>
<h2 id="the-navigation-bar"><a href="#the-navigation-bar" class="heading-anchor">#</a> The navigation bar</h2>
<p>If you prefer an even cleaner look, you can hide the sidebar altogether and use the navigation bar instead.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short navigation-bar.mp4?raw=true" type="video/mp4">
</video>
<h2 id="distraction-free-mode"><a href="#distraction-free-mode" class="heading-anchor">#</a> Distraction free mode</h2>
<p>Distraction free mode centers my code, making it easier to read on large displays. By default it also hides tabs and line numbers, but you can show them again using the actions menu.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short distraction-free.mp4?raw=true" type="video/mp4">
</video>
<h2 id="scopes-and-file-colours"><a href="#scopes-and-file-colours" class="heading-anchor">#</a> Scopes and file colours</h2>
<p>I use scopes to group and colour my code, allowing for easier navigation.</p>
<video controls="true" autoplay="" muted="" loop="" playsinline="">
    <source src="https://github.com/brendt/stitcher.io/blob/master/resources/img/static/clean-phpstorm/short scopes.mp4?raw=true" type="video/mp4">
</video>
<hr />
<p>That's it! Take a look at <a href="https://www.youtube.com/user/BrenDtRoose">my YouTube channel</a> if you like these kinds of videos!</p>
<iframe width="560" height="420" src="https://www.youtube.com/embed/jVTk-F3g9XM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-06-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ My PHP enum style guide ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-enum-style-guide"/>

                <id>https://www.stitcher.io/blog/php-enum-style-guide</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>This is my personal style guide for using enums in PHP. Each section describes the rule, but also the personal, <em>opinionated</em> reasoning behind the rule.</p>
<h2 id="1.-uppercase"><a href="#1.-uppercase" class="heading-anchor">#</a> 1. Uppercase</h2>
<p>You must use uppercase notation for enum cases:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">PostState</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">PENDING</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">STARRED</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">DENIED</span>;
}
</pre>
<h3 id="why?"><a href="#why?" class="heading-anchor">#</a> Why?</h3>
<p>Enums are very close to "constant values". Even though <a href="https://wiki.php.net/rfc/enumerations">the RFC</a> showed them using PascalCase (inspired by other languages), it doesn't give a good reason for doing so.</p>
<p>Some people argue to use PascalCase for enums specifically to visually distinguish between constants and enums. I don't believe that relying on naming conventions to distinguish between concepts is a good idea. It's better to rely on your IDE's or editor's insights to know what something is, instead of holding onto a naming convention.</p>
<p>Ironically, uppercase constants exist because of the same reason: to distinguish them from normal variables. I want to acknowledge that fact, however there's little we can do to change decades of programming history. I think it's fair to say that the majority of PHP projects use uppercase constants, and so I would like to keep following that convention for closely related concepts, despite how the convention originated.</p>
<p>Nevertheless, I have tried using PascalCase for enums, but it always felt unnatural to me: I wrote my enum cases uppercase automatically, only to notice I did afterwards; meaning I had to go back and refactor them. I decided not to fight my instincts and just go with uppercase notation which feels the most natural to me, because of how constant values have been written for years, and how close enums are to constants anyway.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="2.-don't-overuse-backed-enums"><a href="#2.-don't-overuse-backed-enums" class="heading-anchor">#</a> 2. Don't overuse backed enums</h2>
<p>You should only use backed enums when you actually have a need for them. A common use case is serialization. If an enum is only going to be used within code, you shouldn't make it a backed enum.</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">PostState</span>: <span class="hl-type">string</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">PENDING</span> = '<span class="hl-value">pending</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span> = '<span class="hl-value">published</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">STARRED</span> = '<span class="hl-value">starred</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">DENIED</span> = '<span class="hl-value">denied</span>';
}
</pre>
<h3 id="why?"><a href="#why?" class="heading-anchor">#</a> Why?</h3>
<p>Manually assigning values to enums introduces maintenance overhead: you're not only maintaining the enum cases itself, but also their values. It's important to take into consideration when to add overhead, and when not.</p>
<p>On top of that: enums have their built-in <code>name</code> property that's always accessible in case you need a textual representation:</p>
<pre><span class="hl-type">Status</span>::<span class="hl-property">PUBLISHED</span>-&gt;<span class="hl-property">name</span>; <span class="hl-comment">// PUBLISHED</span>
</pre>
<p>When in doubt, apply this rule: do you need to create this enum from scalar values (from a database, from user input, …): use a backed enum. If the answer is "no" however, hold off assigning values until your use case requires it.</p>
<h2 id="3.-simple-match-methods-are-allowed"><a href="#3.-simple-match-methods-are-allowed" class="heading-anchor">#</a> 3. Simple match methods are allowed</h2>
<p>Enums shouldn't contain complex methods. Ideally, they only contain methods using the <code>match</code> expression that provide richer functionality for specific enum cases:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">label</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-variable">$this</span>) {
            <span class="hl-type">Status</span>::<span class="hl-property">DRAFT</span> =&gt; '<span class="hl-value">work in progress</span>',
            <span class="hl-type">Status</span>::<span class="hl-property">PUBLISHED</span> =&gt; '<span class="hl-value">published</span>',
            <span class="hl-type">Status</span>::<span class="hl-property">ARCHIVED</span> =&gt; '<span class="hl-value">archived</span>',
        };
    }
}
</pre>
<h3 id="why?"><a href="#why?" class="heading-anchor">#</a> Why?</h3>
<p>Enums shouldn't provide complex functionality, if you find yourself writing too much logic in your enums, you probably want to look into using the <a href="/blog/laravel-beyond-crud-05-states">state pattern</a> instead.</p>
<p>A good rule of thumb is that if it can fit into a <code>match</code> expression (without returning closures or callables or what not), you're good to go. Otherwise consider alternatives.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="4.-values-shouldn't-be-used-as-labels"><a href="#4.-values-shouldn't-be-used-as-labels" class="heading-anchor">#</a> 4. Values shouldn't be used as labels</h2>
<p>A backed enum's value should only be used as a value for (de)serialization, not for functionality like providing labels.</p>
<h3 id="why?"><a href="#why?" class="heading-anchor">#</a> Why?</h3>
<p>You might be tempted to rewrite the example from the previous point as follows:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span> = '<span class="hl-value">work in progress</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span> = '<span class="hl-value">published</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span> = '<span class="hl-value">archived</span>';
}
</pre>
<p>While shorter, you're now mixing two concerns into one: representing labels in a user-readable format, combined with their serialization value. The first one is very likely to change over time, the second one should stay unchanged as much as possible to prevent complex data migrations.</p>
<h2 id="5.-no-index-values"><a href="#5.-no-index-values" class="heading-anchor">#</a> 5. No index values</h2>
<p>You should only use integer backed enums when their values actually are integers, not to assign some notion of "order" or "indexing" to your enums.</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">VatPercentage</span>: <span class="hl-type">int</span> 
{
    <span class="hl-keyword">case</span> <span class="hl-property">SIX</span> = 6;
    <span class="hl-keyword">case</span> <span class="hl-property">TWELVE</span> = 12;
    <span class="hl-keyword">case</span> <span class="hl-property">TWENTY_ONE</span> = 21;
}

<span class="hl-keyword">enum</span> <span class="hl-type">Status</span>: <span class="hl-type">int</span> 
{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span> = 1;
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span> = 2;
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span> = 3;
}
</pre>
<h3 id="why?"><a href="#why?" class="heading-anchor">#</a> Why?</h3>
<p>It might be tempting to assign integer values to, for example, status enums where <code>DRAFT</code> comes before <code>PUBLISHED</code>, comes before <code>ARCHIVED</code>.</p>
<p>While such sequential indexing works in a limited amount of cases, it's a mess to maintain. What happens when you're required to add another state called <code>DENIED</code>? It should probably get the value <code>2</code> or <code>3</code>, meaning that you're stuck with data migrations for all published and archived entries.</p>
<p>When in doubt, you can again use the state pattern to model complex transitions between states and their order instead.</p>
<hr />
<p>Do you agree? Disagree? Let me know on <a href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">email</a>!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-05-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Attribute usage in top-1000 PHP packages ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/attribute-usage-in-top-php-packages"/>

                <id>https://www.stitcher.io/blog/attribute-usage-in-top-php-packages</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Attributes were originally <a href="/blog/attributes-in-php-8">introduced in PHP 8.0</a> two years ago. Yesterday, I came across an interesting <a href="https://www.exakat.io/en/adoption-of-php-8-attributes-in-2022/">post from Exakat</a>: they analysed 535 open source packages to see which attributes were used the most often.</p>
<p>However: they didn't share their raw data or absolute numbers, and they also didn't mention which packages were analysed exactly and how.</p>
<p>I think we can do better. So let's take a closer look at how attributes are used in the PHP open source community.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="setup"><a href="#setup" class="heading-anchor">#</a> Setup</h2>
<p>I used Nikita's <a href="https://github.com/nikic/popular-package-analysis">Popular Package Analyser</a>: it downloads the top-1000 packages from Packagist, and allows you to run analysis on them by writing simple PHP scripts.</p>
<p>In this case I looped over all PHP files, and scanned whether they contained attributes. You can <a href="https://gist.github.com/brendt/09026efba38a2eae952556aa274c268f">check out the full script here</a>.</p>
<p>A couple of remarks:</p>
<ul>
<li>This is a quick and dirty script, it gets the job done and that's all it should do.</li>
<li>I filtered out JetBrains packages, because they only contain stubs for IDE usage, and heavily skew the result: JetBrains' packages alone account for ±65% of the total attribute usage.</li>
<li>Matching is done with a simple regex, I believe I took every edge case into account: names with and without backslashes and multiline and single-line attributes. If you believe there's something missing, don't hesitate to <a href="mailto:brendt@stitcher.io">let me know</a>.</li>
<li>You can <a href="https://docs.google.com/spreadsheets/d/1-JvMJcpArIMYN6NMV5NFm1hbWYcNYg4-AGmDi-t6lsI/edit?usp=sharing">browse the raw data here</a>.</li>
<li>We should recognise the limits of this data set: client projects will probably use much more attributes compared to reusable packages. Think about Symfony's route attributes for example: they will only represent a very small share in this analysis, while it's reasonable to assume they are use significantly more in real projects.</li>
</ul>
<h2 id="the-most-popular-attribute"><a href="#the-most-popular-attribute" class="heading-anchor">#</a> The most popular attribute</h2>
<p>The first metric that stood out is that <code>#[\ReturnTypeWillChange]</code> outnumbers all others by far: out of <strong>2786 attributes in total</strong>, 1668 are either <code>#[\ReturnTypeWillChange]</code> or <code>#[ReturnTypeWillChange]</code>, that's <strong>almost 60% being <code>ReturnTypeWillChange</code> attributes</strong>.</p>
<p><a href="/resources/img/blog/attributes-stats/attributes.svg"><img src="/resources/img/blog/attributes-stats/attributes.svg" srcset="/resources/img/blog/attributes-stats/attributes-per-package.svg 0w" sizes="" alt=""></img></a></p>
<p>This attribute is the first built-in attribute in PHP, introduced in PHP 8.1, and meant to <a href="/blog/dealing-with-deprecations">deal with a newly added deprecation notice</a>. It was a design goal of the original attribute RFC to use them for these kinds of cases where we want userland code to communicate information to PHP's interpreter. In this case: to suppress a deprecation notice.</p>
<p>Speaking of the two variants (with and without a leading <code>\</code>): some developers import their attributes and others use the fully qualified class name: the latter option is by far the preferred one: out of <strong>1668 <code>ReturnTypeWillChange</code> usages</strong>, only <strong>524 imported</strong> the attribute — that's only <strong>31%</strong>. It seems that most developers like to use the FQCN variant.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="the-most-active-packages"><a href="#the-most-active-packages" class="heading-anchor">#</a> The most active packages</h2>
<p>Out of 997 packages, <strong>only 200 packages are using attributes</strong>. Out of those 200, Symfony, Drupal and Laravel have large pieces of the pie. Symfony is the leader here with <strong>9.6%</strong>: not unlikely caused by the fact that Symfony has been using docblock annotations for years.</p>
<p><a href="/resources/img/blog/attributes-stats/attributes-per-package.svg"><img src="/resources/img/blog/attributes-stats/attributes-per-package.svg" srcset="" sizes="" alt=""></img></a></p>
<h2 id="custom-attributes"><a href="#custom-attributes" class="heading-anchor">#</a> Custom attributes</h2>
<p>Another point of interest is the use of <code>#[Attribute]</code> and <code>#[\Attribute]</code>: representing custom attributes provided by packages themselves. In total there are <strong>561 custom attributes</strong> provided by these packages.</p>
<p>Looking on a per-package basis: <strong>Symfony provides 88 custom attributes</strong>, with PHPUnit providing 49, and doctrine's mongodb implementation providing 42. Again a clear example of how Symfony is an early adopter, thanks to them being used to docblock annotations for years. Interestingly, <strong>Laravel provides no custom attributes</strong>.</p>
<h2 id="multiline-attributes"><a href="#multiline-attributes" class="heading-anchor">#</a> Multiline attributes</h2>
<p>It's remarkable that there are no vendors using multiline attributes:</p>
<pre>#[
    <span class="hl-type">AsCommand</span>,
    <span class="hl-type">ReturnTypeWillChange</span>,
]
</pre>
<p>It makes sense that vendors opt for the single-line notation, since it's compatible with older PHP versions because these lines are treated like comments before PHP 8.0:</p>
<pre><span class="hl-attribute">#[<span class="hl-type">AsCommand</span>]</span>
<span class="hl-attribute">#[<span class="hl-type">ReturnTypeWillChange</span>]</span>
</pre>
<h2 id="conclusions"><a href="#conclusions" class="heading-anchor">#</a> Conclusions</h2>
<ul>
<li>Only <strong>20%</strong> of the top-1000 most popular packages use attributes</li>
<li>Only <strong>23%</strong> of the top-1000 most popular packages have PHP 8.0 or higher as their minimum required version</li>
<li>The <code>ReturnTypeWillChange</code> attribute is by far the most used one</li>
<li>
<strong>Symfony clearly is the frontrunner</strong>, embracing attributes thanks to experience with docblock annotations in the past</li>
<li>
<strong>Laravel provides no custom attributes</strong> for their users, although they use some internally, mostly the <code>AsCommand</code> attribute, which is provided by Symfony</li>
</ul>
<p>On a personal note: I'd say there's room for improvement. I think Laravel should start embracing custom attributes, especially since they now require PHP 8.0 as their minimum version.</p>
<p>What's your opinion? Let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">email</a>!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-05-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Dealing with deprecations ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/dealing-with-deprecations"/>

                <id>https://www.stitcher.io/blog/dealing-with-deprecations</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>You've probably dealt with them at one point your programming career:</p>
<pre>Deprecated: Creation of dynamic property Post::$name 
is deprecated in /in/4IreV on line 10
</pre>
<p>Deprecation notices 🤢</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Despite them being annoying and frustrating to many developers, they actually serve a purpose. I would even say you will appreciate them once you understand their goal, and how to deal with them. Let's take a look!</p>
<p>Oh, by the way: you can watch this blog post as a vlog if you prefer that:</p>
<iframe width="560" height="435" src="https://www.youtube.com/embed/9Kox9HQnLUg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="1.-deprecations-are-helpful"><a href="#1.-deprecations-are-helpful" class="heading-anchor">#</a> 1. Deprecations are helpful</h2>
<p>It's a common complaint: "why do my PHP scripts break with minor version updates??". And quite right: PHP has a tendency to add deprecation notices in minor releases, which tend to be audibly present when upgrading a project. Take for example <a href="/blog/new-in-php-81#internal-method-return-types-rfc">PHP 8.1</a>, where suddenly logs were filled with these kinds of warnings:</p>
<pre>Return type should either be compatible with 
IteratorAggregate::getIterator(): Traversable, 
or the #[ReturnTypeWillChange] attribute should be used 
to temporarily suppress the notice
</pre>
<p>It's important to understand what deprecations are about: they aren't errors, they are <em>notices</em>. They are a way of notifying PHP developers about a breaking change in the future. They want to warn you up front, to give you plenty of time to deal with that upcoming breaking change.</p>
<p>Of course, one could ask: are these breaking changes and fancy features really necessary? Do we <em>really</em> need to change internal return types like <code>IteratorAggregate::getIterator(): Traversable</code>, do we <em>really</em> need to <a href="/blog/new-in-php-82#deprecate-dynamic-properties-rfc">disallow dynamic properties</a>?</p>
<p>In my opinion — and it's shared by the majority of PHP internal developers — yes. We need to keep improving PHP, it needs to grow up further. And that sometimes means introducing a breaking change, like for example when internals add return types to built-in class methods: if you're extending <code>IteratorAggregate</code> in userland code, you will need to make some changes. The language needs to evolve.</p>
<p>Overall I'd say that, despite some of the annoyances that come with such an evolving language, it's for the better.</p>
<p>And luckily we have a mechanic like deprecation notices: they tell us that something will break in the future, but that we can still use it today. We can incrementally make changes and updates around our codebase.</p>
<h2 id="2.-deprecations-can-be-silenced"><a href="#2.-deprecations-can-be-silenced" class="heading-anchor">#</a> 2. Deprecations can be silenced</h2>
<p>Second, PHP internals go to great lengths to help userland developers in dealing with deprecations. Thanks to the addition of <a href="/blog/attributes-in-php-8">attributes in PHP 8.0</a>, we now have a much better and standardized way of communication between our code and PHP's interpreter.</p>
<p>For example: you can tag userland code with the <code>ReturnTypeWillChange</code> attribute in order to prevent deprecation notices being shown.</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">MyIterator</span> <span class="hl-keyword">implements</span><span class="hl-type"> </span>\IteratorAggregate
{
    #[<span class="hl-type">\ReturnTypeWillChange</span>]
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getIterator</span>()
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>Of course, this code will break in PHP 9.0, so while silencing deprecation notices is a short-term solution; you will need to fix them if you ever want to upgrade to the next major version:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">MyIterator</span> <span class="hl-keyword">implements</span><span class="hl-type"> </span>\IteratorAggregate
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getIterator</span>(): \Traversable
    {

    }
}
</pre>
<p>One more example maybe? With <a href="/blog/new-in-php-82#deprecate-dynamic-properties-rfc">dynamic properties being deprecated in PHP 8.2</a>, you can mark classes with the <code>AllowDynamicProperties</code> attribute, making it so that they allow dynamic properties again and suppress the deprecation notice:</p>
<pre>#[<span class="hl-type">\AllowDynamicProperties</span>]
<span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
}

<span class="hl-comment">// …</span>

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span> = '<span class="hl-value">Name</span>';
</pre>
<h2 id="3.-they-are-notices,-not-fatal-errors"><a href="#3.-they-are-notices,-not-fatal-errors" class="heading-anchor">#</a> 3. They are notices, not fatal errors</h2>
<p>PHP code will keep working just fine, even when parts of it trigger deprecation notices. Of course, you know by now that it's in your best interest to fix them if you ever want to upgrade to the next major version, but you don't need to do it right now. It's perfectly ok to upgrade your production projects and deal with deprecations notices over time.</p>
<p>I'd even recommend disabling deprecation notices on production altogether, or at least not show them to your end users:</p>
<pre><span class="hl-property">error_reporting</span>(<span class="hl-property">E_ALL</span> ^ <span class="hl-property">E_DEPRECATED</span>);
</pre>
<p>Maybe you can keep track of them using an external error tracker for the first months, to get a clear image of the places you'll need to fix those deprecations. But above all: deprecation notices shouldn't be blockers when upgrading to the latest minor PHP version.</p>
<h2 id="4.-automation"><a href="#4.-automation" class="heading-anchor">#</a> 4. Automation</h2>
<p>Lastly, keep in mind that you don't need to do the boring tasks by hand. There are tools like <a href="https://github.com/rectorphp/">Rector</a> and <a href="https://github.com/squizlabs/PHP_CodeSniffer/">phpcs</a> that can take care of many upgrading issues for you. Usually it's a matter of running a script that takes a couple of minutes at most to scan and fix your codebase. That's work that you might need days for if you'd do it by hand.</p>
<p>It's not difficult or time consuming anymore to deal with PHP upgrades. In fact, deprecations help tremendously to create a smoother upgrade path and prepare your codebase for the future.</p>
<p>I like deprecations, you should too.</p>
 ]]></summary>

                <updated>2022-05-18T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Dynamic Strategies ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/strategies"/>

                <id>https://www.stitcher.io/blog/strategies</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>Just a note up front: I wrote this post as a thought exercise, not as an absolute source of truth. I'd love to hear people disagree and tell me why, so don't hesitate to reply wherever you want.</em></p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>You've probably used the strategy pattern before: <a target="_blank" href="https://en.wikipedia.org/wiki/Strategy_pattern">a behavioral pattern that enables selecting an algorithm at runtime</a>.</p>
<p>Let's consider a classic example: the user provides some input either in the form of XML, JSON or an array; and we want that input to be parsed to a pretty JSON string.</p>
<p>So all these inputs:</p>
<pre>'{&quot;title&quot;:&quot;test&quot;}'
'&lt;title&gt;test&lt;/title&gt;'
['title' =&gt; 'test']
</pre>
<p>Would convert to this:</p>
<pre>{
    &quot;title&quot;: &quot;test&quot;
}
</pre>
<p>Oh, there's one more requirement: we need these strategies to be extensible. Developers should be allowed to add their own strategies for dealing with other kinds of inputs: YAML, interfaces, iterable objects, whatever they need.</p>
<p>Let's take a look at the classic solution, and its problems.</p>
<hr />
<p>Usually, we start by introducing some kind of interface that all strategies should implement:</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">ParserInterface</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">canParse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">bool</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>;
}
</pre>
<p>Each strategy must define whether it can run on a given input, and provide its actual implementation.</p>
<p>Next we can provide several implementations of that interface:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">ArrayParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">canParse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">is_array</span>(<span class="hl-variable">$input</span>);
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(<span class="hl-variable">$input</span>, <span class="hl-property">JSON_PRETTY_PRINT</span>);
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">JsonParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">canParse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> 
            <span class="hl-property">is_string</span>(<span class="hl-variable">$input</span>) 
            <span class="hl-operator">&amp;&amp;</span> <span class="hl-property">str_starts_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">{</span>') 
            <span class="hl-operator">&amp;&amp;</span> <span class="hl-property">str_ends_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">}</span>');
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(
            <span class="hl-property">json_decode</span>(<span class="hl-variable">$input</span>), 
            <span class="hl-type">JSON_PRETTY_PRINT</span>
        );
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">XmlParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">canParse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span>
            <span class="hl-property">is_string</span>(<span class="hl-variable">$input</span>) 
            <span class="hl-operator">&amp;&amp;</span> <span class="hl-property">str_starts_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">&lt;</span>') 
            <span class="hl-operator">&amp;&amp;</span> <span class="hl-property">str_ends_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">&gt;</span>');
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(
            <span class="hl-property">simplexml_load_string</span>(
                <span class="hl-variable">$input</span>, 
                &quot;<span class="hl-value">SimpleXMLElement</span>&quot;, 
                <span class="hl-type">LIBXML_NOCDATA</span>
            ), 
            <span class="hl-type">JSON_PRETTY_PRINT</span>
        );
    }
}
</pre>
<p>Full disclosure: these are very naive implementations. The strategy detection in the <code>canParse</code> method simply looks at the first and last character of the input string, and probably isn't fool-proof. Also: the XML decoding doesn't properly work; but it's good enough for the sake of this example.</p>
<p>The next step is to provide a class that developers can use as the public API, this one will use our different strategies underneath. It's configured by adding a set of strategy implementations, and exposes one <code>parse</code> method to the outside:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Parser</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">ParserInterface[] </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$parsers</span> = [];
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>() {
        <span class="hl-variable">$this</span>
            -&gt;<span class="hl-property">addParser</span>(<span class="hl-keyword">new</span> <span class="hl-type">ArrayParser</span>)
            -&gt;<span class="hl-property">addParser</span>(<span class="hl-keyword">new</span> <span class="hl-type">JsonParser</span>)
            -&gt;<span class="hl-property">addParser</span>(<span class="hl-keyword">new</span> <span class="hl-type">XmlParser</span>);
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addParser</span>(<span class="hl-injection"><span class="hl-type">ParserInterface</span> $parser</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">parsers</span>[] = <span class="hl-variable">$parser</span>;
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">parsers</span> <span class="hl-keyword">as</span> <span class="hl-variable">$parser</span>) {
            <span class="hl-keyword">if</span> (<span class="hl-variable">$parser</span>-&gt;<span class="hl-property">canParse</span>(<span class="hl-variable">$input</span>)) {
                <span class="hl-keyword">return</span> <span class="hl-variable">$parser</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$input</span>);
            }
        }
        
        <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">Exception</span>(&quot;<span class="hl-value">Could not parse given input</span>&quot;);
    }
}
</pre>
<p>And we're done, right? The user can now use our <code>Parser</code> like so:</p>
<pre><span class="hl-variable">$parser</span> = <span class="hl-keyword">new</span> <span class="hl-type">Parser</span>();

<span class="hl-variable">$parser</span>-&gt;<span class="hl-property">parse</span>('<span class="hl-value">{&quot;title&quot;:&quot;test&quot;}</span>');
<span class="hl-variable">$parser</span>-&gt;<span class="hl-property">parse</span>('<span class="hl-value">&lt;title&gt;test&lt;/title&gt;</span>');
<span class="hl-variable">$parser</span>-&gt;<span class="hl-property">parse</span>(['<span class="hl-value">title</span>' =&gt; '<span class="hl-value">test</span>']);
</pre>
<p>And the output will always be a pretty JSON string.</p>
<p>Well… let's take a look at it from the other side: a developer who wants to extend the existing parser with their own functionality: an implementation that transforms a <code>Request</code> class to a JSON string. We designed our parser with the strategy pattern for this exact reason; so, easy enough:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">RequestParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">canParse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$input</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Request</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>([
            '<span class="hl-value">method</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">method</span>,
            '<span class="hl-value">headers</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">headers</span>,
            '<span class="hl-value">body</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">body</span>,
        ], <span class="hl-property">JSON_PRETTY_PRINT</span>);
    }
}
</pre>
<p>And let's assume our parser is registered somewhere in an IoC container, we can add it like so:</p>
<pre><span class="hl-type">Container</span>::<span class="hl-property">singleton</span>(
    <span class="hl-type">Parser</span>::<span class="hl-keyword">class</span>,
    <span class="hl-keyword">fn</span> () =&gt; (<span class="hl-keyword">new</span> <span class="hl-type">Parser</span>)-&gt;<span class="hl-property">addParser</span>(<span class="hl-keyword">new</span> <span class="hl-type">RequestParser</span>);
);
</pre>
<p>And we're done!</p>
<p>Except… have you spotted the one issue? If you've used the strategy pattern in this way before (many open source packages apply it), you might already have an idea.</p>
<p>It's in our <code>RequestParser::parse</code> method:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
{
    <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>([
        '<span class="hl-value">method</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">method</span>,
        '<span class="hl-value">headers</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">headers</span>,
        '<span class="hl-value">body</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">body</span>,
    ], <span class="hl-property">JSON_PRETTY_PRINT</span>);
}
</pre>
<p>The problem here is that we have no clue about the actual type of <code>$input</code>. We know it should be a <code>Request</code> object because of the check in <code>canParse</code>, but our IDE of course doesn't know that. So we'll have to help it a little bit, either by providing a docblock:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@var</span> <span class="hl-type">mixed|Request</span> <span class="hl-variable">$input</span> 
 */</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
{
    <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>([
        '<span class="hl-value">method</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">method</span>,
        '<span class="hl-value">headers</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">headers</span>,
        '<span class="hl-value">body</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">body</span>,
    ], <span class="hl-property">JSON_PRETTY_PRINT</span>);
}
</pre>
<p>Or by doing the <code>instanceof</code> check again:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
{
    <span class="hl-keyword">if</span> (! <span class="hl-variable">$input</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Request</span>) {
        <span class="hl-comment">// error?</span>
    }
    
    <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>([
        '<span class="hl-value">method</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">method</span>,
        '<span class="hl-value">headers</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">headers</span>,
        '<span class="hl-value">body</span>' =&gt; <span class="hl-variable">$input</span>-&gt;<span class="hl-property">body</span>,
    ], <span class="hl-property">JSON_PRETTY_PRINT</span>);
}
</pre>
<p>So because of how we designed our <code>ParserInterface</code>, developers who want to implement it, will have to do double work:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">RequestParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">canParse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$input</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Request</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">if</span> (! <span class="hl-variable">$input</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Request</span>) {
            <span class="hl-comment">// error?</span>
        }
        
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>This kind of code duplication isn't the end of the world, at most it's a minor inconvenience. Most developers won't even bat an eye.</p>
<p>But I do. As a package maintainer, I want my public APIs to be as intuitive and frictionless as possible. To me, that means that static insights are a crucial part of the developer experience, and I don't want the users of my code to be hindered because of how I designed this parser.</p>
<p>So, let's discuss a couple of ways to fix this problem.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="no-more-duplication"><a href="#no-more-duplication" class="heading-anchor">#</a> No more duplication</h2>
<p>If the problem of duplication happens because we've split our <code>canParse</code> and <code>parse</code> methods, maybe the easiest solution is to simply… not split them?</p>
<p>What if we design our strategy classes in such a way that they will throw an exception if they can't parse it, instead of using an explicit conditional?</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">ParserInterface</span>
{
    <span class="hl-comment">/**
     * <span class="hl-value">@throws</span> CannotParse 
     *         When this parser can't parse 
     *         the given input. 
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>;
}

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">RequestParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">if</span> (! <span class="hl-variable">$input</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Request</span>) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">CannotParse</span>;
        }
        
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>Our generic parser class would change like so:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Parser</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">parsers</span> <span class="hl-keyword">as</span> <span class="hl-variable">$parser</span>) {
            <span class="hl-keyword">try</span> {
                <span class="hl-keyword">return</span> <span class="hl-variable">$parser</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$input</span>);
            } <span class="hl-keyword">catch</span> (<span class="hl-type">ParseException</span>) {
                <span class="hl-keyword">continue</span>;
            }
        }
        
        <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">Exception</span>(&quot;<span class="hl-value">Could not parse given input</span>&quot;);
    }
}
</pre>
<p>Of course, now we're opening up the rabbit hole of "what an exception is" and whether we're allowed to use exceptions to control our program flow in this way. My personal opinion is "yes, definitely"; because passing a string to a method that can only work with a <code>Request</code> object is in fact, an <em>exception</em> to the rule. At least, that's my definition.</p>
<p>Some people might opt for returning <code>null</code> instead of throwing an exception, although that feels more wrong to me: <code>null</code> doesn't communicate that this particular method wasn't able to handle the input. In fact, <code>null</code> could very well be a valid result from this parser, depending on its requirements. So no, no <code>null</code> for me.</p>
<p>However, I share the opinion that probably a couple of people have when reading this: either returning <code>null</code> or throwing an exception doesn't feel like the cleanest solution. If we're embarking on this journey for the sole purpose of fixing a detail that only a handful of developers might be bothered about, we might explore other options as well, and dive even deeper into the rabbit hole.</p>
<h2 id="types"><a href="#types" class="heading-anchor">#</a> Types</h2>
<p>We've written this manual check to guard against invalid input: <code>$input instanceof Request</code>; but did you know there's an automated way for PHP to do these kinds of checks? Its built-in type system! Why bother rewriting stuff manually that PHP can do for us behind the scenes? Why not simply type hint on <code>Request</code>?</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">RequestParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">Request</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>Well we can't, because of two problems:</p>
<ul>
<li>We're not allowed to narrow parameter types from <code>mixed</code> to <code>Request</code> according to the <a href="/blog/liskov-and-type-safety">Liskov Substitution Principle</a>, which is enforced by PHP and our <code>ParserInterface</code>; and</li>
<li>not every input can be represented as a dedicated type: both XML and JSON are strings, there's some ambiguity there.</li>
</ul>
<p>So, end of story? Well… we're already so deep into the rabbit hole, we might as well give it a shot.</p>
<p>Let's start by imagining that the two problems mentioned aren't an issue: could we in fact design our parser in such a way that it's able to detect each strategy's accepted input, and select the proper strategy based on that information?</p>
<p>We sure can! The most simple solution is to loop over all strategies, try to pass them some input and continue if they can't handle it; let PHP's type system handle the rest:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Parser</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">parsers</span> <span class="hl-keyword">as</span> <span class="hl-variable">$parser</span>) {
            <span class="hl-keyword">try</span> {
                <span class="hl-keyword">return</span> <span class="hl-variable">$parser</span>-&gt;<span class="hl-property">parse</span>(<span class="hl-variable">$input</span>);
            } <span class="hl-keyword">catch</span> (<span class="hl-type">TypeError</span>) {
                <span class="hl-keyword">continue</span>;
            }
        }
        
        <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">Exception</span>(&quot;<span class="hl-value">Could not parse given input</span>&quot;);
    }
}
</pre>
<p>I actually prefer this approach over any kind of runtime reflection trying to determine which method can accept which input. <strong>Let's not try to recreate PHP's type checker at runtime</strong>. The only real requirement for this approach to work is that your strategy methods won't have any side effects and that they'll always properly type hint their input. That's one of my personal cornerstones when programming, and so I have no problems writing code that assumes this principle.</p>
<p>Ok so it is possible to match any given input to its correct strategy based on its method signature. But we still need to deal with our two initial problems.</p>
<p>The first one is that we're not allowed to write this:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">RequestParser</span> <span class="hl-keyword">implements</span><span class="hl-type"> ParserInterface
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">Request</span> $input</span>): <span class="hl-type">mixed</span>
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>Because we defined the signature of <code>parse</code> in our <code>ParserInterface</code> like so:</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">ParserInterface</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">parse</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>;
}
</pre>
<p>We can't narrow down parameter types, we can only widen them; that's called <a href="/blog/liskov-and-type-safety">contravariance</a>.</p>
<p>So on the one hand we have an interface that says that our strategies can take <em>any</em> type of input (<code>mixed</code>); but on the other hand we have our strategy classes that tell us they can only work with a <em>specific</em> type of input.</p>
<p><em>If</em> we want to go further into the rabbit hole, then there's no other conclusion to make than that our interface isn't actually telling the truth: we're not making strategies that work with <em>any</em> kind of input, and so it doesn't make sense to have an interface tell us that we do. This interface is essentially telling a lie, and there's no reason to keep it.</p>
<p>Well, actually: there <em>is</em> a reason to have this interface: it guides a developer in understanding how they can add their own strategies, without having to rely on documentation. When a developer sees this method signature:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Parser</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addParser</span>(<span class="hl-injection"><span class="hl-type">ParserInterface</span> $parser</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">parsers</span>[] = <span class="hl-variable">$parser</span>;
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
}
</pre>
<p>It's clear to them that they'll need to implement <code>ParserInterface</code> for their custom strategies to work. So I'd say that getting rid of this interface might do more harm than good, because without it, developers are operating in the dark.</p>
<p>There is <em>one</em> solution that I can think of that can counter this problem: accepting callables.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addParser</span>(<span class="hl-injection"><span class="hl-type">callable</span> $parser</span>): <span class="hl-type">self</span>
{
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">parsers</span>[] = <span class="hl-variable">$parser</span>;
    
    <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
}
</pre>
<p><code>callable</code> is a <em>special</em> type in PHP, because it doesn't only cover functions and closures, but also invokable objects. The only real thing missing here is that we can't tell — with certainty — from our code what our callables should look like.</p>
<p>We've established a rule saying that it should accept any kind of input that it can work with, but there's no way we can tell developers extending our code that, without providing an additional docblock. This is definitely a downside of this approach, and might be reason enough for you not to go with it.</p>
<p>I personally don't mind, I think the code duplication we had in the beginning and manual type validation annoys me more than having to read a docblock:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@param</span> <span class="hl-type">callable</span> <span class="hl-variable">$parser</span> A callable accepting one typed parameter.
 *                         This parameter's type is used to match 
 *                         the input given to the parser to the
 *                         correct parser implementation.
 */</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addParser</span>(<span class="hl-injection"><span class="hl-type">callable</span> $parser</span>): <span class="hl-type">self</span>
{
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">parsers</span>[] = <span class="hl-variable">$parser</span>;
    
    <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
}
</pre>
<p>Then there's our second problem: not everything can be represented by a type. For example: both JSON and XML parsers should match on a <code>string</code> of either JSON or XML, and we can't type hint those. I can think of two solutions.</p>
<ul>
<li>Do some manual checks in the <code>parse</code> method for these edge cases, and throw an <code>TypeError</code> when they don't match; or</li>
<li>introduce <code>JsonString</code> and <code>XmlString</code> as custom classes, and have a factory first convert those raw strings to their proper types.</li>
</ul>
<p>The first option would look like this:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">JsonParser</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">string</span> $input</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">if</span> (
            ! <span class="hl-property">str_starts_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">{</span>') 
            <span class="hl-operator">||</span> ! <span class="hl-property">str_ends_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">}</span>')
        ) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">TypeError</span>(&quot;<span class="hl-value">Not a valid JSON string</span>&quot;);   
        }
        
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(
            <span class="hl-property">json_decode</span>(<span class="hl-variable">$input</span>), 
            <span class="hl-type">JSON_PRETTY_PRINT</span>
        );
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">XmlParser</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">string</span> $input</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">if</span> (
            ! <span class="hl-property">str_starts_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">&lt;</span>') 
            <span class="hl-operator">||</span> ! <span class="hl-property">str_ends_with</span>(<span class="hl-property">trim</span>(<span class="hl-variable">$input</span>), '<span class="hl-value">&gt;</span>')
        ) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">TypeError</span>(&quot;<span class="hl-value">Not a valid XML string</span>&quot;);
        }
        
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(
            <span class="hl-property">simplexml_load_string</span>(
                <span class="hl-variable">$input</span>, 
                &quot;<span class="hl-value">SimpleXMLElement</span>&quot;, 
                <span class="hl-type">LIBXML_NOCDATA</span>
            ), 
            <span class="hl-type">JSON_PRETTY_PRINT</span>
        );
    }
}
</pre>
<p>The second one, having a custom class for <code>JsonString</code> and <code>XmlString</code>, would look something like this:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">JsonParser</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">JsonString</span> $input</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(
            <span class="hl-property">json_decode</span>(<span class="hl-variable">$input</span>), 
            <span class="hl-type">JSON_PRETTY_PRINT</span>
        );
    }
}

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">XmlParser</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">XmlString</span> $input</span>): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(
            <span class="hl-property">simplexml_load_string</span>(
                <span class="hl-variable">$input</span>, 
                &quot;<span class="hl-value">SimpleXMLElement</span>&quot;, 
                <span class="hl-type">LIBXML_NOCDATA</span>
            ), 
            <span class="hl-type">JSON_PRETTY_PRINT</span>
        );
    }
}
</pre>
<p>But don't forget that we'd also need to introduce a factory to convert a string to its proper type, which means quite a lot of overhead.</p>
<p>On a final note, <code>callable</code> has another advantage: users aren't bound to using invokable classes. Depending on their needs and how they test, they could get away with simply adding closures:</p>
<pre><span class="hl-type">Container</span>::<span class="hl-property">singleton</span>(
    <span class="hl-type">Parser</span>::<span class="hl-keyword">class</span>,
    <span class="hl-keyword">fn</span> () =&gt; (<span class="hl-keyword">new</span> <span class="hl-type">Parser</span>)-&gt;<span class="hl-property">addParser</span>(
        <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Request</span> $request</span>) =&gt; <span class="hl-property">json_encode</span>([
            '<span class="hl-value">method</span>' =&gt; <span class="hl-variable">$request</span>-&gt;<span class="hl-property">method</span>,
            '<span class="hl-value">headers</span>' =&gt; <span class="hl-variable">$request</span>-&gt;<span class="hl-property">headers</span>,
            '<span class="hl-value">body</span>' =&gt; <span class="hl-variable">$request</span>-&gt;<span class="hl-property">body</span>,
        ], <span class="hl-property">JSON_PRETTY_PRINT</span>)
    );
);
</pre>
<hr />
<p>Are there downsides to this approach? Definitely. Just like there are downsides to the original solution where we had lots of code duplication. I personally think that, from a developer experience point of view; it's worth considering alternatives to the original way of how we implement dynamic strategies; and I can imagine some projects benefiting from it.</p>
<p>What do you think? Let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">email</a>; don't hesitate to say I'm slowly going crazy if you think so!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-04-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Goodbye ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/goodbye"/>

                <id>https://www.stitcher.io/blog/goodbye</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <iframe width="560" height="420" src="https://www.youtube.com/embed/R9xTgaRzAQs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>I've got some important news: today marked my last day working at Spatie and I will start working at JetBrains in the PhpStorm team on Monday. I want to talk about that.</p>
<p>You might be wondering what happened. I actually didn't plan on leaving Spatie originally; I wasn't looking for a new job. It was back in September last year, that I was told about the PhpStorm team looking for a developer advocate; and that felt like an opportunity I couldn't pass.</p>
<p>If you'd ask me to describe my dream job, I would probably tell you it would focus on the PHP community, content creation and education; and this is everything my new job at JetBrains is focussed on. So, I don't think this comes as a surprise to anyone, and I think you'll understand why I made this decision.</p>
<p>I'll of course miss my colleagues at Spatie — I spent almost 5 years with them — but I'm also ready and very excited about this new adventure; I'll keep you posted!</p>
<h2 id="what-about-my-blog,-videos-and-newsletter?"><a href="#what-about-my-blog,-videos-and-newsletter?" class="heading-anchor">#</a> What about my blog, videos and newsletter?</h2>
<p>Nothing much will change: I'll keep working on my blog and other personal projects in my free time; like I have been doing for the past years. I do find more creative energy in making videos over blog posts at the moment though, but I don't have any long term plans. I'll just keep doing what I like at the moment.</p>
<h2 id="what-about-open-source?"><a href="#what-about-open-source?" class="heading-anchor">#</a> What about open source?</h2>
<p>I've written quite a lot of open source code at Spatie, and I'm happy to help maintain it. It's actually an important part of my new job to keep programming, just to keep in touch with the language. So while I won't work any more on client projects like I used to, I will keep writing PHP.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-03-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The case for PHP generics ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/generics-in-php-4"/>

                <id>https://www.stitcher.io/blog/generics-in-php-4</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I started <a href="https://stitcher.io/blog/generics-in-php-1">this series</a> by saying it’s not just about teaching you, it’s also about making my case for what I think is the most viable and the most logical path to adding generics in PHP.</p>
<p>It’s up to you to decide after this video whether you agree or not. So, your honor, I’d like to start my closing statements.</p>
<div class="sidenote">
<div class="center">
    <a href="https://www.youtube.com/watch?v=2o8A9AgccKs&list=PL0bgkxUS9EaKyOugEDffRzsvupBE2YEoD&index=4&ab_channel=BrentRoose" target="_blank" rel="noopener noreferrer">
        <img class="small" src="/resources/img/static/generics-thumb-4.png">
        <p><em class="center small">You can watch the video instead of reading a blog post — if you prefer that!</em></p>
    </a>
</div>
</div>
<p>Adding <a href="/blog/generics-in-php-3">monomorphized or reified generics</a> won’t happen. At least not according to Nikita who did an extensive amount of research on the topic. Both options either pose performance problems or simply require too much core code refactoring of PHP’s runtime type checker to be achievable within a reasonable amount of time.</p>
<p>However, if we think about the true value that generics bring, it’s not about runtime type checks. By the time PHPs runtime type checker kicks in and possibly throws a type error, we’re already running our code. Our program will crash. And I’ve never heard any user of my programs say “oh, it’s a type error, it’s ok”. No. The program crashed, and that’s the end of story.</p>
<p>Runtime type checks in PHP are a very useful debugging tool, I give you that, and in some cases required for type juggling. But most of the value of PHP’s type system comes from static analysis.</p>
<p>So, if we want generics in PHP we need a mind shift:</p>
<p>First, developers need to <strong>embrace static analysis</strong>. The irony here is that developers who want generics and understand their value, also understand the value of static type checkers. So while there is a group of PHP developers who don’t care about static analysis, they also shouldn’t care about the value that generics bring. Because, these two: generics and static type checking, simply cannot be separated.</p>
<p>Second, if PHP internals decide that statically checked generics have their place in PHP; they should wonder whether static analysis should be left as a responsibility with the community, or whether they should play a role in it. Either by creating <strong>a specification</strong> that every static analyser should follow, or by shipping their <strong>own static type checker</strong>. The second one would definitely be preferable, but you can imagine what an undertaking that would be. I don’t think that relying on proven third part tools should be an issue.</p>
<p>Third, <strong>type juggling simply wouldn’t be possible anymore</strong>, at least not when using generics. You’d have to trust your static type checker. This is a way of programming that PHP developers aren’t really used to, but many other languages do exactly this, and it works fine. A static type checker is incredibly powerful and accurate. I can imagine it’s difficult for PHP developers to understand the power of statically typed languages without having used one before. It’s worth looking into a language like Rust, Java, or even TypeScript, just to appreciate the power of static type systems. Or you could start using one of PHP’s third party static analysers: Psalm or PHPStan.</p>
<p>To summarize: if we want generics in PHP, with all the benefits they bring to static analysis, we need to accept the fact that runtime erased generics are the only viable path.</p>
<p>In closing, a few more remarks I’d address.</p>
<p>First there’s the argument that what I’m describing is already possible with docblocks. If you go back to the <a href="/blog/generics-in-php-2">second post in this series</a>, you’ll find me explaining the differences in detail, but let me quickly summarize:</p>
<ul>
<li>Docblocks don’t communicate the same importance to developers as built-in syntax does, which is also why we got attributes in PHP 8; built-in syntax has a value over docblocks</li>
<li>And, also, there’s no official specification of what generic annotations should look like when using doc blocks. That’s a big issue today, with all three major static analysers having slightly different implementations.</li>
</ul>
<p>A second remark is that, even with type erasure, we could still expose generic type information via the reflection API. I’m not saying that the type information should be completely gone at runtime, my foremost concern is that PHP shouldn’t check generic types at runtime. I’m not sure what the impact would be on PHP’s core to have generic type information available via reflection; so I’m just putting it out there that I’m not against that idea.</p>
<p>And finally, there is of course another solution. One that anyone could pursue in theory. One that has proven itself in the past: TypeScript. It could be possible for <a href="https://www.youtube.com/watch?v=kVww3uk7HMg&amp;list=PL0bgkxUS9EaKyOugEDffRzsvupBE2YEoD&amp;index=5&amp;ab_channel=BrentRoose">a superset of PHP</a> to exist that compiles to normal PHP, and while compiling doing lots of type checks and other cool stuff. TypeScript is immensely popular, and I think that if there’s room for a similar approach in serverside languages, PHP is probably a good candidate. However, TypeScript didn’t just magically appear overnight. It was created by experienced language designers, it’s magnitudes larger than adding runtime-ignored generics in PHP. But who knows, maybe one day.</p>
<p>With all of that being said, I hope that you found this series useful and educational; I said everything I wanted to about generics. I’d appreciate it if you shared this series with your colleagues and followers — I believe it’s an important topic and I want to see things change.</p>
<p>I rest my case.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-03-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Why we can&#039;t have generics in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/generics-in-php-3"/>

                <id>https://www.stitcher.io/blog/generics-in-php-3</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>We’re going to take a deep dive in what’s going on behind the scenes when it comes to generics and PHP. It’s super interesting, and very important to understand why generics aren’t supported yet as first-class citizens in PHP.</p>
<p>Let’s get started.</p>
<div class="sidenote">
<div class="center">
    <a href="https://www.youtube.com/watch?v=BN0L2MBkhNg&list=PL0bgkxUS9EaKyOugEDffRzsvupBE2YEoD&index=3&ab_channel=BrentRoose" target="_blank" rel="noopener noreferrer">
        <img class="small" src="/resources/img/static/generics-thumb-3.png">
        <p><em class="center small">You can watch the video instead of reading a blog post — if you prefer that!</em></p>
    </a>
</div>
</div>
<p>Generics aren’t coming to PHP. That was <a href="https://www.reddit.com/r/PHP/comments/j65968/ama_with_the_phpstorm_team_from_jetbrains_on/g7zg9mt/">Nikita’s conclusion</a> last year. It simply wasn’t doable.</p>
<p>To understand why Nikita said that, we need to look at how generics could be implemented. In general, there are three possible ways to do so; programming languages that do support generics mostly use one of these three methods.</p>
<p>The first one is called <strong>Monomorphized Generics</strong>. Let’s go back to the first post of this series where I showed this collection example:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">StringCollection</span> <span class="hl-keyword">extends</span> <span class="hl-type">Collection</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $key</span>): <span class="hl-type">string</span> 
    { <span class="hl-comment">/* … */</span> }
}

<span class="hl-keyword">class</span> <span class="hl-type">UserCollection</span> <span class="hl-keyword">extends</span> <span class="hl-type">Collection</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $key</span>): <span class="hl-type">User</span> 
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>I explained that we could manually create implementations of the collection class for each type that we needed a collection for. It would be lots of manual work, there’d be lots of code, but it would work.</p>
<p>Monomorphized generics do exactly this, but in an automated way, behind the scenes. At runtime, PHP would not know about the generic Collection class, but rather about two or more specific implementations:</p>
<pre><span class="hl-variable">$users</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>&lt;User&gt;();
<span class="hl-comment">// Collection_User</span>

<span class="hl-variable">$slugs</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>&lt;string&gt;();
<span class="hl-comment">// Collection_string</span>
</pre>
<p>Monomorphized generics are a totally valid approach. Rust, for example, uses them. One advantage is that there are a bunch of performance gains, because there are no more generic type checks at runtime, it’s all split apart before running the code.</p>
<p>But that immediately brings us to the problem with monomorphized generics in PHP. PHP doesn’t have an explicit compilation step like Rust to split one generic class into several specific implementations; and, on top of that: monomorphized generics do require quite a lot of memory, because you’re making several copies of the same class with a few differences. That might not be as big an issue for a compiled Rust binary, but it is a serious concern for PHP code being run from a central point, the server; maybe serving hundreds or thousands of requests per second.</p>
<p>The next option is <strong>Reified Generics</strong>. This is an implementation where the generic class is kept as-is, and type information is evaluated on the fly, at runtime. C# and Kotlin have reified generics, and it’s the closest to PHP’s current type system, because PHP does all its type checks at runtime. The problem here is that it would require an immense amount of core code refactoring for reified generics to work, and you can imagine some performance overhead creeping in, as we’re doing more and more type checks at runtime.</p>
<p>That brings us to the last option: completely ignore generics at runtime. Act like they are not there; after all, a generic implementation of, for example, a collection class would work with every kind of input anyway.</p>
<p>So if we ignore all generic type checks at runtime, there aren’t any problems.</p>
<p>Well, not so fast. Ignoring generic types at runtime — it’s called <strong>type erasure</strong> by the way, Java and Python do it — it poses some problems for PHP.</p>
<p>For one: PHP not only uses types for validation, it also uses type information to convert values on the fly from one type to another — that’s the type juggling I mentioned in the first post of this series:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">add</span>(<span class="hl-injection"><span class="hl-type">int</span> $a, <span class="hl-type">int</span> $b</span>): <span class="hl-type">int</span> 
{
    <span class="hl-keyword">return</span> <span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>;
}

<span class="hl-property">add</span>('<span class="hl-value">1</span>', '<span class="hl-value">2</span>') <span class="hl-comment">// 3;</span>
</pre>
<p>If PHP ignored the generic type of this “string” collection, and we’d accidentally add an integer to it, it wouldn’t be able to warn us about that, if the generic type was erased:</p>
<pre><span class="hl-variable">$slugs</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>&lt;<span class="hl-generic">string</span>&gt;();

<span class="hl-variable">$slugs</span>[] = 1; <span class="hl-comment">// 1 won't be cast to '1'</span>
</pre>
<p>The second, and more important problem with type erasure — maybe you’re already yelling it at your screen by now — is that the types are gone. Why would we add generic types, if they are erased at runtime?</p>
<p>It makes sense in Java and Python, because all type definitions are checked before running the code using a static analyser. Java for example runs a built-in static analyser when compiling code; something that PHP simply doesn’t do: there is no compilation step, and there certainly isn’t a built-in static type checker.</p>
<p>On the other hand… all the advantages of type checking, the ones we discussed in the previous posts; they don’t come from PHP’s built-in runtime typechecker. By the time PHP’s type checker tells us something is wrong, we’re already running the code. A type error essentially crashes our program.</p>
<p>Instead, most of the added value of type checks comes from static analysers that don’t require us to run our code. They are pretty good at making sure there can be no runtime type errors, as long as you, the programmer, provide enough type information. That doesn’t mean there can’t be any bugs in your code, but it is possible to write PHP code that’s completely statically checked and doesn’t produce any type errors while running. And on top of that: there are all the static insights that we get while writing code; that’s by far the most valuable part of any type system, and has nothing to do with runtime type checks.</p>
<p>So do we actually need runtime type checks? Because that’s the main reason why generics can’t be added in PHP today: it’s either too complex or too resource intensive for PHP to validate generic types at runtime.</p>
<p>That’s next time, in the last post of this series.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-03-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Generics in depth ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/generics-in-php-2"/>

                <id>https://www.stitcher.io/blog/generics-in-php-2</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I showed a very boring example of generics in the <a href="/blog/generics-in-php-1">previous post</a>, we’re going to do better in this one.</p>
<pre><span class="hl-variable">$users</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>&lt;<span class="hl-generic">User</span>&gt;();

<span class="hl-variable">$slugs</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>&lt;<span class="hl-generic">string</span>&gt;();
</pre>
<p>Collections; they are probably the easiest way to explain what generics are about, but they also are the example that everyone talks about when discussing generics. It’s actually not uncommon for people to think that “generics” and “collections with a type” are the same thing. That’s definitely not the case.</p>
<p>So let’s take a look at two more examples.</p>
<div class="sidenote">
<div class="center">
    <a href="https://www.youtube.com/watch?v=5CwOuHCp29I&list=PL0bgkxUS9EaKyOugEDffRzsvupBE2YEoD&index=2&ab_channel=BrentRoose" target="_blank" rel="noopener noreferrer">
        <img class="small" src="/resources/img/static/generics-thumb-2.png">
        <p><em class="center small">You can watch the video instead of reading a blog post — if you prefer that!</em></p>
    </a>
</div>
</div>
<p>Here’s a function called <code>app</code> — if you work with a framework like Laravel, it might look familiar: this function takes a class name, and will resolve an instance of that class using the dependency container:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">app</span>(<span class="hl-injection"><span class="hl-type">string</span> $className</span>): <span class="hl-type">mixed</span>
{
    <span class="hl-keyword">return</span> <span class="hl-type">Container</span>::<span class="hl-property">get</span>(<span class="hl-variable">$className</span>);
}
</pre>
<p>Now, you don’t need to know how the container works, what’s important is that this function will give you an instance of the class that you request.</p>
<p>So, basically, it’s a generic function; one whose return type will depend on what kind of class name you gave it. And it would be cool if our IDE and other static analysers also understand that if I give the classname “UserRepository” to this function, I expect an instance of UserRepository to be returned, and nothing else:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">app</span>(<span class="hl-injection"><span class="hl-type">string</span> $className</span>): <span class="hl-type">mixed</span>
{ <span class="hl-comment">/* … */</span> }

<span class="hl-property">app</span>(<span class="hl-type">UserRepository</span>::<span class="hl-keyword">class</span>); <span class="hl-comment">// ?</span>
</pre>
<p>Well, generics allow us to do that.</p>
<p>And I guess this is a good time to mention that I’ve been keeping a secret, kind of: I <a href="/blog/generics-in-php-1">previously said</a> that generics don’t exist in PHP; well, that’s not entirely true. All static analysers out there — the tools that read your code without running it, tools like your IDE — they have agreed to use doc block annotation for generics:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@template</span> <span class="hl-generic">Type</span>
 * <span class="hl-value">@param</span> <span class="hl-type">class-string&lt;<span class="hl-generic">Type</span>&gt;</span> <span class="hl-variable">$className</span>
 * <span class="hl-value">@return</span> <span class="hl-type"><span class="hl-generic">Type</span></span>
 */</span>
<span class="hl-keyword">function</span> <span class="hl-property">app</span>(<span class="hl-injection"><span class="hl-type">string</span> $className</span>): <span class="hl-type">mixed</span>
{ <span class="hl-comment">/* … */</span> }
</pre>
<p>Granted: it’s not the most pretty syntax, and all static analysers are relying on a simple agreement that this is the syntax — there’s no official specification; but nevertheless: it works. PhpStorm, Psalm and PhpStan — those are the three largest static analysers in the PHP world — understand this syntax to some degree.</p>
<p>IDEs like PhpStorm use it to give the programmer feedback when they are writing code, and tools like Psalm and PhpStan use it to analyse your codebase in bulk and detect potential bugs, mostly based on type definitions.</p>
<p>So actually, we can build this <code>app</code> function in such a way that our tools aren’t operating in the dark anymore. Of course, there’s no guarantee by PHP itself that the return type will be the correct one — PHP won’t do any runtime type checks for this function; but if we can trust our static analysers to be right, there’s very little — or even no chance of this code breaking when running it.</p>
<p>This is the incredible power of static analysis: we can actually be sure that, without running our code; most of it will work as intended. All of that thanks to types — including generics.</p>
<p>Let’s look at an even more complex example:</p>
<pre><span class="hl-type">Attributes</span>::<span class="hl-property">in</span>(<span class="hl-type">MyController</span>::<span class="hl-keyword">class</span>)
    -&gt;<span class="hl-property">filter</span>(<span class="hl-type">RouteAttribute</span>::<span class="hl-keyword">class</span>)
    -&gt;<span class="hl-property">newInstance</span>()
    -&gt;
</pre>
<p>Here we have a class that can “query” attributes and instantiate them on the fly. If you’ve worked with attributes before you know that their reflection API is rather verbose, so I find this kind of helper class very useful.</p>
<p>When we use the <code>filter</code> method, we give it an attribute’s class name; and afterwards calling the <code>newInstance</code> method, we know that the result will be an instance of our filtered class. And again: it would be nice if our IDE understood what we’re talking about.</p>
<p>You guessed it: generics allow us to do that:</p>
<pre><span class="hl-comment">/** <span class="hl-value">@template</span> <span class="hl-generic">AttributeType</span> */</span>
<span class="hl-keyword">class</span> <span class="hl-type">Attributes</span>
{
    <span class="hl-comment">/**
     * <span class="hl-value">@template</span> <span class="hl-generic">InputType</span>
     * <span class="hl-value">@param</span> <span class="hl-type">class-string&lt;<span class="hl-generic">InputType</span>&gt;</span> <span class="hl-variable">$className</span>
     * <span class="hl-value">@return</span> <span class="hl-type">self&lt;<span class="hl-generic">InputType</span>&gt;</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">filter</span>(<span class="hl-injection"><span class="hl-type">string</span> $className</span>): <span class="hl-type">self</span>
    { <span class="hl-comment">/* … */</span> }
 
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">AttributeType </span>
     */</span>   
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">newInstance</span>(): <span class="hl-type">mixed</span>
    { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>I hope you start to see how powerful simple type information can be. A couple of years ago, I would have needed an IDE plugin for these kinds of insights to work, now I just need to add some type information.</p>
<p>This latest example doesn’t only rely on generics though, there’s another equally important part that’s in play. Type inference: the ability of a static analyser to “guess” — or reliably determine — a type without the user specifying it. That’s what’s happening with that class-string annotation over there. Our IDE is able to recognise the input we give this function as a class name, and infer that type as the generic type.</p>
<p>So, everything’s solved, right: generics are available in PHP and all major static analysers know how to work with them. Well… there’s a couple of caveats.</p>
<p>First of, there’s no official spec of what generics should look like, right now every static analyser could push its own syntax; they happen to have agreed on one, for now; but there are little future guarantees.</p>
<p>Second: doc blocks are, in my opinion, suboptimal. They feel like a less important part of our codebase. And granted: generic annotations only provide static insights and no runtime functionality, but we’ve seen how powerful static analysis can be, even without runtime type checks. I think it’s unfair to treat type information as “doc comments”, it doesn’t communicate the importance of those types within our code. That’s why we got attributes in PHP 8: all functionality that attributes provide, was already possible with docblock annotations, but that just didn’t feel good enough. The same goes for generics.</p>
<p>And finally: without a proper specification, all three major static analysers have differences between their generics implementations. PhpStorm being the one most lacking at the moment. Ideally, there would be an official specification coming from PHP’s internals. Right now, there isn’t.</p>
<p>These are the main reasons why I believe that it’s worth investing time in a more permanent and sustainable solution. So why doesn’t PHP have proper generics yet? Why do we rely on doc blocks without a clear specification?</p>
<p>That’s for the <a href="/blog/generics-in-php-3">next post</a>!</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-03-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Generics in PHP: The basics ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/generics-in-php-1"/>

                <id>https://www.stitcher.io/blog/generics-in-php-1</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Generics in PHP. I know I’d want them. And I know a lot of developers who agree. On the other hand, there is a group of PHP programmers, maybe even larger, that say they don’t know what generics are, or why they should care.</p>
<p>I’m going to do a series on this blog about generics and PHP. We’ll start from the beginning, but quickly work our way to the more complex topics. We’ll talk about what generics are, why PHP doesn’t support them, and what’s possible in the future.</p>
<p>Let’s get started.</p>
<div class="sidenote">
<div class="center">
    <a href="https://www.youtube.com/watch?v=c8hQ1fWU_mQ&list=PL0bgkxUS9EaKyOugEDffRzsvupBE2YEoD&index=1&ab_channel=BrentRoose" target="_blank" rel="noopener noreferrer">
        <img class="small" src="/resources/img/static/generics-thumb-1.png">
        <p><em class="center small">You can watch the video instead of reading a blog post — if you prefer that!</em></p>
    </a>
</div>
</div>
<p>Every programming language has some kind of type system. Some languages have a very strict implementation, while others — PHP falls in this category — are much more lenient.</p>
<p>Now, type systems are used for a variety of reasons; the most obvious one is <strong>type validation</strong>.</p>
<p>Let’s imagine we have a function that takes two numbers, two integers; and does some kind of maths operation on them:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">add</span>(<span class="hl-injection">$a, $b</span>) 
{
    <span class="hl-keyword">return</span> <span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>;
}
</pre>
<p>PHP will happily allow you to pass any kind of data to that function, numbers, strings, booleans, doesn’t matter. PHP will try its best to convert a variable whenever it makes sense, like for example adding them together.</p>
<pre><span class="hl-property">add</span>('<span class="hl-value">1</span>', '<span class="hl-value">2</span>');
</pre>
<p>But those conversions — type juggling — often lead to unexpected results, if not to say: bugs and crashes.</p>
<pre><span class="hl-property">add</span>([], <span class="hl-keyword">true</span>); <span class="hl-comment">// ?</span>
</pre>
<p>Now, we could manually write code to check whether our maths addition will work with any given input:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">add</span>(<span class="hl-injection">$a, $b</span>) 
{
    <span class="hl-keyword">if</span> (!<span class="hl-property">is_int</span>(<span class="hl-variable">$a</span>) <span class="hl-operator">||</span> !<span class="hl-property">is_int</span>(<span class="hl-variable">$b</span>)) {
        <span class="hl-keyword">return</span> <span class="hl-keyword">null</span>;
    }
    
    <span class="hl-keyword">return</span> <span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>;
}
</pre>
<p>Or we could make use of PHPs built-in type hints — built-in shorthands for what we’d otherwise do manually:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">add</span>(<span class="hl-injection"><span class="hl-type">int</span> $a, <span class="hl-type">int</span> $b</span>): <span class="hl-type">int</span> 
{
    <span class="hl-keyword">return</span> <span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>;
}
</pre>
<p>Many developers in the PHP community say they don’t really care about these type hints because they know they should only pass integers to this function — they wrote it, after all.</p>
<p>However, that kind of reasoning quickly falls apart: you’re often not the only one working in that codebase, you’re also using code that you haven’t written yourself — think about how many packages you’re pulling in with composer. And so, while this example in isolation might not seem to be that big a deal, type checking does come in handy once your code starts to grow.</p>
<p>Besides that, adding type hints not only guards against invalid state, but they also <strong>clarify</strong> what kind of input is expected from us, programmers. Types often make it so that you don’t need to read external documentation, because much of what a function does is already encapsulated by its type definition.</p>
<p>IDEs make heavy use of this principle: they can tell the programmer what kind of input is expected by a function or what fields and methods are available on an object — because it belongs to a class. IDEs make our code writing so much more productive, in large part because they can statically analyse type hints across our codebase.</p>
<p>Keep that word in mind: <strong>static analysis</strong> — it’s going to be very important later in this series. It means that programs, IDEs or other kinds of “static analysers” can look at our code, and without running it tell us whether it will work or not — at least, to some degree. If we’re passing a string to our function that takes an integer, our IDE will tell us we’re doing something wrong — something that would lead to a crashing program at runtime; but our IDE is able to tell us without having to actually run the code.</p>
<p>On the other hand, type systems have their limitations. A common example is a “list of items”:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Collection</span> <span class="hl-keyword">extends</span> <span class="hl-type">ArrayObject</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $key</span>): <span class="hl-type">mixed</span> 
    { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">filter</span>(<span class="hl-injection"><span class="hl-type">Closure</span> $fn</span>): <span class="hl-type">self</span> 
    { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">map</span>(<span class="hl-injection"><span class="hl-type">Closure</span> $fn</span>): <span class="hl-type">self</span> 
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>A collection has a bunch of methods that work with any kind of input: looping, filtering, mapping, you name it; a collection implementation shouldn’t care about whether it’s dealing with strings or integers.</p>
<p>But let’s look at it from an outsider’s perspective. What happens if we want to be sure that one collection only contains strings, and another one only contains <code>User</code> objects. The collection itself doesn’t care when looping over its items, but we do. We want to know whether this item in a loop is a User or a string — that’s quite the difference. But without proper type information, our IDE is operating in the dark.</p>
<pre><span class="hl-variable">$users</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>();

<span class="hl-comment">// …</span>

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$users</span> <span class="hl-keyword">as</span> <span class="hl-variable">$user</span>) {
    <span class="hl-variable">$user</span>-&gt; <span class="hl-comment">// ?</span>
}
</pre>
<p>Now, we could create separate implementations for each collection: one that only works with strings, and another that only works with <code>User</code> objects:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">StringCollection</span> <span class="hl-keyword">extends</span> <span class="hl-type">Collection</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $key</span>): <span class="hl-type">string</span> 
    { <span class="hl-comment">/* … */</span> }
}

<span class="hl-keyword">class</span> <span class="hl-type">UserCollection</span> <span class="hl-keyword">extends</span> <span class="hl-type">Collection</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $key</span>): <span class="hl-type">User</span> 
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>But what if we need a third implementation? A fourth? Maybe ten or twenty. It becomes quite painful to manage all that code.</p>
<p>That’s where generics come in.</p>
<p>Now, to be clear: PHP doesn’t have generics. That’s a bold statement cutting quite a lot of corners, and we’re coming back to that later in this series. But for now it’s sufficient to say that what I’m showing next isn’t possible in PHP. But it is in many other languages.</p>
<p>Instead of creating a separate implementation for every possible type, many programming languages allow developers to define a “generic” type on the collection class:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Collection</span>&lt;Type&gt; <span class="hl-keyword">extends</span> <span class="hl-type">ArrayObject</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $key</span>): <span class="hl-type">Type</span> 
    { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>Basically we’re saying that the implementation of the collection class will work for any kind of input, but when we create an instance of a collection, we should specify a type. It’s a generic implementation, but it’s made specific depending on the programmer’s needs:</p>
<pre><span class="hl-variable">$users</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>&lt;User&gt;();

<span class="hl-variable">$slugs</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>&lt;string&gt;();
</pre>
<p>It might seem like a small thing to do: adding a type. But that type alone opens a world of possibilities. Our IDE now knows what kind of data is in a collection, it can tell us whether we’re adding an item with the wrong type; it can tell us what we can do with items when iterating over a collection, it can tell us whether we’re passing the collection to a function that knows how to work with those specific items.</p>
<p>And while we could technically achieve the same by manually implementing a collection for every type we need; a generic implementation would be a significant improvement for you and me, developers who are writing and maintaining code.</p>
<p>So, why don’t we have generics in PHP? What other things can we do with them besides a boring collection? Can we add support for them? We’re going to answer all those questions in this mini series. And to be clear up front: my goal with this series is to teach you about generics, but equally important is that I want to create awareness about how we’re missing out with PHP. I want that to change.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-03-22T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP in 2021 (video) ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-in-2021-video"/>

                <id>https://www.stitcher.io/blog/php-in-2021-video</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Back in December, I made this video looking back on PHP in 2021. You can <a href="https://www.youtube.com/watch?v=W3p8BGeiTwQ">watch it</a> (make sure to like and subscribe if you liked it), or you can read the transcript here if you don't like watching videos.</p>
<iframe width="560" height="435" src="https://www.youtube.com/embed/W3p8BGeiTwQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<hr />
<p>It’s the end of 2021 and I still hear some people say they think PHP is dead. They are wrong, let’s talk about that.</p>
<p>Let’s start with the language itself. It’s been actively developed for the past decade, with a new release every year. And just to name a few features that have been added recently:</p>
<ul>
<li>Enums</li>
<li>The match operator</li>
<li>Named arguments</li>
<li>Typed and readonly properties</li>
<li>FFI which stands for foreign function interface and allows cross-language communication</li>
<li>Property promotion</li>
<li>Fibers — also known as green threads or coroutines</li>
<li>Null coalescing</li>
<li>Array spreading</li>
<li>The JIT — a just-in-time compiler</li>
<li>Preloading</li>
<li>And Attributes — also known as annotations for better meta programming</li>
</ul>
<p>And these are just my favourites, there’s much more. All of that to say that PHP is a rich language these days.
On top of that, static analysis has grown in popularity over the years, allowing for generics, closure definitions and quite a lot more;
and we see more and more people and projects adopting static analysis tools like Psalm and PHPStan. It’s quite powerful.</p>
<p>Finally, when it comes to the language itself: just recently the PHP foundation was announced. A non-profit with the goal to support, promote, and advance PHP. They are backed by companies like</p>
<ul>
<li>Jetbrains</li>
<li>Automattic (that’s the company behind wordpress)</li>
<li>Symfony</li>
<li>Laravel</li>
<li>Packgist</li>
<li>Zend</li>
<li>and Craft;</li>
</ul>
<p>just to name a few. Their only focus is to be able to pay core developers so that they can work on PHP full time.
The foundation was announced less than a month ago, and has raised
Two hundred fourteen thousand dollars to date, with a yearly goal of slightly less than three hundred thousand.</p>
<hr />
<p>Besides the language itself — which I can assure you is stable and very much alive — PHP has a large and active community.
Packagist is the most popular package manager, and has a total of almost fifty billion downloads. With around one point five billion new downloads each month.</p>
<p>Next there are the immensely popular web frameworks live Symfony and Laravel, and CMSs like WordPress and Craft.</p>
<p>There’s also the async community — don’t be mistaken: PHP can perfectly run asynchronously like for example you’d do with node. There’s Swoole and RoadRunner which are low-level components that optimize PHP’s runtime for asynchronous programming,
but there also are high-level packages that you can plug  into any project: packages like Amp and ReactPHP.</p>
<hr />
<p>Finally, PHP is just a fun language to work with. It’s mature, performant, has a huge community, and is actively developed. I like working with PHP. You might prefer other languages which is totally fine, but there’s absolutely no reason to say that PHP is dead. It’s very much alive.</p>
 ]]></summary>

                <updated>2022-01-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Dealing with dependencies ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/dealing-with-dependencies"/>

                <id>https://www.stitcher.io/blog/dealing-with-dependencies</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>This post was originally sent to <a href="/newsletter/subscribe">my newsletter</a>.</em></p>
<p>I've written a lot about PHP 8.1 these past months. Not just about the release itself, but also about how important it is to keep up-to-date with PHP versions.</p>
<p>I don't want to leave you with empty words though, so I want to share some actionable advice on how to deal with updating external dependencies. Because, let's face it, you  <em>want</em> to update your project to PHP 8.1, but some of your dependencies don't support it. So, end of story, right?</p>
<p>Here's what I do in such cases.</p>
<p>First off, I <strong>don't wait</strong> for the official PHP release to start testing my code. This goes for client and private projects, as well as open source projects. You can safely start testing once PHP's release candidates arrive. You might even discover a bug or two in PHP's core, helping them along the way.</p>
<p>Next, if you encounter an external dependency that doesn't support the latest PHP version yet, try and <strong>send a pull request</strong> to fix it yourself. Open source maintainers will often be very thankful for your contribution. It might be best to check the open issues, pull requests and discussions though, maybe it's already being worked on.</p>
<p>Of course, it's not always possible to send a PR on your own. Either you don't know the codebase well enough or don't have the time. The next step is to <strong>reach out to the maintainers</strong>, politely ask if they can provide PHP X.X support and whether you can help in any way. Even when you're not able to actually <em>code</em> the required changes, you might be able to test those changes in your project, and provide early feedback.</p>
<p>The benefit of starting early, is that you're not as much pressured for time. Maybe it'll take maintainers a bit longer than you anticipated, so starting early is only beneficial.</p>
<p>Let's fast-forward in time. PHP 8.1 is released, and one of your dependencies still hasn't been updated. Either the maintainer seems to be inactive, or there's a roadblock that can't be solved in a reasonable amount of time. <strong>Start looking for alternatives</strong>. This is the reason why you shouldn't pull in any dependency into your project without doing your research first. You should look into who and how many people are maintaining it, whether their work is funded, whether there's recent activity in the repository or not, and how many open and stale issues there are. It's best to do this kind of research before, instead of having to deal with it right when want to upgrade your project.</p>
<p>It's impossible to predict the future though, so you'll have to deal with inactive projects one day or another.</p>
<p>If you can't find any alternative dependencies, or none that can be implemented in a reasonable amount of time; you can consider <strong>forking the package</strong> and pulling it into your project. This should always be a last-resort option, but it might be worth it. Realise that you're adding tons of technical debt to your project by doing so though, so carefully consider the pros and cons. Also avoid trying to maintain a public fork, unless you're really motivated to do so.</p>
<p>Now, this strategy seems to work fine in client projects; but what about open source projects that have dependencies themselves? Things get a little more difficult when your open source code turns out to be dependant on other code, code that doesn't support the latest PHP version. Our last resort — forking — isn't as trivial when hundreds or thousands of projects depend on that code as well.</p>
<p>If you're an open source maintainer, I'd say the rule about picking your dependencies is even more important for your open source code. Forking "in the open" comes with a lot of headaches that you want to avoid at all costs.</p>
<p>While it's still a valid strategy in <em>some</em> cases, it might be worth to look at it from a different angle.</p>
<p>Being active in the Laravel community, I actually think we're rather fortunate. There are companies that pay employees to work on open source code. Laravel itself is the best example. I spoke with <a href="https://twitter.com/driesvints">Dries</a> in preparation for this post, one of the maintainers of Laravel. I asked him about the most difficult things when it comes to dealing with external dependencies from Laravel's point of view. He said it's mostly a waiting game. On top of that there's lots of communication between them and external package maintainers to get everything working.</p>
<p>So if you're in open source, the best thing you can do is to carefully consider what packages you depend on. Keep a good relation with those maintainers and try to help where you can. If, on the other hand, you're an open source user; you or your company should consider supporting the people you depend on. They are doing incredibly important work; most of the time, for free.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>That's all I've got for you today. Though I'm wondering: are you running up-to-date PHP versions? If not, what's keeping you back? Are external dependencies the problem, or maybe you're dealing with server constraints? Maybe it has to do with time or budget issues or something else? Let me know via <a href="mailto:brendt@stitcher.io">email</a> or <a href="https://twitter.com/brendt_gd">Twitter</a>, I'm curious!</p>
 ]]></summary>

                <updated>2022-01-19T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ &quot;It&#039;s your fault&quot; ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/its-your-fault"/>

                <id>https://www.stitcher.io/blog/its-your-fault</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I read an intriguing blog post yesterday. It's an old one dating back to 2008, titled "<a href="https://devblogs.microsoft.com/oldnewthing/20080925-00/?p=20763">Even if a function doesn’t do anything, you still have to call it if the documentation says so, because it might do something tomorrow</a>". That's quite a mouthful, but the article itself is rather short; I can summarise it one paragraph for you.</p>
<p>There used to be a function in Windows Kernel that didn't do anything. Yet, the docs told programmers that this function <em>had</em> to be called after calling another one: <em>if</em> you called <code>GetEnvironmentStrings</code>, you <em>also</em> needed to call <code>FreeEnvironmentStrings</code>. However, many programmers didn't bother to do so because it was pointless: <code>FreeEnvironmentStrings</code> didn't do anything, it was literally an empty function. A couple of years later, that function actually got an implementation, and many applications started to break because their programmers never bothered to call it in the first place.</p>
<p>The article summarises it as follows:</p>
<blockquote>
<p>If the documentation says that you have to call a function, then you have to call it. It may be that the function doesn’t do anything, but that doesn’t prevent it from doing something in the future.</p>
</blockquote>
<p>Or, how I like to phrase it: some of the most crappy software design possible.</p>
<p>There was a whole debate in the <a href="https://web.archive.org/web/20100222121715/http://blogs.msdn.com/oldnewthing/archive/2008/09/25/8965129.aspx">comment section</a> on whether Microsoft or the developers — the users of Microsoft's code — messed up. After all: the docs explicitly told their users they needed to call that function, so if they didn't follow the rules, they were on their own.</p>
<p>There were a couple of commentators calling out Microsoft though:</p>
<blockquote>
<p>Why not instead design the API such that the programmer cannot fail to use it correctly and still have their program compile?</p>
</blockquote>
<em class="small center">
    <a href="https://web.archive.org/web/20100222121715/http://blogs.msdn.com/oldnewthing/archive/2008/09/25/8965129.aspx#8965837">Source</a>
</em>
<p>And:</p>
<blockquote>
<p>As a sometimes systems-programmer myself, I'm dismayed that it took until just a couple of comments ago before somebody pointed out that it was ALSO a dumb thing to stick in a do-nothing function call and then assume people would call it by contract.</p>
<p>Uh, did that REALLY seem like a good idea to anybody? By Windows NT 4, had we not all figured out a long time ago that many application developers are not going to do things exactly the way you tell them?</p>
<p>This is MS's error first; the app developer's second. Neither one is right, but MS was more wrong.</p>
</blockquote>
<em class="small center">
    <a href="https://web.archive.org/web/20100222121715/http://blogs.msdn.com/oldnewthing/archive/2008/09/25/8965129.aspx#8966943">Source</a>
</em>
<p>In my opinion, these are some sensible arguments. Users in general can't be trusted to, one, read the docs and two, follow rules that don't seem to make sense at that point in time. That's just not how to world works.</p>
<p>But ok, this was 2008 and we've learned to do better now, haven't we? Well… it's actually still very common to write code that's going to be used by others, and <em>assume</em> those users will know how to use that code responsibly. I personally know plenty of people who follow this mindset. I respect them very much, and they also know I disagree with them on this opinion.</p>
<p>Looking at it from the user perspective though, this mindset is suboptimal as well: if the code <em>itself</em> isn't clear on how it should be used, there's a level of uncertainty introduced in the user's mind. "Am I missing something here?" "Should I read every docs page available before actually using this code?"</p>
<p>I think it's better software design, for vendors and users alike, to make our code as explicit and robust as possible, with as little room for interpretation and uncertainty as possible.</p>
<p>In my opinion, that means:</p>
<ul>
<li>Using a proper type system (as strict as possible)</li>
<li>Not allowing classes to be extended, unless it's by design, <code>final</code> by default</li>
<li>Not allowing state to be writeable from the outside, unless it's by design, <code>readonly</code> by default</li>
<li>Only adding methods to your public API that <em>actually</em> should be publicly accessible, <code>private</code> by default</li>
<li>Using explicit, clear names everywhere</li>
<li>Programming to an interface instead of an implementation</li>
</ul>
<blockquote>
<p>It's better software design, for vendors and users alike, to make our code as explicit and robust as possible, with as little room for interpretation and uncertainty.</p>
</blockquote>
<p>To me, it's not a matter of distrust, it's about writing code that's clear about what it does, without having to dig through a set of rules written in the docs somewhere far away from your IDE.</p>
<p>There's only very little code around these days that doesn't need extra explanation, and I think we can do better than that.</p>
 ]]></summary>

                <updated>2022-01-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Twitter home made me miserable ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/twitter-home-made-me-miserable"/>

                <id>https://www.stitcher.io/blog/twitter-home-made-me-miserable</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>This post was originally sent to <a href="/newsletter/subscribe">my newsletter</a> in November, 2021. I wanted to share it here as well, just to hear some more thoughts.</em></p>
<hr />
<p>Two months ago, I decided to give Twitter Home another chance: the timeline that Twitter fills using their algorithm instead of just chronologically showing tweets of people you follow. I wanted to discover interesting new people to follow and I figure Twitter would fill my feed with tweets related to my interests; based on what and who I liked, retweeted and followed over the years.</p>
<p>I was wrong.</p>
<p>After two months, I now only see tweets of:</p>
<ul>
<li>self proclaimed "tech-gurus" who don't have much, if any, up-to-date experience with real-life projects and clients;</li>
<li>people trying to sell me their latest products;</li>
<li>people showing off their new MacBook pro;</li>
<li>people going out of their way trying to spread "positive vibes" to the point that it becomes a little cringey;</li>
<li>people who use threads, which I don't find a very efficient way of communicating longer and coherent thoughts.</li>
</ul>
<p>And just to be clear, I'm not mad at any of those people; most of them actually tweet interesting stuff as well; but Twitter simply didn't show those more interesting tweets in my Home feed.</p>
<p>It turns out <a href="https://medium.com/technically-social/study-suggests-twitters-timeline-algorithm-buries-external-links-92cb5841082f">their algorithm is rather picky</a>, especially when it comes to tweeting external sources:</p>
<blockquote>
<p>On average, 51% of tweets in chronological timelines contained an external link, compared to just 18% in the algorithmic timelines</p>
</blockquote>
<p>Unfortunately for me, I find external sources (blog posts, news articles, etc) often the most relevant and insightful; and Twitter deliberately filters them out when discovering new people.</p>
<p>So after using Twitter Home for two months, I felt genuinely miserable every time I opened my feed. I knew that almost no tweet would interest me, and I'm sad that the Twitter algorithm doesn't work better for my case. I'm sure Twitter is well aware of how their algorithm works, and I'm sure it yields the best results for the majority of their users, but I apparently don't belong in that group.</p>
<p>So, here's where I need your help: I really want to discover more interesting people online; people who write about PHP, webdev, and programming; people who dare to challenge ideas that we take for granted; content that makes us think outside our box.</p>
<p>But how do I find those people? Twitter clearly isn't the best platform and I find Reddit and HackerNews either too focussed or too broad. So what's left? Any ideas? I would very much appreciate your input!</p>
 ]]></summary>

                <updated>2022-01-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ How I plan ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/how-i-plan"/>

                <id>https://www.stitcher.io/blog/how-i-plan</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I love <a href="mailto:brendt@stitcher.io">getting mail</a>. If you're a regular reader of this blog, you probably know that by now. I received a mail today from Muhammad, asking me a question that's not directly related to programming, though maybe it might interest some programmers nevertheless.</p>
<p>Here's what he asked:</p>
<blockquote>
<p>I struggle in one area and I would like your help in that regard. I wonder how you plan your week, month, year and 5 years?
Developers like me can learn coding and programming techniques; but struggle to set a goal, set proper time and follow a plan.</p>
</blockquote>
<p>It only rarely happens, but this time it did: this question actually made me think really hard about my own progress, and I think it's worth sharing it.</p>
<hr />
<p>First off, I should make a distinction between doing client work, and what I like to call "creative" work. Client work pays the bills, but creative work is what really gives me energy. I have a very different approach in handling them both.</p>
<p>Let's start with client work (the most boring part of the answer): I've been working on the same project for over three years now. I work on it together with a team of wonderful colleagues. I'm the one who has been communicating directly with the client though: analyzing the problem space, setting goals and deadlines, etc.</p>
<p>There's only one thing I can think of that I've come to find incredibly important: clear communication. Check and double check that the work we're doing is what the client is expecting, and clearly communicate about how we're doing in terms of time and budget. We have regular meetings just to talk about how it's going. We both understand that things <em>can</em> change, and we both are adaptable. But we also know that change comes at a price, and we respect that.</p>
<p>So: honest communication and building a meaningful relation between us and our clients are what I consider to be the key. Everything planning related goes rather smoothly once there's a level of trust between both parties.</p>
<p>That's about all I wanted to say about client work, now I want to look at the exciting part — the part that really got me thinking when Muhammad asked his question. How do I plan what I write about on this blog? What kind of podcasts I make? What kind of videos or tweets or newsletters I post?</p>
<p>I don't.</p>
<p>Whenever I try to shove my creative energy into a some kind of system, I find that it utterly fails. That's why, on some weeks, I write 3 or 4 blog posts, and while sometimes I go a month without writing anything.</p>
<p>Sometimes I feel inspired to make a video or podcast. When I do I usually sit down whenever I find the time, write a script, record it and edit it as soon as possible. I've got no "long term media engagement strategy" like some people do. I tried it, and it simply doesn't work.</p>
<p>I <em>used</em> to plan everything to the minute though. Both my wife and I did.</p>
<p>I remember us sitting in the car visiting my wife's gynaecologist — she had been pregnant with our first child for about 3 months — and we were discussing how we wanted the delivery to go. Ideally my wife wanted to stay less then 24 hours in the hospital (you can do that in Belgium if your baby is healthy, it's called an "outpatient delivery" if Google Translate can be trusted).</p>
<p>Fast forward two months and we're sitting in that same car driving urgently to the hospital. It turns out there were some serious complications and my wife needed to be hospitalized. Eventually our son was born at around eight months with an emergency C-section — <em>not</em> what we had planned for. Almost one year later the pandemic hit and we suddenly were in lockdown for the next couple of months with a 9-month old baby.</p>
<p>We learned that no single plan can ever guarantee it'll succeed. So why bother with the stress, disappointment and frustration that comes with it when things turn out to be different than expected. Sure, we still plan short-term things, but there's definitely not a long-term plan we hold on to. There are dreams and hopes, but we don't expect all of them to become a reality.</p>
<p>I do the same with my creative work. Whether it's a blog post, newsletter, tweet, video or podcast; I don't make any long term plans. At most I keep a list of ideas that pop up into my head, but I'll have to admit I remove most of them after a couple of months if I didn't find the energy to work on them by then. Only a handful of ideas make it, and those are the ones that I simply start working on whenever I feel like it.</p>
<p>I'll see where this whole online adventure takes me step by step, and I'm ok with that. I actually find it very liberating. The same goes for learning (for me at least). When I'm truly passionate about something, I don't need a schedule to force me to spend time digging into it. On the contrary: I'd almost need a schedule to tell me when to pause because I need to take care of the kids or do house chores or whatever. After all, aren't only the things we're truly passionate about worth spending so much time on?</p>
<hr />
<p>I'm not sure this was the answer Muhammad expected, but at least it's the most accurate one I could give. If you want to share your thoughts as well, just <a href="mailto:brendt@stitcher.io">send me an email</a>!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2022-01-13T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP in 2022 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-in-2022"/>

                <id>https://www.stitcher.io/blog/php-in-2022</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's the fourth time I'm writing a yearly "PHP in 20XX" post, and I must admit I've never been as excited about it as this year: we've seen awesome new features added to PHP, with stuff like attributes, enums, promoted properties and fibers; and on top of that, the static analysis community is making great progress, my personal favourite feature is PhpStorm now supporting generics <em>when</em> writing code.</p>
<p>Exciting times are ahead, let's take a look at modern day PHP!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<hr />
<h2 id="php-8.1"><a href="#php-8.1" class="heading-anchor">#</a> PHP 8.1</h2>
<p>I can't help but start this list with <a href="/blog/new-in-php-81">the newest PHP version</a>, released just a little more than one month ago. My main projects are already being prepared to run on PHP 8.1 in production, which I must admit I'm very excited about. You might not expect it from a minor release — there are no major breaking changes and only deprecation notices added — but PHP 8.1 brings some very cool features. here's my personal top three.</p>
<p><a href="/blog/php-enums">Enums</a> are now built-into the language:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">draft</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">published</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">archived</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">color</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-variable">$this</span>) 
        {
            <span class="hl-type">Status</span>::<span class="hl-property">draft</span> =&gt; '<span class="hl-value">grey</span>',   
            <span class="hl-type">Status</span>::<span class="hl-property">published</span> =&gt; '<span class="hl-value">green</span>',   
            <span class="hl-type">Status</span>::<span class="hl-property">archived</span> =&gt; '<span class="hl-value">red</span>',   
        };
    }
}
</pre>
<p>We're able to use <code>new</code> <a href="/blog/php-81-new-in-initializers">in initializers</a>:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostStateMachine</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span> = <span class="hl-keyword">new</span> <span class="hl-type">Draft</span>(),
    </span>) {
    }
}
</pre>
<p>And, of course, <a href="/blog/php-81-readonly-properties">readonly properties</a>:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">PostState</span> <span class="hl-property">$state</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$publishedAt</span>,
    </span>) {}
}
</pre>
<p>Which, combined with PHP 8.0's <a href="/blog/constructor-promotion-in-php-8">promoted properties</a>, make for some very clean data classes. Just to visualise the difference, here's that same class, with the same functionality, written in PHP 5.6:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostData</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$title</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">State </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$state</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\DateTimeImmutable|null </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$publishedAt</span>;
   
   <span class="hl-comment">/**
    * <span class="hl-value">@param</span> <span class="hl-type">string</span> <span class="hl-variable">$title</span> 
    * <span class="hl-value">@param</span> <span class="hl-type">State</span> <span class="hl-variable">$state</span> 
    * <span class="hl-value">@param</span> <span class="hl-type">\DateTimeImmutable|null</span> <span class="hl-variable">$publishedAt</span> 
    */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        $title,
        $state,
        $publishedAt = <span class="hl-keyword">null</span>
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> = <span class="hl-variable">$state</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span> = <span class="hl-variable">$publishedAt</span>;
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">string </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>()
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">State </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getState</span>() 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span>;    
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">\DateTimeImmutable|null </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>() 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<p>Can you see why I'm excited? PHP is getting these awesome syntax improvements with every release. It's only getting more and more fun to write it! Of course, there are a lot more features added in modern PHP, check out my 3-minute video if you want a quick rundown, or you can scroll to keep reading — there's much more exciting about PHP in 2022!</p>
<iframe width="560" height="420" src="https://www.youtube.com/embed/W3p8BGeiTwQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="static-analysis"><a href="#static-analysis" class="heading-anchor">#</a> Static Analysis</h2>
<p>I've already briefly mentioned it: static analysis in PHP is growing significantly.</p>
<ul>
<li>Frameworks like Laravel are embracing <a href="https://github.com/laravel/framework/pull/38538">static typing</a> more and more (writing code and docblocks with the sole purpose of helping static analysis);</li>
<li>PhpStorm <a href="https://blog.jetbrains.com/phpstorm/2021/07/phpstorm-2021-2-beta/">added support</a> for generic types, it's a pretty big deal if you can write generic code and have your IDE understand it <em>while</em> you're writing it;</li>
<li>
<a href="https://packagist.org/packages/phpstan/phpstan/stats">PhpStan</a> and <a href="https://packagist.org/packages/vimeo/psalm/stats">psalm</a> are only growing; and finally</li>
<li>my own newsletter <a href="https://road-to-php.com/static">series about static analysis</a> has been doing pretty well with over 1500 participants, more and more people are getting interested in the topic.</li>
</ul>
<p>If you just want a quick read about why static analysis matters in PHP, and why I'm so excited about it, you could check out this blog post: "<a href="/blog/we-dont-need-runtime-type-checks">We don't need runtime type checks</a>".</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="the-php-foundation"><a href="#the-php-foundation" class="heading-anchor">#</a> The PHP foundation</h2>
<p>Two months ago, the PHP world got some pretty big news, maybe even the biggest news of 2021: Nikita, one of most active core maintainers is stepping down to work on LLVM, but at the same time there's also a new initiative backed by several big companies to finally make core development sustainable.</p>
<p>In short, there's the <a href="https://opencollective.com/phpfoundation">PHP Foundation</a>, a non-profit with the only goal to fund PHP core development. The initiative is driven by JetBrains, who have already pledged $100,000 to the project. Alongside many others, they have now raised $329,920.75; a good start!</p>
<p>That money is used to fund core development, and opens doors for people to work on PHP who were previously unable. You can read more about the Foundation's mission and goals in <a href="https://blog.jetbrains.com/phpstorm/2021/11/the-php-foundation/">JetBrains' blog post</a>.</p>
<h2 id="the-ecosystem"><a href="#the-ecosystem" class="heading-anchor">#</a> The ecosystem</h2>
<p>Just like every year, I can't go without mentioning Packagist, now with over 3 million registered versions and more than 300.000 packages. As you can see, the ecosystem just keeps growing and growing, 2022 won't be any different.</p>
<p><a href="/resources/img/blog/php-in-2022/01.png"><img src="/resources/img/blog/php-in-2022/01.png" srcset="/resources/img/blog/php-in-2022/01-1042x411.png 1042w, /resources/img/blog/php-in-2022/01-2330x920.png 2330w, /resources/img/blog/php-in-2022/01-1473x581.png 1473w, /resources/img/blog/php-in-2022/01-1804x712.png 1804w, /resources/img/blog/php-in-2022/01-2084x822.png 2084w" sizes="" alt=""></img></a></p>
<p>Oh, by the way, just recently Packagist passed the milestone of having handled over more than 50 billion installs. Congrats Packagist!</p>
<h2 id="async-php"><a href="#async-php" class="heading-anchor">#</a> Async PHP</h2>
<p>One exciting development in the async community, is that the developers from both Amp and ReactPHP — the two major async players — have come together to make a fiber-compatible event loop implementation called <a href="https://github.com/revoltphp/event-loop">Revolt PHP</a>.</p>
<p>In comparison to the community at large, async PHP is only used by a small portion of it; but nevertheless it's still good to see the async community is going strong and embracing modern PHP.</p>
<h2 id="serverless-php"><a href="#serverless-php" class="heading-anchor">#</a> Serverless PHP</h2>
<p>An interesting development I've been following along the sideline, is serverless PHP. My buddy <a href="https://twitter.com/matthieunapoli">Matthieu Napoli</a> is making it his mission to educate PHP developers about this relatively new way of using PHP, and he seems to be doing pretty well. You can check out <a href="https://bref.sh/">Bref</a>, his open source project to make serverless PHP easy, or check out <a href="https://gumroad.com/a/575280243">his course</a> about serverless PHP in 2022.</p>
<p>I haven't had any use cases for it myself, but I know more and more people running serverless PHP in production, so it's definitely something worth keeping an eye on.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="looking-forward"><a href="#looking-forward" class="heading-anchor">#</a> Looking forward</h2>
<p>So what about this year? I'm looking forward to see where static analysis is going, and am especially curious about even better integration with PhpStorm. I find that realtime static analysis — static analysis in your code <em>while</em> you're writing it — offers much more value during the development phase itself.</p>
<p>I'm a little worried now that Nikita has stepped down. He's definitely not the only person capable of working on PHP's core, but he <em>did</em> a tremendous amount of work these past years with PHP 8.0 and 8.1. I hope the PHP Foundation will be up to speed soon and that there are enough core developers who have time to work on PHP next year. PHP 8.2 is <a href="https://wiki.php.net/rfc#php_82">already in development</a>, although there aren't many RFCs drafted yet.</p>
<p>I don't think 2022 will be the most mind blowing year for PHP, but rather a year of adding stability. Nothing wrong with that.</p>
<hr />
<p>These were the things that stood out the most to me personally in 2021, and that make me excited for PHP in 2022: awesome new syntax, stability for core development thanks to the PHP Foundation, static analysis is growing stronger and better, and lots of interesting developments across the community.</p>
<p>What are you most excited about? Let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">email</a>; I'd love to hear your thoughts!</p>
 ]]></summary>

                <updated>2022-01-11T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP version stats: January, 2022 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-version-stats-january-2022"/>

                <id>https://www.stitcher.io/blog/php-version-stats-january-2022</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's that time again: my biyearly summary of which PHP versions are used across the community. It's been <a href="/blog/php-version-stats-july-2021">6 months</a> since my previous post and during that time <a href="/blog/new-in-php-81">PHP 8.1</a> was released. It'll be interesting to see some numbers on this newest version as well.</p>
<p>As always, it's important to note that I'm working with the data available to us. That means that these charts are no 100% accurate representation of the PHP community as a whole, but they <em>are</em> an accurate representation of one of the most prominent parts of PHP: the <a href="https://packagist.org/php-statistics">packagist ecosystem</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="usage-statistics"><a href="#usage-statistics" class="heading-anchor">#</a> Usage Statistics</h2>
<p>Let's start with the raw numbers: the percentage of PHP versions being used, today and six months ago.</p>
<table>
<tr class="table-head">
    <td>Version</td>
    <td>July, 2021 (%)</td>
    <td>January, 2022 (%)</td>
</tr>
<tr>
    <td>8.1</td>
    <td>0.1</td>
    <td>9.1</td>
</tr>
<tr>
    <td>8.0</td>
    <td>14.7</td>
    <td>23.9</td>
</tr>
<tr>
    <td>7.4</td>
    <td>46.8</td>
    <td>43.9</td>
</tr>
<tr>
    <td>7.3</td>
    <td>19.2</td>
    <td>12.0</td>
</tr>
<tr>
    <td>7.2</td>
    <td>10.4</td>
    <td>6.6</td>
</tr>
<tr>
    <td>7.1</td>
    <td>3.8</td>
    <td>2.4</td>
</tr>
<tr>
    <td>7.0</td>
    <td>1.3</td>
    <td>0.8</td>
</tr>
</table>
<p>Note that I've omitted all versions that didn't have more than 1% usage back in July, 2021. Visualizing this data looks something like this:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2022-jan-01.svg"><img src="/resources/img/blog/version-stats/2022-jan-01.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2022-jan-01.svg">Evolution of version usage</a></em></p>
<p>It's good to see PHP 8.1 being used in almost 10% of all composer installs, only one month after its release. It makes sense that it's easier picked up on for projects already on PHP 8.0, since it's fairly easy to upgrade from PHP 8.0 to PHP 8.1.</p>
<p>I'm also happy to see PHP 8.0's growth, although PHP 8.0 and 8.1 combined only account for one third of all installs. That means that two out of three composer installs use a PHP versions that <a href="https://www.php.net/supported-versions.php">isn't actively supported</a> any more.</p>
<p>Over the past years, I've been making it my goal to educate the people around me about the importance of keeping software up to date. I believe we — you and I — all have a responsibility to carry. If you want some hands-on tips on how to start, you can read <a href="/blog/a-storm-in-a-glass-of-water">this post</a> about the why and how of managing PHP version ugrades.</p>
<blockquote>
<p><strong>two out of three composer installs use a PHP versions that isn't actively supported any more</strong></p>
</blockquote>
<p>Moving on the the all-time overview chart, here you can see the evolution of version usage across time.</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2022-jan-02.svg"><img src="/resources/img/blog/version-stats/2022-jan-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2022-jan-02.svg">All time evolution</a></em></p>
<p>Despite PHP 7.4 starting its downward trajectory, it's clear that it still has a way to go. Let's hope we'll see a steeper decline in six months.</p>
<h2 id="required-versions"><a href="#required-versions" class="heading-anchor">#</a> Required versions</h2>
<p>Another interesting metric is the minimum required version across packages. I've used Nikita's <a target="_blank" href="https://github.com/nikic/popular-package-analysis">popular package analyzer</a> to download the 1000 most popular composer packages, and wrote a little script to get the lowest version they support from their <code>composer.json</code>. Here are the results:</p>
<table>
<tr class="table-head">
    <td>Version</td>
    <td>July, 2021 (#)</td>
    <td>January, 2022 (#)</td>
</tr>
<tr>
    <td>8.0</td>
    <td>117</td>
    <td>160</td>
</tr>
<tr>
    <td>7.4</td>
    <td>56</td>
    <td>69</td>
</tr>
<tr>
    <td>7.3</td>
    <td>133</td>
    <td>116</td>
</tr>
<tr>
    <td>7.2</td>
    <td>142</td>
    <td>133</td>
</tr>
<tr>
    <td>7.1</td>
    <td>182</td>
    <td>190</td>
</tr>
<tr>
    <td>7.0</td>
    <td>31</td>
    <td>29</td>
</tr>
<tr>
    <td>5.6</td>
    <td>61</td>
    <td>49</td>
</tr>
<tr>
    <td>5.5</td>
    <td>43</td>
    <td>42</td>
</tr>
<tr>
    <td>5.4</td>
    <td>41</td>
    <td>43</td>
</tr>
<tr>
    <td>5.3</td>
    <td>97</td>
    <td>83</td>
</tr>
<tr>
    <td>5.2</td>
    <td>12</td>
    <td>10</td>
</tr>
<tr>
    <td>5.0</td>
    <td>2</td>
    <td>2</td>
</tr>
</table>
<p>You'll notice there are a little less than 1000 packages included, that's because some of the 1000 most popular packages don't specifically require a PHP version.</p>
<p>For visual learners, here's the same data visualised in a chart:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2022-jan-03.svg"><img src="/resources/img/blog/version-stats/2022-jan-03.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2022-jan-03.svg">Minimal PHP requirement over time</a></em></p>
<p>You might be surprised not to see PHP 8.1 here yet, but keep in mind that this data shows the <em>minimum</em> required version. It doesn't mean that no packages support PHP 8.1, it only means they also support PHP 8.0 or lower versions. That makes a lot of sense given that PHP 8.1 has only been released for a little more than a month.</p>
<p>By the way, I'm talking about PHP 8.0 and 8.1 as if you're all already familiar with these newer versions. If that's not the case, or if you want 3-minute refresher about all the cool things that are happening in the PHP world these days, check out my video about modern day PHP!</p>
<iframe width="560" height="420" src="https://www.youtube.com/embed/W3p8BGeiTwQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<hr />
<p>So, in summary: I see similar trends as previous years, with the majority of composer installs still running outdated versions. I know many have good reasons why they can't or won't upgrade, but I also believe it has never been easier to stay up-to-date with modern PHP than it is today. Investing a couple of hours or days per year to keep your codebase healthy and up-to-date shouldn't be an issue for anyone. I hope <em>you</em> want to help create awareness for this issue. You can start by sharing this blog post or my <a href="https://www.youtube.com/embed/W3p8BGeiTwQ">recap video</a>.</p>
<p>What are your thoughts on these stats? Are you already using <a href="/blog/new-in-php-81">PHP 8.1</a>? Let me know your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> and subscribe to <a href="/newsletter/subscribe">my newsletter</a> if you want to be kept up-to-date about these posts!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2022-01-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Upgrade to PHP 8.1 with Homebrew on Mac ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-81-upgrade-mac"/>

                <id>https://www.stitcher.io/blog/php-81-upgrade-mac</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="upgrading-with-homebrew"><a href="#upgrading-with-homebrew" class="heading-anchor">#</a> Upgrading with Homebrew</h2>
<p>Start by making sure brew is up-to-date:</p>
<pre>brew update
</pre>
<p>Next, upgrade PHP. You can either use the built-in php recipe, but I recommend to use the <code>shivammathur/homebrew-php</code> tap.</p>
<h3 id="normal-upgrade"><a href="#normal-upgrade" class="heading-anchor">#</a> Normal upgrade</h3>
<pre>brew upgrade php
</pre>
<h3 id="upgrade-with-shivammathur/homebrew-php"><a href="#upgrade-with-shivammathur/homebrew-php" class="heading-anchor">#</a> Upgrade with <code>shivammathur/homebrew-php</code></h3>
<pre>brew tap shivammathur/php
brew install shivammathur/php/php@8.1
</pre>
<p>To switch between versions, use the following command:</p>
<pre>brew link --overwrite --force php@8.1
</pre>
<p>You can read more in the <a target="_blank" href="https://github.com/shivammathur/homebrew-php">repository</a>.</p>
<h3 id="next-steps"><a href="#next-steps" class="heading-anchor">#</a> Next steps</h3>
<p>Check the current version by running <code>php -v</code>:</p>
<pre>php -v
</pre>
<p>Restart Nginx or Apache, if you're using Laravel Valet you can skip to the next section; you need some extra steps in order for the web server to properly work.</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<p>And make sure that your local web server also uses PHP 8.1 by visiting this script:</p>
<pre># index.php, accessible to your web server

<span class="hl-property">phpinfo</span>();
</pre>
<p><em class="small center">The version should show <code>8.1.x</code>.</em></p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="valet"><a href="#valet" class="heading-anchor">#</a> Valet</h2>
<p>If you're using Laravel Valet, you should do the following steps to upgrade it:</p>
<pre>composer global update
</pre>
<p>You can use <code>valet use</code> to switch between PHP versions:</p>
<pre>valet use php@8.1
valet use php@8.0
</pre>
<h2 id="extensions"><a href="#extensions" class="heading-anchor">#</a> Extensions</h2>
<p>PHP extensions are installed using pecl. I personally use Redis and Xdebug. They can be installed like so:</p>
<pre>pecl install redis
pecl install xdebug
</pre>
<p>You can run <code>pecl list</code> to see which extensions are installed:</p>
<pre>pecl list

# Installed packages, channel pecl.php.net:
# =========================================
# Package Version State
# redis   5.3.4   stable
# xdebug  3.1.1   stable
</pre>
<p>You can search for other extensions using <code>pecl search</code>:</p>
<pre>pecl search pdf

# Retrieving data...0%
# ..
# Matched packages, channel pecl.php.net:
# =======================================
# Package Stable/(Latest) Local
# pdflib  4.1.4 (stable)        Creating PDF on the fly with the PDFlib library
</pre>
<p>Make sure to restart your web server after installing new packages:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<pre>valet restart
</pre>
<p>Make sure all extensions are correctly installed and loaded by checking both your PHP webserver and CLI installs:</p>
<pre>php -i | grep redis
</pre>
<pre><span class="hl-property">var_dump</span>(<span class="hl-property">extension_loaded</span>('<span class="hl-value">redis</span>'));
</pre>
<p>If extensions aren't properly loaded, there are two easy fixes.</p>
<p>First, make sure the extensions are added in the correct ini file. You can run <code>php --ini</code> to know which file is loaded:</p>
<pre>Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.1
Loaded Configuration File:         /opt/homebrew/etc/php/8.1/php.ini
Scan for additional .ini files in: /opt/homebrew/etc/php/8.1/conf.d
Additional .ini files parsed:      /opt/homebrew/etc/php/8.1/conf.d/error_log.ini,
/opt/homebrew/etc/php/8.1/conf.d/ext-opcache.ini,
/opt/homebrew/etc/php/8.1/conf.d/php-memory-limits.ini
</pre>
<p>Now check the ini file:</p>
<pre>extension=&quot;redis.so&quot;
zend_extension=&quot;xdebug.so&quot;
</pre>
<p>Note that if you're testing installed extensions via the CLI, you don't need to restart nginx, apache or Valet when making changes to ini settings.</p>
<p>The second thing you can do, if you're updating from an older PHP version which also used pecl to install extension; is to reinstall every extension individually.</p>
<pre>pecl uninstall redis
pecl install redis
</pre>
<h2 id="last-step"><a href="#last-step" class="heading-anchor">#</a> Last step</h2>
<p>Finally you should test and upgrade your projects for <a href="/blog/new-in-php-81">PHP 8 compatibility</a>.</p>
 ]]></summary>

                <updated>2021-11-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.1: real-life performance benchmarks ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-81-performance-in-real-life"/>

                <id>https://www.stitcher.io/blog/php-81-performance-in-real-life</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I did a very quick performance test because I wanted to know the impact of PHP 8.1 on my real-life projects.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>These benchmarks were taken on my local machine, and only meant to measure the relative difference between PHP 8.0 and 8.1. I benchmarked a page that showed lots of data, with lots of classes loaded, as I expected that <a href="/blog/new-in-php-81#performance-improvements-pr">inheritance cache</a> would have the largest performance impact.</p>
<table>
<tr class="table-head">
    <td>Metric</td>
    <td>PHP 8.0</td>
    <td>PHP 8.1</td>
</tr>
<tr>
    <td>Requests per second (#/sec)</td>
    <td>32.02</td>
    <td>34.75</td>
</tr>
<tr>
    <td>Time per request (ms)</td>
    <td>31.232</td>
    <td>28.777</td>
</tr>
</table>
<p>The results seem to be in line what what Dmitry originally reported when he added this feature: a 5-8% performance increase.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-11-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.1 in 8 code blocks ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-81-in-8-code-blocks"/>

                <id>https://www.stitcher.io/blog/php-81-in-8-code-blocks</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">draft</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">published</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">archived</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">color</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-variable">$this</span>) 
        {
            <span class="hl-type">Status</span>::<span class="hl-property">draft</span> =&gt; '<span class="hl-value">grey</span>',   
            <span class="hl-type">Status</span>::<span class="hl-property">published</span> =&gt; '<span class="hl-value">green</span>',   
            <span class="hl-type">Status</span>::<span class="hl-property">archived</span> =&gt; '<span class="hl-value">red</span>',   
        };
    }
}
</pre>
<p><em class="small center"><a href="/blog/php-enums">Enums</a></em></p>
<hr />
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$author</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$createdAt</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">PostState</span> <span class="hl-property">$state</span>,
    </span>) {}
}
</pre>
<p><em class="small center"><a href="/blog/php-81-readonly-properties">Readonly properties</a></em></p>
<hr />
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostStateMachine</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span> = <span class="hl-keyword">new</span> <span class="hl-type">Draft</span>(),
    </span>) {
    }
}
</pre>
<p><em class="small center"><a href="/blog/php-81-new-in-initializers">New in initializers</a></em></p>
<hr />
<pre><span class="hl-variable">$fiber</span> = <span class="hl-keyword">new</span> <span class="hl-type">Fiber</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
    <span class="hl-variable">$valueAfterResuming</span> = <span class="hl-type">Fiber</span>::<span class="hl-property">suspend</span>('<span class="hl-value">after suspending</span>');
    
    <span class="hl-comment">// … </span>
});
 
<span class="hl-variable">$valueAfterSuspending</span> = <span class="hl-variable">$fiber</span>-&gt;<span class="hl-property">start</span>();
 
<span class="hl-variable">$fiber</span>-&gt;<span class="hl-property">resume</span>('<span class="hl-value">after resuming</span>');
</pre>
<p><em class="small center"><a href="/blog/fibers-with-a-grain-of-salt">Fibers, a.k.a. "green threads"</a></em></p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<pre><span class="hl-variable">$array1</span> = [&quot;<span class="hl-value">a</span>&quot; =&gt; 1];

<span class="hl-variable">$array2</span> = [&quot;<span class="hl-value">b</span>&quot; =&gt; 2];

<span class="hl-variable">$array</span> = [&quot;<span class="hl-value">a</span>&quot; =&gt; 0, ...<span class="hl-variable">$array1</span>, ...<span class="hl-variable">$array2</span>];

<span class="hl-property">var_dump</span>(<span class="hl-variable">$array</span>); <span class="hl-comment">// [&quot;a&quot; =&gt; 1, &quot;b&quot; =&gt; 2]</span>
</pre>
<p><em class="small center"><a href="/blog/new-in-php-81#array-unpacking-with-string-keys-rfc">Array unpacking also supports string keys</a></em></p>
<hr />
<pre><span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-type">int</span> $a, <span class="hl-type">int</span> $b</span>) { <span class="hl-comment">/* … */</span> }

<span class="hl-variable">$foo</span> = <span class="hl-property">foo</span>(...);

<span class="hl-variable">$foo</span>(<span class="hl-property">a</span>: 1, <span class="hl-property">b</span>: 2);
</pre>
<p><em class="small center"><a href="https://wiki.php.net/rfc/first_class_callable_syntax">First class callables</a></em></p>
<hr />
<pre><span class="hl-keyword">function</span> <span class="hl-property">generateSlug</span>(<span class="hl-injection"><span class="hl-type">HasTitle&amp;HasId</span> $post</span>) {
    <span class="hl-keyword">return</span> <span class="hl-property">strtolower</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">getTitle</span>()) . <span class="hl-variable">$post</span>-&gt;<span class="hl-property">getId</span>();
}
</pre>
<p><em class="small center"><a href="/blog/new-in-php-81#pure-intersection-types-rfc">Pure intersection types</a></em></p>
<hr />
<pre><span class="hl-variable">$list</span> = [&quot;<span class="hl-value">a</span>&quot;, &quot;<span class="hl-value">b</span>&quot;, &quot;<span class="hl-value">c</span>&quot;];

<span class="hl-property">array_is_list</span>(<span class="hl-variable">$list</span>); <span class="hl-comment">// true</span>

<span class="hl-variable">$notAList</span> = [1 =&gt; &quot;<span class="hl-value">a</span>&quot;, 2 =&gt; &quot;<span class="hl-value">b</span>&quot;, 3 =&gt; &quot;<span class="hl-value">c</span>&quot;];

<span class="hl-property">array_is_list</span>(<span class="hl-variable">$notAList</span>); <span class="hl-comment">// false</span>

<span class="hl-variable">$alsoNotAList</span> = [&quot;<span class="hl-value">a</span>&quot; =&gt; &quot;<span class="hl-value">a</span>&quot;, &quot;<span class="hl-value">b</span>&quot; =&gt; &quot;<span class="hl-value">b</span>&quot;, &quot;<span class="hl-value">c</span>&quot; =&gt; &quot;<span class="hl-value">c</span>&quot;];

<span class="hl-property">array_is_list</span>(<span class="hl-variable">$alsoNotAList</span>); <span class="hl-comment">// false</span>
</pre>
<p><em class="small center"><a href="/blog/new-in-php-81#new-array_is_list-function-rfc">The new <code>array_is_list</code> function</a></em></p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-11-07T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Generics in PHP (video) ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/generics-in-php-video"/>

                <id>https://www.stitcher.io/blog/generics-in-php-video</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I made this video about generics last week, you can watch it (make sure to like and subscribe if you liked it), or you can read the transcript here if you don't like watching videos. Also make sure to share your opinions on the topic via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">email</a>!</p>
<iframe width="560" height="435" src="https://www.youtube.com/embed/FiQdmnnIpEY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<hr />
<p>Generics. We all want them, they are probably not going to be built-into PHP any time soon. BUT there is proper support for generics using docblocks; both by static analysers like PHPStan and Psalm, but also — and this is a big one — by PhpStorm.</p>
<p>You see, only a few months ago, PhpStorm added basic support for generics using docblocks.
And it does in fact work with quite a lot of cases, PhpStorm can tell us — in real time, while coding — what kind of generic type we're dealing with. It's even smart enough to infer generic types in some occasions.</p>
<p>If you have no clue what I'm talking about right now, I would suggest doing some reading on my blog — I've added some useful links in the description for you. But I also want to give an example.</p>
<p>Here we have a kind of "attribute query" class: a class that can filter and instantiate attributes:</p>
<pre><span class="hl-variable">$routeAttributes</span> = <span class="hl-type">Attributes</span>::<span class="hl-keyword">new</span>(<span class="hl-type">MyController</span>::<span class="hl-keyword">class</span>)
    -&gt;<span class="hl-property">instanceOf</span>(<span class="hl-type">Route</span>::<span class="hl-keyword">class</span>)
    -&gt;<span class="hl-property">first</span>();
</pre>
<p>It provides a slightly cleaner API compared to straight up using PHP's built-in reflection classes.</p>
<p>Now, after running this query here, I want my IDE to know, in real time, that I have an instance of the Route attribute here. And this is exactly the kind of complex example that PhpStorm is now able to detect, and it's a huge time saver.</p>
<p>Let me show you the query itself, or at least: the interesting parts of it.</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@template</span> <span class="hl-generic">AttributeType</span>
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">Attributes</span>
{
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">AttributeType</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">first</span>(): <span class="hl-type">mixed</span>
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>Here we have our attribute class, with a generic <code>AttributeType</code>, and that's the type that's returned by the first method, in this example. The problem here: how do we actually set that generic type? It's actually pretty straight forward when you know about generic type inference.</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@template</span> <span class="hl-generic">AttributeType</span>
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">Attributes</span>
{
    <span class="hl-comment">/**
     * <span class="hl-value">@template</span> <span class="hl-generic">InstanceOfType</span>
     *
     * <span class="hl-value">@param</span> <span class="hl-type">class-string&lt;<span class="hl-generic">InstanceOfType</span>&gt;</span> <span class="hl-variable">$className</span>
     *
     * <span class="hl-value">@return</span> <span class="hl-type">self&lt;<span class="hl-generic">InstanceOfType</span>&gt;</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">instanceOf</span>(<span class="hl-injection"><span class="hl-type">string</span> $className</span>): <span class="hl-type">self</span>
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>Here we have our <code>instanceOf</code> method, and you can see it defines another generic type, it's called <code>InstanceOfType</code>. Now, PhpStorm, and other static analysers; are smart enough to detect — or infer the type of the input that's passed to this function — that's the name of the attribute we want to filter on — and use that type as the generic type for our attributes class, when we return it. This kind of generic type inference is an incredibly powerful tool.</p>
<p>You might need to read this example a few times before getting it, but it essentially allows us to create classes like this attribute query class where the end user still has lots of information available to them while using this package.</p>
<p>Now, this is actually not what I wanted to talk about today. It's all pretty cool, and I'm very excited about it; but if you know me, you know that I like to think about the details. And one of those details that we need to talk about, now that generics in PHP are much more accessible; is how to name them.</p>
<p>I used <code>AttributeType</code> and <code>InstanceOfType</code> as the generic type placeholders, but that's kind of not the convention in most programming languages.</p>
<p>I looked at quite a lot of them, and by far, the most popular convention — I think that's thanks to Java — is to use a single letter for generic types; so T, or E or V or K or U — those are some of the popular choices. And that are quite a lot of languages that follow this convention: Java, Kotlin, Rust, Go, also C# and Swift.</p>
<p>And I don't know about you, but I find that this makes my code so much harder to read. And the reasoning behind using these single letters, is to make it clear, by their name, that these are generic types and not real types. But as you can see in my screenshots, you could very well just use a different colour for generic types to differentiate them.</p>
<p>I need to mention though that PhpStorm <a href="https://youtrack.jetbrains.com/issue/WI-63801">doesn't support that yet</a>, but I hope that they'll change it after seeing this video.</p>
<p>Another convention that I've seen around — especially in the Psalm and PHPStan's documentation is to prefix the generic name with an uppercase letter T. But is that really more readable than suffixing it with "Type"? <code>TAttribute</code> or <code>AttributeType</code>; <code>TInstanceOf</code> or <code>InstanceOfType</code>? The second one sounds much more like we'd say it in human language, no?</p>
<p>So yeah, these are the kinds of details I'm thinking about, because I feel like they genuinely affect the readability of my code, and code of others that I need to work in.</p>
<p>So, what I would like to know: what's your opinion?</p>
<p>I made <a href="https://twitter.com/brendt_gd/status/1455760170752036867">a poll on Twitter</a>, and was surprised that so many people — more than 50% — preferred the single letter approach. That's terrible for code readability — especially if you're working with multiple generic types within the same context.</p>
<p>Anyway; I'll probably stick with what feels best for me and what I think is the most readably; but do share your opinions in the comments or on reddit or twitter wherever you're watching this; maybe someone is able to change my mind; or maybe I just changed yours?</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-11-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What&#039;s new in PHP 8.1 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-in-php-81"/>

                <id>https://www.stitcher.io/blog/new-in-php-81</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8.1 was released on <a target="_blank" href="https://wiki.php.net/todo/php81">November 25, 2021</a>. It's currently the latest PHP version. In this post, we'll go through all features, performance improvements, changes and deprecations one by one.</p>
<h2 id="new-features"><a href="#new-features" class="heading-anchor">#</a> New features</h2>
<p>As with every release, PHP 8.1 adds some nice new features. Keep in mind that this list will grow over the year.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<h3 id="enums-rfc"><a href="#enums-rfc" class="heading-anchor">#</a> Enums <small><a target="_blank" href="https://wiki.php.net/rfc/enumerations">RFC</a></small></h3>
<p>Enums will be added in PHP 8.1! If you're unsure what they can be used for, you can read about them <a target="_blank" href="/blog/php-enums">here</a>.</p>
<p>Adding enums would be a significant improvement in PHP, so I for one am very much looking forward seeing enums arrive in PHP 8.1. To give you a quick preview of what they will look like, here's a code sample:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span> {
  <span class="hl-keyword">case</span> <span class="hl-property">Pending</span>;
  <span class="hl-keyword">case</span> <span class="hl-property">Active</span>;
  <span class="hl-keyword">case</span> <span class="hl-property">Archived</span>;
}
</pre>
<p>And this is how they will be used:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span> = Status::Pending;
    </span>) {}

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setStatus</span>(<span class="hl-injection"><span class="hl-type">Status</span> $status</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// …</span>
    }
}

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">setStatus</span>(<span class="hl-type">Status</span>::<span class="hl-property">Active</span>);
</pre>
<p>You can find an in-depth analysis of how to use enums in <a href="/blog/php-enums">this post</a>.</p>
<hr />
<h3 id="fibers-rfc"><a href="#fibers-rfc" class="heading-anchor">#</a> Fibers <small><a target="_blank" href="https://wiki.php.net/rfc/fibers">RFC</a></small></h3>
<p>Fibers — aka <a target="_blank" href="https://en.wikipedia.org/wiki/Green_threads">"green threads"</a> — are a low level mechanism to manage parallelism. You probably won't use them directly in your applications, but frameworks like Amphp and ReactPHP will make extensive use of them.</p>
<p>Here's a simple example of using fibers:</p>
<pre><span class="hl-variable">$fiber</span> = <span class="hl-keyword">new</span> <span class="hl-type">Fiber</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
    <span class="hl-variable">$valueAfterResuming</span> = <span class="hl-type">Fiber</span>::<span class="hl-property">suspend</span>('<span class="hl-value">after suspending</span>');
    
    <span class="hl-comment">// … </span>
});
 
<span class="hl-variable">$valueAfterSuspending</span> = <span class="hl-variable">$fiber</span>-&gt;<span class="hl-property">start</span>();
 
<span class="hl-variable">$fiber</span>-&gt;<span class="hl-property">resume</span>('<span class="hl-value">after resuming</span>');
</pre>
<p>If you want to read some more about fibers, what they can and can't do, you can read <a href="/blog/fibers-with-a-grain-of-salt">this post</a>.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h3 id="performance-improvements-pr"><a href="#performance-improvements-pr" class="heading-anchor">#</a> Performance improvements <small><a target="_blank" href="https://github.com/php/php-src/pull/6627">PR</a></small></h3>
<p>Dmitry Stogov has added some improvements to opcache, he calls it "<a target="_blank" href="https://github.com/php/php-src/pull/6627">inheritance cache</a>". This feature allows links between classes to be cached, much like linked classes can be <a target="_blank" href="/blog/preloading-in-php-74">preloaded</a> as of PHP 7.4.</p>
<p>Dmitry reports between a 5% and 8% performance increase thanks to this change, a nice little detail to look out for in PHP 8.1.</p>
<hr />
<h3 id="array-unpacking-with-string-keys-rfc"><a href="#array-unpacking-with-string-keys-rfc" class="heading-anchor">#</a> Array unpacking with string keys <small><a target="_blank" href="https://wiki.php.net/rfc/array_unpacking_string_keys">RFC</a></small></h3>
<p>Array unpacking was already allowed in <a href="/blog/new-in-php-74">PHP 7.4</a>, but it only worked with numeric keys. The reason string keys weren't supported before is because there wasn't any consensus on how to merge array duplicates. The RFC cleanly solves this by following the semantics of <code>array_merge</code>:</p>
<pre><span class="hl-variable">$array1</span> = [&quot;<span class="hl-value">a</span>&quot; =&gt; 1];

<span class="hl-variable">$array2</span> = [&quot;<span class="hl-value">b</span>&quot; =&gt; 2];

<span class="hl-variable">$array</span> = [&quot;<span class="hl-value">a</span>&quot; =&gt; 0, ...<span class="hl-variable">$array1</span>, ...<span class="hl-variable">$array2</span>];

<span class="hl-property">var_dump</span>(<span class="hl-variable">$array</span>); <span class="hl-comment">// [&quot;a&quot; =&gt; 1, &quot;b&quot; =&gt; 2]</span>
</pre>
<hr />
<h3 id="new-in-initializers-rfc"><a href="#new-in-initializers-rfc" class="heading-anchor">#</a> <code>new</code> in initializers <small><a target="_blank" href="https://wiki.php.net/rfc/new_in_initializers">RFC</a></small></h3>
<p>This RFC allows you to use the <code>new</code> keyword in function definitions as a default parameter, as well as in attribute arguments and other places.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyController</span> {
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">Logger</span> <span class="hl-property">$logger</span> = <span class="hl-keyword">new</span> <span class="hl-type">NullLogger</span>(),
    </span>) {}
}
</pre>
<p>You can read all about this feature in <a href="/blog/php-81-new-in-initializers">this dedicated post</a>.</p>
<hr />
<h3 id="readonly-properties-rfc"><a href="#readonly-properties-rfc" class="heading-anchor">#</a> Readonly properties <small><a target="_blank" href="https://wiki.php.net/rfc/readonly_properties_v2">RFC</a></small></h3>
<p>Class properties can be marked as readonly, meaning they can only be written once.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostData</span> {
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$date</span>,
    </span>) {}
}
</pre>
<p>Trying to change a readonly property after it has been initialized will result in an error:</p>
<pre><span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>('<span class="hl-value">Title</span>', <span class="hl-comment">/* … */</span>);

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span> = '<span class="hl-value">Other</span>';

<span class="hl-property">Error</span>: Cannot modify <span class="hl-keyword">readonly</span> property <span class="hl-type">Post</span>::<span class="hl-property">$title</span>
</pre>
<p>If you want to learn more about readonly properties in depth, you can read <a href="/blog/php-81-readonly-properties">my followup post</a>.</p>
<hr />
<h3 id="first-class-callable-syntax-rfc"><a href="#first-class-callable-syntax-rfc" class="heading-anchor">#</a> First-class callable syntax <small><a target="_blank" href="https://wiki.php.net/rfc/first_class_callable_syntax">RFC</a></small></h3>
<p>You can now make a closure from a callable by calling that callable and passing it <code>...</code> as its argument:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-type">int</span> $a, <span class="hl-type">int</span> $b</span>) { <span class="hl-comment">/* … */</span> }

<span class="hl-variable">$foo</span> = <span class="hl-property">foo</span>(...);

<span class="hl-variable">$foo</span>(<span class="hl-property">a</span>: 1, <span class="hl-property">b</span>: 2);
</pre>
<hr />
<h3 id="pure-intersection-types-rfc"><a href="#pure-intersection-types-rfc" class="heading-anchor">#</a> Pure intersection types <small><a target="_blank" href="https://wiki.php.net/rfc/pure-intersection-types">RFC</a></small></h3>
<p>You already know about <a href="/blog/new-in-php-8#union-types-rfc">union types in PHP 8.0</a>, and intersection types are a similar feature. Where union types require the input to be one of the given types, intersection types require the input to be all of the specified types. Intersection types are especially useful when you're working with lots of interfaces:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">generateSlug</span>(<span class="hl-injection"><span class="hl-type">HasTitle&amp;HasId</span> $post</span>) {
    <span class="hl-keyword">return</span> <span class="hl-property">strtolower</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">getTitle</span>()) . <span class="hl-variable">$post</span>-&gt;<span class="hl-property">getId</span>();
}
</pre>
<p>If you like this style of programming, you'd need to create a new interface <code>Sluggable</code> and implement it in <code>$post</code>, intersection types get rid of that overhead.</p>
<hr />
<h3 id="new-never-type-rfc"><a href="#new-never-type-rfc" class="heading-anchor">#</a> New <code>never</code> type <small><a target="_blank" href="https://wiki.php.net/rfc/noreturn_type">RFC</a></small></h3>
<p>The <code>never</code> type can be used to indicate that a function will actually stop the program flow. This can be done either by throwing an exception, calling <code>exit</code> or other similar functions.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">dd</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">never</span>
{
    <span class="hl-comment">// dump</span>
    
    <span class="hl-keyword">exit</span>;
}
</pre>
<p><code>never</code> differs from <code>void</code> in that <code>void</code> still allows the program to continue. This might seem like a novelty feature but it's actually a quite useful one for static analysers.</p>
<hr />
<h3 id="new-array_is_list-function-rfc"><a href="#new-array_is_list-function-rfc" class="heading-anchor">#</a> New <code>array_is_list</code> function <small><a target="_blank" href="https://wiki.php.net/rfc/is_list">RFC</a></small></h3>
<p>You've probably had to deal with this once in a while: determine if an array's keys are in numerical order, starting from index 0. Just like <code>json_encode</code> decides whether an array should be encoded as an array or object.</p>
<p>PHP 8.1 adds a built-in function to determine whether an array is a list with those semantics, or not:</p>
<pre><span class="hl-variable">$list</span> = [&quot;<span class="hl-value">a</span>&quot;, &quot;<span class="hl-value">b</span>&quot;, &quot;<span class="hl-value">c</span>&quot;];

<span class="hl-property">array_is_list</span>(<span class="hl-variable">$list</span>); <span class="hl-comment">// true</span>

<span class="hl-variable">$notAList</span> = [1 =&gt; &quot;<span class="hl-value">a</span>&quot;, 2 =&gt; &quot;<span class="hl-value">b</span>&quot;, 3 =&gt; &quot;<span class="hl-value">c</span>&quot;];

<span class="hl-property">array_is_list</span>(<span class="hl-variable">$notAList</span>); <span class="hl-comment">// false</span>

<span class="hl-variable">$alsoNotAList</span> = [&quot;<span class="hl-value">a</span>&quot; =&gt; &quot;<span class="hl-value">a</span>&quot;, &quot;<span class="hl-value">b</span>&quot; =&gt; &quot;<span class="hl-value">b</span>&quot;, &quot;<span class="hl-value">c</span>&quot; =&gt; &quot;<span class="hl-value">c</span>&quot;];

<span class="hl-property">array_is_list</span>(<span class="hl-variable">$alsoNotAList</span>); <span class="hl-comment">// false</span>
</pre>
<p><div class="sidenote">
    <p>
        Do you want to stay up-to-date about PHP 8.1's development? Subscribe to my newsletter and receive occasional updates:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="newsletter-email-97">Email</label>
        <input type="email" name="email" id="newsletter-email-97"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
<hr />
<h3 id="final-class-constants-rfc"><a href="#final-class-constants-rfc" class="heading-anchor">#</a> Final class constants <small><a target="_blank" href="https://wiki.php.net/rfc/final_class_const">RFC</a></small></h3>
<p>Class constants in PHP can be overridden during inheritance:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">X</span> = &quot;<span class="hl-value">foo</span>&quot;;
}
 
<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">X</span> = &quot;<span class="hl-value">bar</span>&quot;;
}
</pre>
<p>As of PHP 8.1, you can mark such constants as <code>final</code> in order to prevent this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">final</span> <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">X</span> = &quot;<span class="hl-value">foo</span>&quot;;
}
 
<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">X</span> = &quot;<span class="hl-value">bar</span>&quot;;
    <span class="hl-type">Fatal</span> <span class="hl-property">error</span>: <span class="hl-type">Bar</span>::<span class="hl-property">X</span> cannot override <span class="hl-keyword">final</span> constant <span class="hl-type">Foo</span>::<span class="hl-property">X</span>
}
</pre>
<hr />
<h3 id="new-fsync-function-rfc"><a href="#new-fsync-function-rfc" class="heading-anchor">#</a> New <code>fsync</code> function <small><a target="_blank" href="https://wiki.php.net/rfc/fsync_function">RFC</a></small></h3>
<p>PHP 8.1 adds the <code>fsync</code> and <code>fdatasync</code> functions to force synchronization of file changes to disk and ensure operating system write buffers have been flushed before returning.</p>
<pre><span class="hl-variable">$file</span> = <span class="hl-property">fopen</span>(&quot;<span class="hl-value">sample.txt</span>&quot;, &quot;<span class="hl-value">w</span>&quot;);

<span class="hl-property">fwrite</span>(<span class="hl-variable">$file</span>, &quot;<span class="hl-value">Some content</span>&quot;);

<span class="hl-keyword">if</span> (<span class="hl-property">fsync</span>(<span class="hl-variable">$file</span>)) {
    <span class="hl-keyword">echo</span> &quot;<span class="hl-value">File has been successfully persisted to disk.</span>&quot;;
}

<span class="hl-property">fclose</span>(<span class="hl-variable">$file</span>);
</pre>
<p>Because disk synchronization is a file system operation, the <code>fsync</code> function will only work on plain file streams. Attempting to sync non-file streams will emit a warning.</p>
<hr />
<h3 id="explicit-octal-integer-literal-notation-rfc"><a href="#explicit-octal-integer-literal-notation-rfc" class="heading-anchor">#</a> Explicit octal integer literal notation <small><a target="_blank" href="https://wiki.php.net/rfc/explicit_octal_notation">RFC</a></small></h3>
<p>You can now use <code>0o</code> and <code>0O</code> to denote octal numbers. The previous notation by prefixing a number with <code>0</code> still works as well.</p>
<pre>016 === 0o16; <span class="hl-comment">// true</span>
016 === 0O16; <span class="hl-comment">// true</span>
</pre>
<h2 id="breaking-changes"><a href="#breaking-changes" class="heading-anchor">#</a> Breaking changes</h2>
<p>While PHP 8.1 is a minor version, there will be some changes that might technically be a breaking change, and deprecations as well. Let's discuss them one by one.</p>
<hr />
<h3 id="internal-method-return-types-rfc"><a href="#internal-method-return-types-rfc" class="heading-anchor">#</a> Internal method return types <small><a target="_blank" href="https://wiki.php.net/rfc/internal_method_return_types">RFC</a></small></h3>
<p>Chances are you might run into this deprecation notice when upgrading to PHP 8.1:</p>
<pre>Return type should either be compatible with IteratorAggregate::getIterator(): Traversable, 
or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
</pre>
<p>You might notice this error pop up when using <code>phpunit/phpunit</code>, <code>symfony/finder</code> and some other popular open source packages. What's happened is that internal functions are starting to use proper return types. If you're extending a class from the standard library (like <code>IteratorAggregate</code>), you'll need to add those return types as well.</p>
<p>The fix is simple: update your vendor code if the error occurs in a third-party package (most of those are already fixed with their newest releases). If the error occurs in your code you can either add the <code>ReturnTypeWillChange</code> attribute, suppressing the error until PHP 9.0. Here's an example of a class extending <code>DateTime</code>:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyDateTime</span> <span class="hl-keyword">extends</span> <span class="hl-type">DateTime</span>
{
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">DateTime|false</span>
     */</span>
    <span class="hl-attribute">#[<span class="hl-type">ReturnTypeWillChange</span>]</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">modify</span>(<span class="hl-injection"><span class="hl-type">string</span> $modifier</span>) 
    { 
        <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>; 
    }
}
</pre>
<p>Or you can simply add the return type:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyDateTime</span> <span class="hl-keyword">extends</span> <span class="hl-type">DateTime</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">modify</span>(<span class="hl-injection"><span class="hl-type">string</span> $modifier</span>): <span class="hl-type">DateTime|false</span> 
    { 
        <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>; 
    }
}
</pre>
<hr />
<h3 id="restrict-$globals-usage-rfc"><a href="#restrict-$globals-usage-rfc" class="heading-anchor">#</a> Restrict <code>$GLOBALS</code> usage <small><a target="_blank" href="https://wiki.php.net/rfc/restrict_globals_usage">RFC</a></small></h3>
<p>A small change to how <code>$GLOBALS</code> is used will have a significant impact on the performance of all array operations. Nikita does a fine job explaining the problem and solution in the <a target="_blank" href="https://wiki.php.net/rfc/restrict_globals_usage">RFC</a>. The change means that some edge cases aren't possible to do any more with <code>$GLOBALS</code>. "<em>What is no longer supported are writes to $GLOBALS taken as a whole. All the following will generate a compile-time error</em>":</p>
<pre><span class="hl-variable">$GLOBALS</span> = [];
<span class="hl-variable">$GLOBALS</span> += [];
<span class="hl-variable">$GLOBALS</span> =&amp; <span class="hl-variable">$x</span>;
<span class="hl-variable">$x</span> =&amp; <span class="hl-variable">$GLOBALS</span>;
<span class="hl-keyword">unset</span>(<span class="hl-variable">$GLOBALS</span>);
</pre>
<p>On top of that, passing <code>$GLOBALS</code> by reference will generate a runtime error:</p>
<pre><span class="hl-property">by_ref</span>(<span class="hl-variable">$GLOBALS</span>); <span class="hl-comment">// Run-time error</span>
</pre>
<p>Nikita analysed the top 2000 packages on Packagist, and only found 23 cases that will be affected by this change. We can conclude the impact of this — technically breaking — change will be low, which is why internals decided to add it in PHP 8.1. Remember that most of us will win by this change, given the positive performance impact it has everywhere in our code.</p>
<hr />
<h3 id="resource-to-object-migrations"><a href="#resource-to-object-migrations" class="heading-anchor">#</a> Resource to object migrations</h3>
<p>These changes are part of the long-term vision to convert all resources to dedicated objects. You can read more about it <a target="_blank" href="https://github.com/php/php-tasks/issues/6">here</a>.</p>
<p><strong>Fileinfo functions with <code>finfo</code> objects</strong></p>
<p>Functions like <code>finfo_file</code> and <code>finfo_open</code> used to accept and return resources. As of PHP 8.1, they work with <a target="_blank" href="https://www.php.net/manual/en/class.finfo.php"><code>finfo</code></a> objects.</p>
<p><strong>IMAP functions with <code>IMAPConnection</code> objects</strong></p>
<p>Just like the fileinfo change, IMAP functions like <code>imap_body</code> and <code>imap_open</code> no longer work with resources</p>
<hr />
<h3 id="deprecate-passing-null-to-non-nullable-arguments-of-internal-functions-rfc"><a href="#deprecate-passing-null-to-non-nullable-arguments-of-internal-functions-rfc" class="heading-anchor">#</a> Deprecate passing null to non-nullable arguments of internal functions <small><a target="_blank" href="https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_arg">RFC</a></small></h3>
<p>This change is simple: internal functions currently accept <code>null</code> for arguments that are non-nullable, this RFC deprecates that behaviour. For example, this is currently possible:</p>
<pre><span class="hl-property">str_contains</span>(&quot;<span class="hl-value">string</span>&quot;, <span class="hl-keyword">null</span>);
</pre>
<p>In PHP 8.1, these kinds of errors will throw a deprecation warning, in PHP 9 they will be converted to type errors.</p>
<hr />
<h3 id="autovivification-on-false-rfc"><a href="#autovivification-on-false-rfc" class="heading-anchor">#</a> Autovivification on <code>false</code> <small><a target="_blank" href="https://wiki.php.net/rfc/autovivification_false">RFC</a></small></h3>
<p>From the RFC:</p>
<blockquote>
<p>PHP natively allows for autovivification (auto-creation of arrays from falsey values). This feature is very useful and used in a lot of PHP projects, especially if the variable is undefined. However, there is a little oddity that allows creating an array from a false and null value.</p>
</blockquote>
<p>You can read the details on the RFC page. In summary, this behaviour is deprecated:</p>
<pre><span class="hl-variable">$array</span> = <span class="hl-keyword">false</span>;

<span class="hl-variable">$array</span>[] = 2;

<span class="hl-type">Automatic</span> conversion of <span class="hl-keyword">false</span> to array is deprecated
</pre>
<hr />
<h3 id="other-small-changes"><a href="#other-small-changes" class="heading-anchor">#</a> Other small changes</h3>
<p>With every release, there's a bunch of very minor changes to the language. All of them are listed in the <a target="_blank" href="https://github.com/php/php-src/blob/PHP-8.1.0/UPGRADING">UPGRADING</a> guide on GitHub and the <a href="https://wiki.php.net/rfc/deprecations_php_8_1">small deprecations RFC</a>, make sure to check it out if you want to know every little detail.</p>
<p>Here's a summary of the most significant changes:</p>
<ul>
<li>
<code>MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH</code> no longer has an effect</li>
<li>
<code>MYSQLI_STORE_RESULT_COPY_DATA</code> no longer has an effect</li>
<li>
<hljs type>PDO</hljs>::<hljs prop>ATTR_STRINGIFY_FETCHES</hljs> now also works with booleans</li>
<li>Integers and floats in PDO MySQL and Sqlite result sets will be returned using native PHP types instead of strings when using emulated prepared statements</li>
<li>Functions like <code>htmlspecialchars</code> and <code>htmlentities</code> now also escape <code>'</code> by default to <code>&amp;amp;#039;</code>; malformed UTF-8 will also be replaced with a unicode character, instead of resulting in an empty string</li>
<li>The <code>hash</code>, <code>hash_file</code> and <code>hash_init</code> have an extra argument added to them called <code>$options</code>, it has a default value of <code>[]</code> so it won't affect your code</li>
<li>New support for <code>MurmurHash3</code> and <code>xxHash</code>
</li>
</ul>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>That's it for now, keep in mind I'll regularly update this post during the year, so make sure to <a href="/newsletter/subscribe">subscribe</a> if you want to be kept in the loop. Are you excited for PHP 8.1? Let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a>!</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-11-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The case for route attributes ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/route-attributes"/>

                <id>https://www.stitcher.io/blog/route-attributes</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been thinking about route attributes lately. By doing so, I came to realise that I've got a somewhat strange relation with <a href="/blog/attributes-in-php-8">annotations a.k.a. attributes</a>. Over the years, I've gone from loving them to hating them, to loving them again, to somewhere in between. I've seen them abused, both inside and outside of PHP and I've heard both advocates and opponents making compelling arguments for and against them.</p>
<p>Lately, I've done quite a lot of thinking about a specific use case for them. I've talked with a bunch of people about it and I've tried to approach the question as rationally as possible: are attributes used for routing, a good or bad idea?</p>
<p>After months of thoughts and discussions, I've come to (what I think to be as objectively as possible) a conclusion: they are worth giving a try, albeit with some side notes attached. In this post, I'll share my thought process, as well as address all counterarguments I've heard against route attributes over these past years.</p>
<p>Let's get started.</p>
<hr />
<p>To make sure we're on the same page, route attributes in their most basic form would look something like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostAdminController</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>() {}
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts/{post}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {}
    
    <span class="hl-comment">// …</span>
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Post</span>('<span class="hl-value">/posts/{post}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">store</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {}
}
</pre>
<p>There are <em>a lot</em> of issues with such a simplified example, so let's go through them one by one.</p>
<h3 id="duplication"><a href="#duplication" class="heading-anchor">#</a> Duplication</h3>
<p>First of all, there's the issue of duplication. It might not seem like a problem in this example, but most projects definitely have more than "a few routes". I've counted them in two of the larger projects I'm working on: 470 and 815 routes respectively.</p>
<p>Both <a href="https://symfony.com/doc/current/routing.html#route-groups-and-prefixes">Symfony</a> and <a href="https://laravel.com/docs/8.x/routing#route-groups">Laravel</a> have a concept called "route groups" to deal with these kinds of scaling issues. And the same thinking can be applied when using route attributes.</p>
<p>I'm sure you can come up with quite a lot of different approaches to modeling such attribute route groups; I'm going to share two that I think are robust and qualitative solutions, but it's by no means a definitive list.</p>
<p>You could manage "shared route configuration", stuff like prefixes and middlewares, on the controller level:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Prefix</span>('<span class="hl-value">/posts</span>')]</span></span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Middleware</span>(<span class="hl-type">AdminMiddleware</span>::<span class="hl-keyword">class</span>)]</span></span>
<span class="hl-keyword">class</span> <span class="hl-type">PostController</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>() {}
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts/{post}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {}
}
</pre>
<p>Or, taking it a step further; have a generic <code>Route</code> attribute that can be used like so:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Route</span>(
    <span class="hl-property">prefix</span>: '<span class="hl-value">/post</span>',
    <span class="hl-property">middleware</span>: [<span class="hl-type">AdminMiddleware</span>::<span class="hl-keyword">class</span>]
)]</span></span>
<span class="hl-keyword">class</span> <span class="hl-type">PostController</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>() {}
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts/{post}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {}
}
</pre>
<p>But also make it extensible:</p>
<pre><span class="hl-attribute">#[<span class="hl-type">Attribute</span>]</span>
<span class="hl-keyword">class</span> <span class="hl-type">AdminRoute</span> <span class="hl-keyword">extends</span> <span class="hl-type">Route</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $prefix,
        <span class="hl-type">array</span> $middleware,
    </span>) {
        <span class="hl-keyword">parent</span>::<span class="hl-property">__construct</span>(
            <span class="hl-property">prefix</span>: &quot;<span class="hl-value">/admin/{$prefix}</span>&quot;,
            <span class="hl-property">middleware</span>: [
                <span class="hl-type">AdminMiddleware</span>::<span class="hl-keyword">class</span>,
                ...<span class="hl-variable">$middleware</span>
            ],
        )
    }
}
</pre>
<p>And be used like so:</p>
<pre><span class="hl-attribute">#[<span class="hl-type">AdminRoute</span>]</span>
<span class="hl-keyword">class</span> <span class="hl-type">PostController</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>() {}
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/posts/{post}</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {}
}
</pre>
<p>This last approach is definitely my favourite, but feel free to differ in that opinion. The main point here is: <strong>excessive duplication doesn't have to be a problem with route attributes</strong>.</p>
<h3 id="discoverability"><a href="#discoverability" class="heading-anchor">#</a> Discoverability</h3>
<p>The second-biggest argument against route attributes comes from people who say that they prefer to keep their routes in a single file, so that they can easily search them, instead of spreading them across potentially hundreds of controller files.</p>
<p>Let's take a look at a real life example though. Here we have a contacts controller with an <code>edit</code> method:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ContactsController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">edit</span>(<span class="hl-injection"><span class="hl-type">Contact</span> $contact</span>) 
    { <span class="hl-comment">/* … */</span> };
}
</pre>
<p>People arguing for "a central place to manage their routes", in other words: <em>against</em> route attributes; say that a central route file makes it easier to find what they are looking for. So, ok, let's click through to our routes file (in my case the Laravel IDEA plugin allows you to click the <code>edit</code> method and go straight to the route definition), and take a look at what's there:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">{contact}</span>', [<span class="hl-type">ContactsController</span>::<span class="hl-keyword">class</span>, '<span class="hl-value">edit</span>']);
</pre>
<p>So, what's the URI to visit this page? Is it <code>/{contactId}</code>? Of course not, this route is part of a route group:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">prefix</span>('<span class="hl-value">people</span>')-&gt;<span class="hl-property">group</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
    <span class="hl-comment">// …</span>
    <span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">{contact}</span>', [<span class="hl-type">ContactsController</span>::<span class="hl-keyword">class</span>, '<span class="hl-value">edit</span>']);
});
</pre>
<p>So, it's <code>/people/{contactId}</code>? Nope, because this group is part of another group:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">prefix</span>('<span class="hl-value">crm</span>')
    <span class="hl-comment">// …</span>
    -&gt;<span class="hl-property">group</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
        <span class="hl-type">Route</span>::<span class="hl-property">prefix</span>('<span class="hl-value">people</span>')-&gt;<span class="hl-property">group</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
            <span class="hl-comment">// …</span>
            <span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">{contact}</span>', [<span class="hl-type">ContactsController</span>::<span class="hl-keyword">class</span>, '<span class="hl-value">edit</span>']);
        });
    }
</pre>
<p>Which is part of another group:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">middleware</span>('<span class="hl-value">can:admin,</span>' . <span class="hl-type">Tenant</span>::<span class="hl-keyword">class</span>)
    -&gt;<span class="hl-property">group</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
        <span class="hl-type">Route</span>::<span class="hl-property">prefix</span>('<span class="hl-value">crm</span>')
        <span class="hl-comment">// …</span>
        -&gt;<span class="hl-property">group</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
            <span class="hl-type">Route</span>::<span class="hl-property">prefix</span>('<span class="hl-value">people</span>')-&gt;<span class="hl-property">group</span>(<span class="hl-keyword">function</span> (): <span class="hl-type">void</span> {
                <span class="hl-comment">// …</span>
                <span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">{contact}</span>', [<span class="hl-type">ContactsController</span>::<span class="hl-keyword">class</span>, '<span class="hl-value">edit</span>']);
            });
        }
</pre>
<p>Which is part of another group, defined in Laravel's route service provider:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">middleware</span>(['<span class="hl-value">web</span>', '<span class="hl-value">auth</span>', <span class="hl-comment">/* … */</span>])
    -&gt;<span class="hl-property">prefix</span>('<span class="hl-value">admin/{currentTenant}</span>')
    -&gt;<span class="hl-property">group</span>(<span class="hl-property">base_path</span>('<span class="hl-value">routes/admin_tenant.php</span>'));
</pre>
<p>So, in fact, the full URI to this controller is <code>/admin/{tenantId}/crm/people/edit/{contactId}</code>. And now remember our route file actually contains somewhere between 700 and 1500 lines of code, not just the snippets I shared here.</p>
<p>I'd argue that using dedicated route attributes like <code>CrmRoute</code> extending <code>AdminRoute</code> would be <em>much</em> easier to work with, since you can simply start from the controller and click your way one level up each time, without manually looking through group configurations.</p>
<p>Furthermore, <em>adding</em> a route to the right place in such a large route file poses the same issue: on what line exactly should my route be defined to fall in the right group? I'm not going to step through the same process again in reverse, I'm sure you can see the problem I'm pointing at.</p>
<p>Finally, some people mention splitting their route files into separate ones to partially prevent these problems. And I'd agree with them: that's exactly what route attributes allow you to do on a controller-based level.</p>
<p>In short, <strong>dedicated route files do not improve discoverability and route attributes definitely don't worsen the situation</strong>.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h3 id="consistency"><a href="#consistency" class="heading-anchor">#</a> Consistency</h3>
<p>With the two main arguments <em>against</em> route attributes refuted, let's consider whether they have additional benefits compared to separated route files.</p>
<p>Spoiler: they do.</p>
<p>In the vast majority of cases, from my own experience and based on other's testimonies, controller methods and URIs almost <em>always</em> map one to one together. So why shouldn't they be kept together?</p>
<p>When I'm writing a new controller method, the last thing I want to be bothered about is to create the controller method, and then having to think about "ok, which route file should I now go to that has the correct middleware groups setup, and where in that file should I register this particular method". There's so much unnecessary cognitive overload introduced because of separate route files, because they pull apart two concepts they tightly belong together.</p>
<p>Let's just keep them together, so that we can focus on more important stuff.</p>
<p>Furthermore, any framework worth its salt will provide you with the tools necessary to generate any URI based on a controller method:</p>
<pre><span class="hl-property">action</span>([<span class="hl-type">PostController</span>::<span class="hl-keyword">class</span>, '<span class="hl-value">show</span>'], <span class="hl-variable">$post</span>);
</pre>
<p>If you're already working with controller methods as the "entry point" into your project's URI scheme, then why not keep relevant meta data right with them as well?</p>
<p>So yes, <strong>route attributes do add value compared to route files: they reduce cognitive load while programming</strong>.</p>
<h3 id="route-collisions"><a href="#route-collisions" class="heading-anchor">#</a> Route collisions</h3>
<p>One of the only arguments against route attributes that I kind of agree with, is how we deal with collisions. You've probably dealt with a situation like this one, where two route definitions collide with each other:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">/contacts/{id}</span>', …);
<span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">/contacts/list</span>', …);
</pre>
<p>Here we have a classic collision: when visiting <code>/contacts/list</code>, your router could detect it as matching <code>/contacts/{id}</code>, and in turn runs the wrong action for that route.</p>
<p>Such problems occur rarely, but I've had to deal with them myself on the odd occasion. The solution, when using a single route file, is to simply switch their order:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">/contacts/list</span>', …);
<span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">/contacts/{id}</span>', …);
</pre>
<p>This makes it so that <code>/contacts/list</code> is the first hit, and thus prevents the route collision. However, you don't have any control over the route order when using attributes since they are directly coupled to controller methods and not grouped together; so what then?</p>
<p>First of all, there are a couple of ways to circumvent route collisions, using route files or attributes, all the same; that don't require you to rely on route ordering:</p>
<ul>
<li>You could change your URI scheme, so that there are no potential collisions:  <code>/contacts/show/{id}</code> or <code>/contacts/{id}/show</code>; or</li>
<li>you could use regex validation to only match numeric ids: <code>/contacts/{id:\d+}</code>.</li>
</ul>
<p>However, there still might be some edge cases where collisions are unavoidable. How to handle those? The most obvious solution is to simply allow some kind of "order" key on route attributes, so that you can carefully control their order yourself:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/contacts/list</span>', <span class="hl-property">order</span>: '<span class="hl-value">contacts-1</span>')]</span></span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>() {}

<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Get</span>('<span class="hl-value">/contacts/{id}</span>', <span class="hl-property">order</span>: '<span class="hl-value">contacts-2</span>')]</span></span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">show</span>(<span class="hl-injection"><span class="hl-type">Contact</span> $contact</span>) {}
</pre>
<p>I agree that this approach isn't ideal, but I'd say that solving route collisions never is. On top of that, <strong>these kinds of collisions only rarely happen, so I only consider it a very minor problem that <em>can</em> be solved when needed</strong>.</p>
<h3 id="performance"><a href="#performance" class="heading-anchor">#</a> Performance</h3>
<p>Finally a short one, but one that needs mentioning: some people are afraid of attributes because of performance issues.</p>
<p>First of all: reflection in PHP is pretty fast, all major frameworks use reflection extensively, and I bet you never noticed those parts being a performance bottleneck.</p>
<p>And, secondly: attribute discovery and route registration is something that is very easily cacheable in production: Laravel already does this with event listeners and blade components, just to name two examples.</p>
<p>In fact, the concept of "a route cache" is already present in both Symfony and Laravel, and Symfony even already supports route attributes.</p>
<p>So no, <strong>performance isn't a concern when using route attributes</strong>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>So, what's left? The only argument I've heard that I didn't address here is that "people just don't like attributes".</p>
<p>There's very little to say against that. I think it mostly means that "people don't like change" in general. I've been guilty of this attitude myself. The only advice I can give, if you're in that situation, is to just try it out. Get out of your comfort zone, it's a liberating thing to do.</p>
<p>Now, maybe you want to tell me I'm wrong, or share your own thoughts on the matter. I'd love for my opinion to be challenged, so feel free to share your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">email</a>!</p>
 ]]></summary>

                <updated>2021-10-27T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.1: new in initializers ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-81-new-in-initializers"/>

                <id>https://www.stitcher.io/blog/php-81-new-in-initializers</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8.1 adds a feature that might seem like a small detail, but one that I think will have a significant day-by-day impact on many people. So what's this "new in initializers RFC" about? Let's take a look at an example; we've all written code like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyStateMachine</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">?State</span> <span class="hl-property">$state</span> = <span class="hl-keyword">null</span>,
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> ??= <span class="hl-keyword">new</span> <span class="hl-type">InitialState</span>();
    }
}
</pre>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>In this state machine example, we'd like to construct our class in two ways: <em>with</em> and <em>without</em> an initial state. If we construct it <em>without</em> an initial state, we want a default one to be set. PHP of course supports setting initial values directly in the parameter list, but only for primitive types. For example, if our state machine used strings instead of objects internally, we'd be able to write its constructor like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyStateMachine</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">string</span> <span class="hl-property">$state</span> = 'initial',
    </span>) {
    }
}
</pre>
<p>So with PHP 8.1 we're able to use that same "default value" syntax for objects as well. In other words: you can use <code>new</code> for default arguments (which are one example of "initializers"):</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyStateMachine</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span> = <span class="hl-keyword">new</span> <span class="hl-type">InitialState</span>(),
    </span>) {
    }
}
</pre>
<p>"Initializers" are more than parameter default values though, here's a simple explanation from the RFC:</p>
<blockquote>
<p>This RFC proposes to allow use of new expressions inside parameter default values, attribute arguments, static variable initializers and global constant initializers</p>
</blockquote>
<p>You read it right: attributes are in this list as well! Imagine a simple validation library that uses attributes to validate input on properties. Maybe it should be able to validate array elements, something like this:</p>
<pre>class CreateEmailsRequest extends FormRequestData
{
    #[ValidArray(
        email: [new Required, new ValidEmail],
        name: [new Required, new ValidString],
    )]
    public array $people;
}
</pre>
<p>Before PHP 8.1, you wouldn't be able to write this kind of code, because you weren't allowed to use <code>new</code> in attributes, due to the way they are evaluated, but now you can!</p>
<p>Let's take a look at some important details worth mentioning.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h3 id="only-constructed-when-needed"><a href="#only-constructed-when-needed" class="heading-anchor">#</a> Only constructed when needed</h3>
<p>These kinds of "new values" will only be constructed when actually needed. That means that, in our first example, PHP will only create a new object of <code>InitialState</code> if no argument is given:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyStateMachine</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span> = <span class="hl-keyword">new</span> <span class="hl-type">InitialState</span>(),
    </span>) {
    }
}

<span class="hl-keyword">new</span> <span class="hl-type">MyStateMachine</span>(<span class="hl-keyword">new</span> <span class="hl-type">DraftState</span>()); <span class="hl-comment">// No InitialState is created</span>
<span class="hl-keyword">new</span> <span class="hl-type">MyStateMachine</span>(); <span class="hl-comment">// But now it is</span>
</pre>
<p>In case of attributes, for example, the objects will only be created when <code>newInstance</code> is called on the <a href="/blog/attributes-in-php-8">reflection attribute</a>.</p>
<h3 id="not-in-class-properties"><a href="#not-in-class-properties" class="heading-anchor">#</a> Not in class properties</h3>
<p>You should also know that you cannot use <code>new</code> as a default value in class properties. Supporting this functionality would introduce lots of unforeseen side effects when, for example, serializing and unserializing objects.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyStateMachine</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span> = <span class="hl-keyword">new</span> <span class="hl-type">InitialState</span>();
}
</pre>
<p>Luckily we have <a href="/blog/constructor-promotion-in-php-8">promoted properties</a> which do allow a default value, since PHP will transpile the property promotion syntax, keeping the default value in the constructor argument, but not in the actual property.</p>
<p>Here's what the transpiled version looks like:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyStateMachine</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">State</span> <span class="hl-property">$state</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">State</span> $state = <span class="hl-keyword">new</span> <span class="hl-type">InitialState</span>(),
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> = <span class="hl-variable">$state</span>;
    }
}
</pre>
<h3 id="limited-input"><a href="#limited-input" class="heading-anchor">#</a> Limited input</h3>
<p>You might have already guessed it, but you can only pass a limited set of input when constructing new objects in initializers. For example, you can't use variables, the spread operator, anonymous classes, etc. Still, it's a very welcome addition!</p>
<hr />
<p>PHP is getting better and better with every update. Some people argue that these changes aren't strictly necessary since they don't add any new functionality to the language; but they <em>do</em> make our day-by-day developer lives just a little more easy, I really like that about PHP these days!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-10-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The birth and death of a framework ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/birth-and-death-of-a-framework"/>

                <id>https://www.stitcher.io/blog/birth-and-death-of-a-framework</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="sidenote">
    <p>This post was first released on <a href="https://stitcher.io/mail">my newsletter</a>. Feel free to <a href="https://stitcher.io/mail">subscribe</a> if you want to be the first to see these kinds of posts, and want to talk about about them with me directly via email.</p>
</div>
<p>Every once in a while, maybe every couple of years, someone has an idea that revolutionises the tech industry. All popular frameworks that we use day by day once started out as such a small and insignificant idea: React, TypeScript, Tailwind, Electron, Laravel.</p>
<p>It's hard to imagine a world without those frameworks. And yet: if you told me 15 years ago that the JavaScript ecosystem would be where it is today, I'd have a hard time believing you.</p>
<hr />
<p>Eric Evans once gave <a target="_blank" href="https://www.youtube.com/watch?v=T29WzvaPNc8">a talk</a> about trying to imagine alternatives to frameworks and libraries that we're used to today. He looked at a popular Java time library — Joda Time — and wondered if it was the best solution out there. It certainly was the most used one, but did that also mean "the best"? What followed was a thought experiment about dealing with time, thinking outside the box and solving domain problems from scratch without being influenced by prior knowledge and legacy expectations.</p>
<p>What if we'd start from a blank slate, Eric wondered?</p>
<p>I think that's exactly the spot where potential revolutionary ideas are born. What if we don't take our current solutions for granted but start from scratch instead?</p>
<p>I find Laravel to be a good example. You could easily say that, 10 years ago, the problem of "MVC frameworks for PHP" had already been solved by several frameworks; why would we need another one? And yet, Laravel managed to outgrow every other framework in just a few years time. There's quite a few data sources confirming that:</p>
<ul>
<li>
<a target="_blank" href="https://www.jetbrains.com/lp/devecosystem-2021/php/#PHP_which-php-frameworks-and-platforms-do-you-regularly-use-if-any">JetBrains' Developer Ecosystem Survey</a>
</li>
<li>
<a target="_blank" href="https://insights.stackoverflow.com/survey/2021#most-popular-technologies-webframe-prof">StackOverflow's Developer Survey</a>
</li>
<li>Packagist stats, comparing the relative growth of <a target="_blank" href="https://packagist.org/packages/laravel/laravel/stats">Laravel</a> and <a target="_blank" href="https://packagist.org/packages/symfony/symfony/stats">Symfony</a>
</li>
</ul>
<p>It's true that there's no single data set with a 100% accurate representation of the real world, though I think these sources are the most accurate available, and they all confirm the same: the massive growth of a framework that didn't really solve any new problems compared to its competitors, and yet skyrocketed in popularity.</p>
<p>Ironically though, it's that same popularity, that will most likely mean its end in the long run.</p>
<hr />
<p>What I like about Eric's thought experiment, is that there weren't any alternative goals: he simply wanted to take an honest look at the software he had at hand and wonder "could it be better?".</p>
<p>There's a hidden caveat with Eric's approach though: he can come up with the best solution in the world, all the while ignoring legacy code and backwards compatibility. If you don't have to worry about an existing user base then yes, you <em>can</em> come up with a better solution to almost any given problem.</p>
<p>Joda Time wasn't popular because it was <em>the best</em>, but because it grew with its users for many, many years. It was a trusted solution — sure it had its quirks, but it had proven itself more than enough.</p>
<p>The irony of managing popular software is that once it becomes popular, you can't promise the same quality you did at the start. You can't create the same disruption over and over again, because you need to accommodate your existing user base. In the end, you inevitably end up making compromises.</p>
<p>I feel like this is happening to Laravel today, 10 years after its birth. That's not a bad thing, by the way; it's a sign of maturity and stability, which are two key components in creating long lasting, valuable software.</p>
<p>On top of that, Laravel has solved most, if not all, of the problems there are when writing a web application. There aren't many more ground-breaking features that are missing. Every release brings some niceties, but nothing that's absolutely life critical. Meanwhile though, it takes a very long time to get up to speed with the <a href="/blog/new-in-php-8">latest PHP additions</a>, because there's a legacy user base to keep in mind.</p>
<p>By satisfying their users and guaranteeing stability, any framework <em>must</em> stop being as disruptive as they were at the start.
They <em>must</em> create a void that will be filled by another framework somewhere in the future.</p>
<p>That's exactly why Laravel grew so popular: it filled the void created by other popular frameworks. Ten years ago, that void in the PHP community was simplicity and a low-level entry barrier. That's the void that Laravel filled, and turned out to be extremely successful.</p>
<p>Laravel is in the same place today, where other frameworks were a decade ago. There's a subtle void being created, and it'll grow steadily for the years to come. I believe there <em>will</em> be a point in time where that void is large enough to spark the birth of a new framework. And while Laravel will keep being relevant for many more years — there's quite a lot of production code dependant on it — there will be another "best thing". Laravel, just like any other framework, will reach a tipping point; just like jQuery, Rails, Bootstrap, Symfony, Angular.</p>
<p>So the question at hand: who and what will fill that void?</p>
<h2 id="on-the-other-hand…"><a href="#on-the-other-hand…" class="heading-anchor">#</a> On the other hand…</h2>
<p>I think it's possible for any framework to fill its own void, but it requires groundbreaking changes. In Laravel's case, I can come up with a few things I'd expect from a framework if it were created from scratch today:</p>
<ul>
<li>Proper type support (this is already partially <a href="https://github.com/laravel/framework/pull/38538">worked on</a>, though there's still lots of room for improvement).</li>
<li>Getting rid of unnecessary technical debt. For example, Facades and other forms of magic: they served a purpose 10 years ago when its target audience wasn't using a proper IDE or relying on static analysis, but the PHP community is generally moving towards another type of programming.</li>
<li>Embrace modern PHP features like <a href="/blog/php-8-named-arguments">named arguments</a>, <a href="/blog/php-enums">enums</a> and <a href="/blog/attributes-in-php-8">attributes</a>.</li>
<li>Venture in new territories like async and serverless, Laravel is actually already <a href="https://vapor.laravel.com/">doing</a> <a href="https://laravel.com/docs/8.x/octane">that</a>, and is on the forefront in this area within the PHP community.</li>
</ul>
<p>It'll be interesting to see whether Laravel will be able to fill its own void the next decade or so. I wouldn't be surprised if it did, or at least partially.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-09-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.1: readonly properties ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-81-readonly-properties"/>

                <id>https://www.stitcher.io/blog/php-81-readonly-properties</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p><strong>Important note: PHP 8.2 adds a way of making whole classes readonly at once: <a href="/blog/readonly-classes-in-php-82">readonly classes</a>.</strong></p>
<p>Writing data transfer objects and value objects in PHP has become significantly easier over the years. Take for example a look at a DTO in PHP 5.6:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$title</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">Status </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$status</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\DateTimeImmutable|null </span>*/</span>
    <span class="hl-keyword">private</span> <span class="hl-property">$publishedAt</span>;
   
   <span class="hl-comment">/**
    * <span class="hl-value">@param</span> <span class="hl-type">string</span> <span class="hl-variable">$title</span> 
    * <span class="hl-value">@param</span> <span class="hl-type">Status</span> <span class="hl-variable">$status</span> 
    * <span class="hl-value">@param</span> <span class="hl-type">\DateTimeImmutable|null</span> <span class="hl-variable">$publishedAt</span> 
    */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        $title,
        $status,
        $publishedAt = <span class="hl-keyword">null</span>
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">status</span> = <span class="hl-variable">$status</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span> = <span class="hl-variable">$publishedAt</span>;
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">string </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>()
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">Status </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getStatus</span>() 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">status</span>;    
    }
    
    <span class="hl-comment">/**
     * <span class="hl-value">@return</span> <span class="hl-type">\DateTimeImmutable|null </span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>() 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<p>And compare it to its <a href="/blog/new-in-php-8">PHP 8.0</a>'s equivalent:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">private</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>,
        <span class="hl-keyword">private</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getTitle</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getStatus</span>(): <span class="hl-type">Status</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">status</span>;    
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPublishedAt</span>(): <span class="hl-type">?DateTimeImmutable</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publishedAt</span>;    
    }
}
</pre>
<p>That's already quite the difference, though I think there's still one big issue: all those getters. Personally, I don't use them anymore since PHP 8.0 with its <a href="/blog/constructor-promotion-in-php-8">promoted properties</a>. I simply prefer to use public properties instead of adding getters:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
}
</pre>
<p>Object oriented purists don't like this approach though: an object's internal status shouldn't be exposed directly, and definitely not be changeable from the outside.</p>
<p>In our projects at Spatie, we have an internal style guide rule that DTOs and VOs with public properties shouldn't be changed from the outside; a practice that seems to work fairly well, we've been doing it for quite some time now without running into any problems.</p>
<p>However, yes; I agree that it would be better if the language ensured that public properties couldn't be overwritten at all. Well, <a href="/blog/new-in-php-81">PHP 8.1</a> solves all these issues by introducing the <code>readonly</code> keyword:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
}
</pre>
<p>This keyword basically does what its name suggests: once a property is set, it cannot be overwritten anymore:</p>
<pre><span class="hl-variable">$blog</span> = <span class="hl-keyword">new</span> <span class="hl-type">BlogData</span>(
    <span class="hl-property">title</span>: '<span class="hl-value">PHP 8.1: readonly properties</span>', 
    <span class="hl-property">status</span>: <span class="hl-type">Status</span>::<span class="hl-property">PUBLISHED</span>, 
    <span class="hl-property">publishedAt</span>: <span class="hl-property">now</span>()
);

<span class="hl-variable">$blog</span>-&gt;<span class="hl-property">title</span> = '<span class="hl-value">Another title</span>';

<span class="hl-property">Error</span>: Cannot modify <span class="hl-keyword">readonly</span> property <span class="hl-type">BlogData</span>::<span class="hl-property">$title</span>
</pre>
<p>Knowing that, when an object is constructed, it won't change anymore, gives a level of certainty and peace when writing code: a whole range of unforeseen data changes simply can't happen anymore.</p>
<p>Of course, you still want to be able to copy data over to a new object, and maybe change some properties along the way. We'll discuss how to do that with readonly properties later in this post. First, let's look at them in depth.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h3 id="only-typed-properties"><a href="#only-typed-properties" class="heading-anchor">#</a> Only typed properties</h3>
<p>Readonly properties can only be used in combination with typed properties:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> string <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-property">$mixed</span>;
}
</pre>
<p>You can however use <code>mixed</code> as a type hint:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> string <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> mixed <span class="hl-property">$mixed</span>;
}
</pre>
<p>The reason for this restriction is that by omitting a property type, PHP will automatically set a property's value to <code>null</code> if no explicit value was supplied in the constructor. This behaviour, combined with readonly, would cause unnecessary confusion.</p>
<h3 id="both-normal-and-promoted-properties"><a href="#both-normal-and-promoted-properties" class="heading-anchor">#</a> Both normal and promoted properties</h3>
<p>You've already seen examples of both: <code>readonly</code> can be added both on normal, as well as promoted properties:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> string <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>, 
    </span>) {}
}
</pre>
<h3 id="no-default-value"><a href="#no-default-value" class="heading-anchor">#</a> No default value</h3>
<p>Readonly properties can not have a default value:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> string <span class="hl-property">$title</span> = '<span class="hl-value">Readonly properties</span>';
}
</pre>
<p>That is, unless they are promoted properties:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span> = 'Readonly properties', 
    </span>) {}
}
</pre>
<p>The reason that it <em>is</em> allowed for promoted properties, is because the default value of a promoted property isn't used as the default value for the class property, but only for the constructor argument. Under the hood, the above code would transpile to this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> string <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title = 'Readonly properties', 
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$title</span>;
    }
}
</pre>
<p>You can see how the actual property doesn't get assigned a default value.
The reason for not allowing default values on readonly properties, by the way, is that they wouldn't be any different from constants in that form.</p>
<h3 id="inheritance"><a href="#inheritance" class="heading-anchor">#</a> Inheritance</h3>
<p>You're not allowed to change the readonly flag during inheritance:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> int <span class="hl-property">$prop</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$prop</span>;
}
</pre>
<p>This rule goes in both directions: you're not allowed to add or remove the <code>readonly</code> flag during inheritance.</p>
<h3 id="unset-is-not-allowed"><a href="#unset-is-not-allowed" class="heading-anchor">#</a> Unset is not allowed</h3>
<p>Once a readonly property is set, you cannot change it, not even unset it:</p>
<pre><span class="hl-variable">$foo</span> = <span class="hl-keyword">new</span> <span class="hl-type">Foo</span>('<span class="hl-value">value</span>');

<span class="hl-keyword">unset</span>(<span class="hl-variable">$foo</span>-&gt;<span class="hl-property">prop</span>);
</pre>
<h3 id="reflection"><a href="#reflection" class="heading-anchor">#</a> Reflection</h3>
<p>There's a new <code>ReflectionProperty::isReadOnly()</code> method, as well as a <code>ReflectionProperty::IS_READONLY</code> flag.</p>
<h3 id="cloning"><a href="#cloning" class="heading-anchor">#</a> Cloning</h3>
<p>So, if you can't change readonly properties, and if you can't unset them, how can you create a copy of your DTOs or VOs and change some of its data? You can't <code>clone</code> them, because you wouldn't be able to overwrite its values. There's actually an idea to add a <code>clone with</code> construct in the future that allows this behaviour, but that doesn't solve our problem now.</p>
<p>Well, you <em>can</em> copy over objects with changed readonly properties, if you rely on a little bit of reflection magic. By creating an object <em>without</em> calling its constructor (which is possible using reflection), and then by manually copying each property over — sometimes overwriting its value — you can in fact "clone" an object and change its readonly properties.</p>
<p>I made <a target="_blank" href="https://github.com/spatie/php-cloneable">a small package</a> to do exactly that, here's what it looks like:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">Cloneable</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
    </span>) {}
}

<span class="hl-variable">$dataA</span> = <span class="hl-keyword">new</span> <span class="hl-type">BlogData</span>('<span class="hl-value">Title</span>');

<span class="hl-variable">$dataB</span> = <span class="hl-variable">$dataA</span>-&gt;<span class="hl-property">with</span>(<span class="hl-property">title</span>: '<span class="hl-value">Another title</span>');
</pre>
<p>I actually wrote a dedicated blogpost explaining the mechanics behind all of this, you can read it <a href="/blog/cloning-readonly-properties-in-php-81">here</a>.</p>
<h3 id="readonly-classes"><a href="#readonly-classes" class="heading-anchor">#</a> Readonly classes</h3>
<p>Finally, I should also mention the addition of <a href="/blog/readonly-classes-in-php-82">readonly classes in PHP 8.2</a>. In cases where all properties of your class are readonly (which often happens with DTOs or VOs), you can mark the class itself as readonly. This means you won't have to declare every individual property as readonly — a nice shorthand!</p>
<pre><span class="hl-keyword">readonly</span> <span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">?DateTimeImmutable</span> <span class="hl-property">$publishedAt</span> = <span class="hl-keyword">null</span>,
    </span>) {}
}
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>So, that's all there is to say about readonly properties. I think they are a great feature if you're working on projects that deal with lots of DTOs and VOs, and require you to carefully manage the data flow throughout your code. Immutable objects with readonly properties are a significant help in doing so.</p>
<p>I'm looking forward to using them, what about you? Let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>!</p>
 ]]></summary>

                <updated>2021-09-11T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ My IKEA clock, and software design ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/my-ikea-clock"/>

                <id>https://www.stitcher.io/blog/my-ikea-clock</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>This is my bedside clock:</p>
<p><img src="/resources/img/blog/clock/1.png" srcset="/resources/img/blog/clock/1-2550x1441.png 2550w, /resources/img/blog/clock/1-3606x2039.png 3606w, /resources/img/blog/clock/1-1803x1019.png 1803w, /resources/img/blog/clock/1-3123x1765.png 3123w, /resources/img/blog/clock/1-4032x2280.png 4032w" sizes="" alt=""></img></p>
<p>I've had this IKEA clock for 14 years now — that's half my life. And it's one of those things I'll be really sad about the day it stops working.</p>
<p>Why? This clock is a beautiful example of perfect design. Not because it's pretty, but because it's simple, has a clear goal, combined with extremely good UX.</p>
<ul>
<li>It has a very dim backlight, which only shows for a short period when you press the giant button on top. So there's no additional light in your room while sleeping.</li>
<li>It's wireless, it works with three AAA batteries.</li>
<li>I know for sure that I've changed its batteries once in the last 7 years, maybe once more before but I can't remember.</li>
<li>It has a rubber coating, protecting it from falls — I've actually thrown it at my brother once for waking me up too early, it kept working fine (sorry bro, we were young…). My oldest son has also chewed on it, the clock doesn't care.</li>
<li>It keeps its internal clock state for a minute or so after removing the batteries, so you can change batteries without having to reset the clock afterwards — is this magic?</li>
<li>It can change time both forwards and backwards, making it easy to set alarms without having to do the full 12-hour, 60-minute round trip.</li>
</ul>
<p>We should design our software more like this clock. No nonsense, focussed on a clear goal and with the simplest UX possible. It just <em>works</em>.</p>
<p>Unfortunately, IKEA doesn't make this kind of clock any more (it's called "Slabang", by the way). I really hope mine will last a few more decades; I've already been looking for replacements but nothing seems to match the excellence of this clock.</p>
 ]]></summary>

                <updated>2021-09-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ re: On using PSR abstractions ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/re-on-using-psr-abstractions"/>

                <id>https://www.stitcher.io/blog/re-on-using-psr-abstractions</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Yesterday, I read Matthias Noback's excellent blog post on <a target="_blank" href="https://matthiasnoback.nl/2021/08/on-using-psr-abstractions/">PSR abstractions</a>, and I'd like to share some thoughts on the topic as well.
I'm going to quote the parts I want to answer, but make sure to read the full post if you want more information about Matthias' point of view.</p>
<p>I want to make clear up front that I mean no disrespect to any individual and I've tried very hard to convey that in this post. If something however still comes across as disrespectful or hurtful, please <a href="mailto:brendt@stitcher.io">reach out to me</a> to let me know and I'm happy to revisit it.</p>
<hr />
<p>Let's start at the beginning.</p>
<blockquote>
<p>Several years ago, when the PHP-FIG created its first PSRs they started some big changes in the PHP ecosystem</p>
</blockquote>
<p>They definitely did. I'd say the FIG has done an amazing job in modernizing the PHP ecosystem.</p>
<blockquote>
<p>PSRs for coding standards were defined, which I'm sure helped a lot of teams to leave coding standard discussions behind.</p>
</blockquote>
<p>I think it's fair to say that most professional developers are using at least some PSR, with or without their knowledge.</p>
<blockquote>
<p>Next up were the PSRs that aimed for the big goal: framework interoperability. […] The idea […] was that frameworks could provide implementation packages for the proposed interfaces. So you could eventually use the Symfony router, the Zend container, a Laravel security component, and so on.</p>
</blockquote>
<p>While framework interoperability is useful to some extent, it's unrealistic trying to make everything work together: you'd end up with a single framework in the end. There are only so many ways to implement a router or container, if there's one common set of interfaces shared among different frameworks then there'll be very little differences to the users of those frameworks. Sure there might be some implementation differences — but the goal of a framework is for users not to care about those, and to be able to focus on building applications instead.</p>
<p>Matthias shares this concern:</p>
<blockquote>
<p>One of the concerns I personally had about PSR abstractions is that once you have a good abstraction, you don't need multiple implementation packages</p>
</blockquote>
<p>The beauty of the two or three (or four or five, depending how you count) major frameworks in our community is that they each have their unique way of tackling problems. Each framework has its own identity that attracts a different group of developers.</p>
<p>Aiming for "full framework interoperability" is not only an unrealistic goal, but also something we simply don't need.</p>
<p>But fair enough, maybe Matthias and the FIG aren't talking about <em>full</em> framework interoperability, just about some parts. So let's talk about abstractions. Matthias says there's value in PSRs because they are tried and tested abstractions and you can trust them.</p>
<p>Take, for example PSR-18, the HTTP client interface:</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">ClientInterface</span>
{
    <span class="hl-comment">/**
     * <span class="hl-value">@throws</span> \Psr\Http\Client\ClientExceptionInterface
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">sendRequest</span>(<span class="hl-injection">
        <span class="hl-type">RequestInterface</span> $request
    </span>): <span class="hl-type">ResponseInterface</span>;
}
</pre>
<p>Granted, this is as simple as an HTTP client can get. It should be able to send a request and return a response. Matthias says the following about it:</p>
<blockquote>
<p>It is a great abstraction already: it does what you need, nothing more, nothing less. After all, what you need is to send an HTTP request and do something with the returned HTTP response</p>
</blockquote>
<p>However, there's of course that infamous <code>RequestInterface</code>. Here's Matthias again:</p>
<blockquote>
<p>The only problem about this interface is maybe: how can you create a RequestInterface instance?</p>
</blockquote>
<p>I can resonate with that thought. Whenever I encounter a PSR-7 compliant library, I need to stop and think and search which package allows me to easily create — what I would think should be — a simple request object:</p>
<blockquote>
<p>Every time I need an HTTP client I struggle with this again: what packages to install, and how to get a hold of these objects?</p>
</blockquote>
<p>Matthias contemplates the idea that maybe your own, simpler abstraction is a better option?</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">HttpClient</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">get</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $uri, 
        <span class="hl-type">array</span> $headers, 
        <span class="hl-type">array</span> $query
    </span>): <span class="hl-type">string</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">post</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $uri, 
        <span class="hl-type">array</span> $headers, 
        <span class="hl-type">string</span> $body
    </span>): <span class="hl-type">string</span>;
}
</pre>
<p>"Unfortunately", he says:</p>
<blockquote>
<p>[…] by creating my own abstraction I lose the benefits of using an established abstraction, being:</p>
<ol>
<li>You don't have to design a good abstraction yourself.</li>
<li>You can use the interface and rely on an implementation package to provide a good implementation for it. If you find another package does a better job, it will be a very easy switch.</li>
</ol>
</blockquote>
<p>We're almost arriving at the core of my problem with the FIG these days. Sure, there's value in using tried and tested code, in not reinventing the wheel for every project. Matthias warns about the danger of doing that:</p>
<blockquote>
<p>If you wrap PSR interfaces with your own classes you lose these benefits. You may end up creating an abstraction that just isn't right, or one that requires a heavy implementation that can't be easily replaced.</p>
</blockquote>
<p>The benefit of using PSRs in comparison to running your own implementation, is that your own implementation raises tons of questions that have been answered by the FIG before:</p>
<blockquote>
<ul>
<li>What is the structure of the $headers array: header name as key, header value as value? All strings?</li>
<li>Same for $query; but does it support array-like query parameters? Shouldn't the query be part of the URI?</li>
<li>Should $uri contain the server hostname as well?</li>
<li>What if we want to use other request methods than get or post?</li>
<li>What if we want to make a POST request without a body?</li>
<li>What if we want to add query parameters to a POST request?</li>
<li>How can we deal with failure? Do we always get a string? What kind of exceptions do these methods throw?</li>
</ul>
</blockquote>
<p>So why spend time and money on creating another abstraction while we already have one?</p>
<p>Well, have you considered the fact that… maybe the FIG doesn't always come up with the best abstractions? That maybe the process that takes months of discussion by a small group of developers, to finally come up with an interface that contains a few methods, might not actually solve the problems that developers are dealing with in real life?</p>
<p>Sure the question of creating HTTP requests and responses has been answered by the FIG. It's <em>an</em> answer. Symfony and Laravel both have their own answer as well which are simpler if you ask me. Moreover, possibly better answers for my use cases.</p>
<p>We've been talking about HTTP abstractions, but Matthias gives another example: the container interface. He agrees that the FIG doesn't always come up with an abstraction that's relevant to the community's needs:</p>
<blockquote>
<p>Without meaning to discredit the effort that went into it, nor anyone involved, there will always be standards that end up being outdated, like in my opinion PSR-11: Container interface.</p>
</blockquote>
<p>Matthias carefully uses the word "outdated" here, though I want to say it's a plain irrelevant abstraction. The same way PSR-7 is irrelevant for most of the work I — and many others — are doing in Laravel or Symfony projects. I'm more than happy to ditch "interoperability" — what does that even mean when you're building a project closely tied to a framework and never intend to change it — and just use a simpler, straight forward, opinionated solution. It's also an abstraction, a good one, just not one that has an "official" name backed by the FIG.</p>
<p>Now some people tell me "you can't predict the future, maybe you <em>do</em> want interoperability somewhere in the next few years". I don't know about others but we actually outline the scope of projects in contracts with clients. They pay us to make an application specifically in one framework. There's no need for this level of interoperability.</p>
<p>Take a look, for example at both the container interface implementations of <a href="https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/DependencyInjection/ContainerInterface.php">Symfony</a> and <a href="https://github.com/laravel/framework/blob/8.x/src/Illuminate/Contracts/Container/Container.php">Laravel</a>, both implement <code>\Psr\Container\ContainerInterface</code>, and yet both add so many more methods. Implementing PSR-11 is merely a gimmick here for frameworks to be able to say "yes, we're PSR compliant"; because there's <strong>no real interoperability between these two</strong>.</p>
<p>Another example: PSR-7, the HTTP messages PSR. Both <a target="_blank" href="https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/HttpFoundation/Request.php">Symfony</a> and <a target="_blank" href="https://github.com/laravel/framework/blob/8.x/src/Illuminate/Http/Request.php">Laravel</a> don't implement PSR-7, because it simply doesn't solve their use cases. Oh and, just to be able to say "yes we're PSR compliant", there's the <a target="_blank" href="https://symfony.com/doc/current/components/psr7.html">PSR-7 bridge</a>, which basically applies the adapter pattern.</p>
<p>Do you realise that applying the adapter pattern is <strong>exactly the opposite</strong> of what the FIG is trying to achieve? The FIG wants a common abstraction to be used across frameworks, while the <a href="https://en.wikipedia.org/wiki/Adapter_pattern">adapter pattern</a> allows one interface to be used as <em>another</em> interface.</p>
<hr />
<p>I want to end with making a slight change to Matthias' last sentence:</p>
<blockquote>
<p>At the same time, we should also use PSR abstractions whenever it makes sense, since they will save us a lot of design work and will make our code less sensitive to changes in vendor packages.</p>
</blockquote>
<p>I'd phrase it like this: "we should use <strong>abstractions</strong> whenever it makes sense". Whether it's the tried and tested Laravel or Symfony implementation of <a href="https://github.com/laravel/framework/blob/8.x/src/Illuminate/Contracts/Container/Container.php">the container</a>, <a target="_blank" href="https://github.com/symfony/contracts/blob/main/HttpClient/HttpClientInterface.php">HTTP client</a>, <a href="https://github.com/symfony/contracts/tree/main/Cache">caching</a>, <a href="https://github.com/laravel/framework/blob/8.x/src/Illuminate/Contracts/Bus/Dispatcher.php">queuing</a>, … These implementations <em>work</em>. They are valid abstractions, even if they don't carry the "PSR" name.</p>
<p>Yes, we should use abstractions; but no, we shouldn't use irrelevant and outdated abstractions. It's not because an abstraction carries the name "PSR" that it's suddenly better than others.</p>
<p>I figure there's a chance of some people getting angry by this post. You're allowed to, I’m open for that feedback.  Please reach out to me via <a href="mailto:brendt@stitcher.io">mail</a> to tell me your thoughts. I don't question the sincerity and efforts of the FIG. I just genuinely believe they are trying to solve a problem that doesn't exist.</p>
<p>Let me end with how I started: the FIG has had a great impact on the PHP community, I'm very thankful for the early work they did as pioneers and the whole community needs to acknowledge that. I also think the FIG has reached its goal, and the project should be called complete.</p>
<hr />
<p>As an addendum, I want to address one more point. I shared Matthias' original post on <a href="https://www.reddit.com/r/PHP/comments/pcituv/on_using_psr_abstractions_matthias_noback/">/r/php</a> before publishing this one. There were some insightful discussions about it, and Matthieu Napoli, the author of PSR-11, <a href="https://www.reddit.com/r/PHP/comments/pcituv/on_using_psr_abstractions_matthias_noback/hajasv6/">pitched in</a>.</p>
<p>I want to address one of the things he said, because I reckon it might be a counterargument that people bring up after reading this post as well. He said:</p>
<blockquote>
<p>PSR-11 is great for libraries that want to interoperate with containers, for example:</p>
<ul>
<li>Phinx to allow loading seed classes from your framework's container</li>
<li>Behat for doing dependency injection in feature contexts</li>
<li>Tactician command bus: load from your container (https://tactician.thephpleague.com/plugins/container/)</li>
<li>Faker for dealing with extensions</li>
<li>schmittjoh/serializer for lazy loading handlers from your container</li>
</ul>
</blockquote>
<p>In other words: I mainly look at PSRs from a framework's perspective, frameworks like Symfony or Laravel, while Matthieu is thinking about smaller, standalone, packages.</p>
<p>Here's one of the examples Matthieu gave in practice. Phinx optionally supports to set a container instance, which it'll use to <a target="_blank" href="https://github.com/cakephp/phinx/blob/master/src/Phinx/Migration/Manager.php#L888-L889">resolve seed classes</a>.</p>
<pre><span class="hl-keyword">if</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">container</span> !== <span class="hl-keyword">null</span>) {
    <span class="hl-variable">$seed</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">container</span>-&gt;<span class="hl-property">get</span>(<span class="hl-variable">$class</span>);
}
</pre>
<p>And, fair enough: there seems to be some adoption at least in small, standalone packages. But what about the broader context? Are those features actually used by end users? Would it be worse if those package provided an adapter layer instead of relying on a third-party abstraction? There are a lot of <em>ifs</em> here, and I'd like to <a href="mailto:brendt@stitcher.io">hear</a> from users who actually have real-life experience with using these kinds of packages.</p>
<p>I mainly look at the FIG from a framework's point of view, I think that's relevant since it's the PHP <strong>framework</strong> interoperability group. I'm not entirely dismissing the merits of proper abstractions, I hope that was clear throughout this post.</p>
 ]]></summary>

                <updated>2021-08-31T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Named arguments and open source projects ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/named-arguments-and-variadic-functions"/>

                <id>https://www.stitcher.io/blog/named-arguments-and-variadic-functions</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>There are a few well known open source maintainers within the PHP community against the use of <a href="/blog/php-8-named-arguments">named arguments</a>, citing maintenance overhead and backwards compatibility problems as reasons not wanting to use them.</p>
<p>I want to nuance those arguments a little bit.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="what's-causing-backwards-compatibility-problems?"><a href="#what's-causing-backwards-compatibility-problems?" class="heading-anchor">#</a> What's causing backwards compatibility problems?</h2>
<p>The main fear is that supporting named arguments in, for example, a framework or open source package will increase the risk of breaking changes.</p>
<p>Imagine a package or framework exposing this class:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">QueryBuilder</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">join</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $table, 
        <span class="hl-type">string</span> $leftColumn, 
        <span class="hl-type">string</span> $rightColumn, 
        <span class="hl-type">string</span> $type
    </span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>The problem with named arguments is that if users call this function with them, the framework now needs to treat parameter name changes as possible breaking ones:</p>
<pre><span class="hl-variable">$query</span>-&gt;<span class="hl-property">join</span>(
    <span class="hl-property">type</span>: '<span class="hl-value">left</span>',
    <span class="hl-property">table</span>: '<span class="hl-value">table_b</span>',
    <span class="hl-property">leftColumn</span>: '<span class="hl-value">table_a.id</span>',
    <span class="hl-property">rightColumn</span>: '<span class="hl-value">table_b.table_a_id</span>',
)
</pre>
<p>If the framework wants to rename <code>leftColumn</code> and <code>rightColumn</code> to simply <code>left</code> and <code>right</code>, the above code — userland code — would break.</p>
<p>Here's the thing: <strong>no framework or package can prevent users from using named arguments</strong>, there simply isn't a way to disallow them. So either, as an open source maintainer, you:</p>
<ul>
<li>treat argument name changes as breaking as soon as you support <a href="/blog/new-in-php-8">PHP 8</a>;</li>
<li>ask users not to use named arguments; or</li>
<li>let users deal with those breaking changes themselves, and don't worry about it.</li>
</ul>
<p>Being an open source maintainer myself: I choose option three. First of all: argument name changes only rarely happen; and second: I trust my users to be professional developers and know the consequences of using named arguments. They are smart grown ups, it's their responsibility.</p>
<p>So in summary for this first part: there's nothing the framework can do to prevent this kind of backwards compatibility issues besides making a note in the README on how they deal with argument name changes. Be consistent with whatever policy you choose, and you're fine.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="named-arguments-as-a-cleaner-syntax-to-deal-with-array-data"><a href="#named-arguments-as-a-cleaner-syntax-to-deal-with-array-data" class="heading-anchor">#</a> Named arguments as a cleaner syntax to deal with array data</h2>
<p>The second way named arguments can be used, is in combination with variadic functions, essentially becoming a — in my opinion cleaner — shorthand for passing arrays of data:</p>
<pre><span class="hl-variable">$user</span> = <span class="hl-type">User</span>::<span class="hl-property">create</span>(
    <span class="hl-property">name</span>: '<span class="hl-value">Brent</span>',
    <span class="hl-property">email</span>: '<span class="hl-value">brendt@stitcher.io</span>',
    <span class="hl-property">company_id</span>: 1,  
);
</pre>
<p>This is possible thanks to named arguments playing well together with variadic functions:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">User</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">create</span>(<span class="hl-injection">...$props</span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>Passing a named argument list into this variadic <code>create</code> function will result in an array like this:</p>
<pre>[
    '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">Brent</span>',
    '<span class="hl-value">email</span>' =&gt; '<span class="hl-value">brendt@stitcher.io</span>',
    '<span class="hl-value">company_id</span>' =&gt; 1,  
]
</pre>
<p>Rewriting the above example without named arguments but arrays instead, would look like this:</p>
<pre><span class="hl-variable">$user</span> = <span class="hl-type">User</span>::<span class="hl-property">create</span>([
    '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">Brent</span>',
    '<span class="hl-value">email</span>' =&gt; '<span class="hl-value">brendt@stitcher.io</span>',
    '<span class="hl-value">company_id</span>' =&gt; 1,  
]);
</pre>
<p>I know which one of these two approaches I prefer. Disclaimer: it's the one that has better syntax highlighting and is shorter to write.</p>
<p>Here's the kicker: <strong>there isn't any possibility for breaking changes, because there aren't any hard coded argument names to begin with!</strong></p>
<hr />
<p>We really need to be more thoughtful about claiming that we cannot support named arguments in our open source packages because of backwards compatibility issues. In the first case there's nothing you can do either way, and the second case doesn't pose any danger of breaking changes.</p>
<p>Don't you agree? Send me <a href="mailto:brendt@stitcher.io">an email</a> or <a href="https://twitter.com/brendt_gd">tweet</a> and we can further discuss it. I'm open to be <a href="/blog/rational-thinking">proven wrong</a>.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-08-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Rational thinking ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/rational-thinking"/>

                <id>https://www.stitcher.io/blog/rational-thinking</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Now and then, I like to ask a simple coding style question on Twitter. It usually goes something like this: do you write FQCN's (fully qualified class names) in your doc blocks or not? In other words, do you write code like this:</p>
<pre><span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\App\Models\Foo[] </span>*/</span>
<span class="hl-variable">$arrayOfFoo</span> = …
</pre>
<p>Or like this:</p>
<pre><span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">Foo[] </span>*/</span>
<span class="hl-variable">$arrayOfFoo</span> = …
</pre>
<p>Of course, the second example assumes you've imported the full class name at the top of your file.</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">\App\Models\Foo</span>;

<span class="hl-comment">// …</span>

<span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">Foo[] </span>*/</span>
<span class="hl-variable">$arrayOfFoo</span> = …
</pre>
<p>I've asked this question maybe three or four times over the years, and I consistently get the same answer from a large group of respondents: they use the full class name, so that they don't have to scroll to the top of the file to know what they are dealing with.</p>
<p>My response, time and time again, has been: so what about real types? Property types, argument types, return types? Do you use the full class name in those cases as well?</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Bar</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">baz</span>(<span class="hl-injection"><span class="hl-type">\App\Models\Foo</span> $foo</span>): \App\Models\Foo
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>I've actually had one person say "yes" to that question, and fair enough, they are consistent. But all the others say they don't. They write it like this:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">\App\Models\Foo</span>;

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">baz</span>(<span class="hl-injection"><span class="hl-type">Foo</span> $foo</span>): <span class="hl-type">Foo</span> 
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>So what's the difference between doc block types (which are required in some cases because PHP's type system is limited), or real types? Why do you want to import one, but not the other; and how does "not scrolling to the top" make a good argument when it isn't consistent?</p>
<hr />
<p>Programmers often take pride in their rational thinking. We look at problems from a slightly different angle than non-programmers do. It's probably this personality trait that got many people into programming to begin with.</p>
<p>I don't mind that people aren't consistent in how they write types in or out of doc blocks. But I <em>am</em> always surprised with how difficult it is to defend that opinion, once you start asking deeper questions, once people are forced to think about it a little more.</p>
<p>It makes me wonder, could it be that there are more such opinions that we think we're sure of; but that, in reality, we haven't actually thought through all that well? Tabs or spaces, light or dark colour schemes, active record or entity mapper, dependency injection or service location, …</p>
<p>How many "rational opinions" do we have that turn out to be irrational after all? Opinions that are habit-driven; that we think of as "the best option" — not because they are, but because they've worked in the past and we're comfortable using them.</p>
<p>Are we — the "rational thinkers" — in fact, just like everyone else, influenced by emotion, sometimes without even knowing it?</p>
<hr />
<p>The real reason to always use full class names in doc blocks, by the way, is because PHP doesn't have a reflection API for import statements. So if you want to map a class name from a doc block to its FQCN, you'd need to manually parse that PHP file. Mind you: import statements are quite difficult to parse: there are aliases, partial namespace imports, grouped imports, function imports, and more.</p>
<p>Fortunately, the problem I describe here isn't really a problem anymore. There's a package called <code>phpdocumentor/type-resolver</code> that supports exactly <a href="https://github.com/phpDocumentor/TypeResolver#resolving-partial-classes-and-structural-element-names">this kind of parsing</a>.</p>
<p>So the only <em>real</em> argument against importing doc block types, turns out to be not so relevant anymore.</p>
<hr />
<p>How sure are we of our opinions? How fiercely and emotionally do we defend those opinions, even when we haven't thought them through all that well? And can we admit it when we're wrong, maybe apologise and move on?</p>
<p>I don't want to start a fight over tabs or spaces, importing types or not; but I do want to encourage you to critically look at your own opinions. Wonder whether you thought them through well enough; and if you'd be willing to change them, if they turn out to be more biased than you thought.</p>
<hr />
<p>Are you angry right now? Do you want to tell me I'm wrong? Send me <a href="mailto:brendt@stitcher.io">an email</a> or <a href="https://twitter.com/brendt_gd">a tweet</a> and we can have a proper internet fight! No really, I would very much appreciate you challenging these thoughts if you don't agree, I'm looking forward to hearing from you!</p>
<p>Oh and if you want to stay up-to-date about my content and these kinds of posts, consider subscribing to <a href="/newsletter/subscribe">my newsletter</a>.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-08-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Why do I write? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/why-do-i-write"/>

                <id>https://www.stitcher.io/blog/why-do-i-write</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>This post was originally sent to <a href="/newsletter/subscribe">my newsletter</a> on August 12, 2021. I originally didn't plan to blog about it, but given the reactions that I received, I decided it would be good to share it with a larger audience.</em></p>
<hr />
<p>This is going to be a slightly different style of newsletter than you're used to. I'm not going to blog or tweet about this, I just want to share these thoughts with you, because you can hit the reply button and let me know your feedback, one on one.</p>
<p>So: why do I write? "Being a content creator" has been a hobby of mine for many years now (I actually made Minecraft videos before writing a blog, believe it or not) and I've always wanted to stay true to myself. <strong>My number one rule is that I only write about what I want, when I want to.</strong></p>
<p>Yesterday though, my colleague Sebastian sent out a new edition of his newsletter that made me stop and think about where I am today. You should totally subscribe to <a target="_blank" href="https://sebastiandedeyne.com/newsletter/">Sebastian's newsletter</a> by the way, I'm always happy to receive one of his mails in my inbox.</p>
<p>Anyway, Seb wrote about how we live in a culture where it seems that everyone and their grandma is working on a successful side-project, and how that affects him. He called it the <a target="_blank" href="https://sebastiandedeyne.com/the-monetization-trap/">the monetization trap</a> — a must read!</p>
<p>I immediately told him I felt the same way he described in his post, and we had a small conversation about it. During our conversation, he shared an <a target="_blank" href="https://manuelmoreale.com/fast-food-content">awesome blog post</a> — another must read — and I must admit it struck a nerve with me. Here's a quote from that post:</p>
<p><em><strong>I see a lot of ["fast food content"] on the web sadly. People who once had something to say that are now trapped in an endless cycle of recycled content, month after month, year after year, saying the same thing, over and over and over again.</strong></em></p>
<p>I felt at least a little shame: I've done this myself. Maybe not to extremes, but I have written blog posts in the past, because I knew people like to read them, because I knew they have a high chance of going viral and giving me an adrenaline rush for a day, maybe two.</p>
<p><strong>I was suddenly reminded of my number one rule, and came to realise that I might not always have followed it, even though I thought I did.</strong></p>
<p>Now, I don't regret writing those kinds of posts, in fact I like to believe some of them have had a significant impact on people's professional developer's life (some people have told me it did). And yet, those aren't the posts I'm most proud of.</p>
<p>In fact, the ones I'm most proud of are actually the least popular ones.</p>
<p>Looking back, not following that one rule might have caused some levels of added stress these past few months, and I'm thankful for Seb's and Manu's writings to make me realise that.</p>
<p>Having named the problem and knowing it's there is actually very comforting, it means I can now work on it. It'll be good to focus on things that I want to, instead of things I must. We'll see what the future brings.</p>
<p>Having written all of this, I'm actually thinking of reposting it on my blog one day, because maybe there are more people out there experiencing the same pressure — consciously or not. I want to see your responses first though, so feel free hit the reply button if you have any thoughts! I'll try my best to answer soon.</p>
<p>Kind regards</p>
<p>Brent</p>
<hr />
<p>I'd like to ask you — the blog reader — the same: if you have any thoughts to share about this topic, please <a href="mailto:brendt@stitcher.io">send me an email</a> (if the mailto link doesn't work: brendt@stitcher.io). I'll try my best to answer all mails, it might take a while!</p>
<p>If this post resonates with you, please consider sharing it with your audience. I think there's an important message here, but I'll let you be the judge of that.</p>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2021-08-13T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The Road to PHP 8.1 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/the-road-to-php"/>

                <id>https://www.stitcher.io/blog/the-road-to-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm happy to announce a fun little project today: <a href="https://road-to-php.com/">The Road to PHP 8.1</a>. It's a 10-day popup newsletter that'll teach you about all the shiny new things in PHP 8.1. The only thing you'll need to do is drop your name and email address, and you'll receive a daily email for the next 10 days.</p>
<p>Worried about spam or followup mails? You'll be automatically unsubscribed after those 10 days, I'm not keeping your email address!</p>
<p>You can <a href="https://road-to-php.com/">subscribe here</a>, and see whether it's your thing or not.</p>
 ]]></summary>

                <updated>2021-08-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ We don&#039;t need runtime type checks ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/we-dont-need-runtime-type-checks"/>

                <id>https://www.stitcher.io/blog/we-dont-need-runtime-type-checks</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Do you want to make a guess about when I last encountered a <code>TypeError</code> in one of my projects? To be honest, I can't remember, so it's probably a few years. Coincidentally, I also started relying on static analysis around the same time.</p>
<p>I'm fairly certain that I could disable PHP's runtime type checking altogether — if that was a thing — and have a perfectly working codebase.</p>
<p>Because, here's the thing about runtime type checks: they are a debugging device, not so much a safety net. Runtime type errors make it easier to detect and fix bugs, but the reality is that whenever a type error is triggered, our code still crashed at runtime. When type errors occur in production, the end result is the program crashing, nothing you can do about it.</p>
<p>Now, I've written about type systems before, you'll find some references at the end of this post; so if you want more background information about them be sure to do some followup reading. Today, I want to discuss how static analysis has the power to revolutionize the way we write PHP code much more than it already does today, and how it can open doors to many new possibilities.</p>
<p>The tradeoff? We need a community-wide mind shift: there are still many PHP developers (including internal developers) who are taken aback by the idea of static type checking. My only goal today is to encourage you to think outside your box, to imagine what would be possible if PHP shifted towards a built-in, statically type-checked model.</p>
<p>Whether you're into static type systems or not, I promise it'll be interesting nevertheless. Let's dive in!</p>
<hr />
<p>A while back, it became clear that generics in PHP are probably <a target="_blank" href="https://github.com/PHPGenerics/php-generics-rfc/issues/45">not coming any time soon</a>. One of the main reasons being that there are two ways to implement them, and both have significant problems. Either there's too large an impact on runtime performance, or the implementation is just way too complex to get right.</p>
<p>Both approaches did assume a runtime type-checked implementation though. So I shared a thought experiment with internals: what if we only need to support the syntax for generics, and have static analysers do all the checks? I called them <a href="/blog/the-case-for-transpiled-generics">transpiled generics</a> back then, but <em>runtime-erased</em> or <em>runtime-ignored</em> generics is probably a better name.</p>
<p>My thinking was that adding support for generic syntax shouldn't be all that hard, and without runtime type checks, there shouldn't be any performance impact. It makes sense if you think about it from a static analysis point of view: your code has already been analysed, and it's been proven to work correctly, so there's no more need for runtime type checks. On top of that, most developers only want generics as a way to get better code insights <em>while</em> coding; does the "I want to know what items are in an array" argument ring a bell?</p>
<p>Of course there could still be <em>some</em> type information exposed at runtime via reflection, but we can't deny that having types ignored at runtime is a major paradigm shift that most PHP developers aren't used to. Here's <a target="_blank" href="https://www.reddit.com/r/PHP/comments/iuhtgd/ive_proposed_an_approach_to_generics_on_internals/g5pgkbn/">Sara's response</a> on my runtime-ignored generics idea (which Hack already does) and how it requires a mind-shift:</p>
<blockquote>
<p>Oh, I agree that there's real value in HackLang's approach. It's just that there is a mountain of inertia around "The PHP Way" and it's going to take an equal and opposite mountain to alter course.
Entirely possible, even probable, but we won't see that level of shift in the next five years.</p>
</blockquote>
<p>It'll take a few more years, but it's probably the way PHP <em>will</em> evolve anyway, according to Sara.</p>
<p>Now, before I get an angry mob chasing me: I'm not suggesting we bundle a static analyser in PHP that you're required to run (that would mean a "compilation" step in practice). What I <em>am</em> suggesting is that we can disable PHP's runtime type checks if we want to, and deal with the consequences ourselves. If you want to use generics in such a scenario then, yes, you'll have to use a static analyser. If you don't want to, that's fine, but you won't be able to use generics.</p>
<p>Of course, in an ideal world, PHP would ship with such a built-in, opt-in static analyser; instead of users having to rely on third party tools. Because the main problem with third party tools is consistency between them. Case in point: PhpStorm will support a basic form a generic-type doc blocks in their <a target="_blank" href="https://blog.jetbrains.com/phpstorm/2021/07/phpstorm-2021-2-beta/">next release</a>, years after Psalm and PHPStan added support for them.</p>
<p>If there was an official spec supported by internals, static analysis vendors wouldn't have any choice but to follow that spec. That's the major problem with doc block type checks at the moment: there are no rules, so every vendor does whatever they want.</p>
<p>The idea of a centralised static analyser isn't new, by the way, but you can imagine it's a massive undertaking to get right. Here's <a target="_blank" href="https://externals.io/message/101477#101592">Rasmus</a> on the matter a few years ago:</p>
<blockquote>
<p>Now if the RFC was a plan for baking a compile-time static analysis engine
into PHP itself, that would be interesting. But that is a massive project.</p>
</blockquote>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>When I asked Nikita about the idea of runtime-ignored types and generics, he described the main problem with generics that <em>have</em> a runtime implementation <a target="_blank" href="https://www.reddit.com/r/PHP/comments/j65968/ama_with_the_phpstorm_team_from_jetbrains_on/g7zg9mt/">like so</a>:</p>
<blockquote>
<p>Complexity is a pretty big problem for us, and I think severely underestimated by non-contributors. Feature additions that seem simple on the surface tend to interact with other existing features in ways that balloon the complexity.</p>
</blockquote>
<p>He also called runtime-erased generics "the cowards way out". The reason Nikita says that is because, if runtime-erased generics were supported, it would mean there's a huge inconsistency within PHP's type system where some parts are checked at runtime, and other parts are checked statically.</p>
<p>So to be clear: I don't think runtime-erased or runtime-ignored generics are where we should start. We first need PHP without runtime type checks whatsoever, and then we can think about building on top of that.</p>
<p>I asked Nikita if he thought such a version of PHP would have merit, he <a target="_blank" href="https://www.reddit.com/r/PHP/comments/j65968/ama_with_the_phpstorm_team_from_jetbrains_on/g83vvav/">said this</a>:</p>
<blockquote>
<p>I think that would be a good thing... but then again, lots of things would be different in PHP if we'd do a clean-slate redesign now. We have to work within the constraints we have, somehow.</p>
</blockquote>
<p>From a userland-developer point of view, I think we <em>can</em> work with the given constraints, as long as there's a large enough user base supporting these ideas.</p>
<hr />
<p>So what if internals don't think of it as achievable to optionally step away from runtime type checks? Or what if such a mind shift won't happen within the next decade?</p>
<p>Well, there <em>is</em> another approach, one that actually has been tried and proven before in another language: TypeScript. The power and immense popularity of TypeScript comes from its static type checker. Sure, there's an extra compilation step to transform TypeScript code to regular JavaScript, but developers seem to manage that just fine — because they know how much they gain from proper static analysis.</p>
<p>The same has been tried in PHP before, by the way: there was Hack that at one point <em>did</em> compile to PHP, and there was <a target="_blank" href="https://web.archive.org/web/20190828000023/https://preprocess.io/#/">preprocess</a>, a project by <a target="_blank" href="https://twitter.com/assertchris">Christopher Pitt</a>. Unfortunately, Hack took another direction, and preprocess halted; not because of implementation problems, but because of lack of support in IDEs and the wider community.</p>
<p><em>If</em> transpiling PHP gains more traction again, it'll definitely need proper IDE support if we ever want a chance for it to succeed. That's the benefit of an internals-backed implementation: when it's in PHP core, IDEs and other external tooling can't do anything but to follow along. A community-driven transpiler wouldn't have that benefit.</p>
<hr />
<p>So, this is where we are today:</p>
<ul>
<li>PHP's runtime type checker is reaching its limitations (generics being the most obvious example)</li>
<li>There <em>are</em> already runtime-ignored types (doc blocks), but there's no consensus on syntax and usage across static analysis communities</li>
<li>Runtime-ignored types require a mind-shift that many developers find difficult at this point</li>
<li>Transpiling PHP is possible, it's been done before, but it's a massive undertaking and likely to fail again if tried without proper support</li>
</ul>
<p>I see much more potential for static analysis. It has made my code more stable and easier to write, and I couldn't do without it anymore. On the other hand, the community and toolset has still a long way to go, and we're all playing a part in that journey.</p>
<p>I'd love for internals to further explore the static analysis side of PHP: it's more than just a userland addon to the language, and will only continue to grow tighter to PHP in the future.</p>
<p>I'd want to see these changes to the language today, though I know that's an unrealistic expectation. I hope Sara's assessment is right in that this <em>is</em> the form PHP is evolving to, but unfortunately it'll take a few more years to get there. This blog post is just an attempt to give one more little push in the right direction.</p>
<p>What's your opinion? <a target="_blank" href="https://twitter.com/brendt_gd">Let me know</a>.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="sidenotes"><a href="#sidenotes" class="heading-anchor">#</a> Sidenotes</h2>
<p>I'll probably add some more information to this section when people read this post and share their feedback, though I could already think of a couple of things.</p>
<h3 id="psalm-+-rector-as-a-&quot;transpiler&quot;-?"><a href="#psalm-+-rector-as-a-"transpiler"-?" class="heading-anchor">#</a> Psalm + Rector as a "transpiler" ?</h3>
<p>Someone mentioned the idea about using <a target="_blank" href="https://www.youtube.com/watch?v=N2PENQpQVjQ&amp;t=2454s">PHP without runtime type checks</a> by using a combination of <a target="_blank" href="https://psalm.dev/">Psalm</a> and <a target="_blank" href="https://getrector.org/">Rector</a>: Psalm first analysed the codebase, and Rector removed all type hints afterwards to generate a "compiled" production build.</p>
<p>It's an interesting step to further explore the problem space, and while it doesn't mean there's support for custom syntax, there might be potential in the Psalm + Rector combo.</p>
<h3 id="why-not-use-…-?"><a href="#why-not-use-…-?" class="heading-anchor">#</a> Why not use … ?</h3>
<p>The classic question that gets asked by skeptics: why not use Java or C# or whatever other language if you want to rely on static analysis so much?</p>
<p>Well, the answer is simple: the ecosystem.</p>
<h3 id="what-about-the-fig?"><a href="#what-about-the-fig?" class="heading-anchor">#</a> What about the FIG?</h3>
<p>The main problem with doc block types is one of consistency, which maybe the FIG could solve?</p>
<p>I'm not sure about the relevance of the FIG these days: I can't imagine the FIG having an influence over the development of, for example, PhpStorm; and there are very little significant frameworks still following PSRs to the rule.</p>
<p>So, yes, maybe? I'd love to be proven wrong.</p>
<h3 id="python-already-does-this"><a href="#python-already-does-this" class="heading-anchor">#</a> Python already does this</h3>
<p>Python's whole type system is built on type-erasure. So it's interesting to note that what I'm proposing here isn't anything new.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-07-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Would you like some optimism or realism with your estimate, sir? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/optimistic-or-realistic-estimates"/>

                <id>https://www.stitcher.io/blog/optimistic-or-realistic-estimates</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've already made quite a lot of project estimates in my programming career. In these last three years, I've been estimating (and building) lots of features for one specific project.</p>
<p>Over time, some kind of dynamic has grown between our client and I. They ask me "Brent, would it take much work to build … ?", to which I always reply: "everything is possible, it just depends on how much you want to pay"; our client in turn always says "I know! But I need an accurate estimate first!".</p>
<p>Our client has told me several times that my estimates are actually pretty accurate, so I guess I must be doing <em>something</em> right, and I figure I'd share my process — based on nothing but my own experience — with you. Maybe it can help someone out there.</p>
<hr />
<p>First things first, everything that's between 2 and 4 hours of work, I feel comfortable estimating with a buffer in mind. I usually multiply my original idea by a factor of 2, and that seems to result in accurate, small-scale estimates almost every time.</p>
<p>The problems start with features that take longer than a few hours. I don't think the human brain is capable of fully comprehending the scope of work at these scales, and this is a problem that's only growing more significant the larger the scope becomes.</p>
<p>Personally, I have a tendency to approach my estimates very optimistically: "if everything goes right, it'll probably take three weeks". And that's what I used to tell my clients. The problem with that approach is that they only hear "three weeks", and forget about the "if everything goes right" part.</p>
<p>I've now learned that nothing ever goes "just right"; and that there will always be unforeseen changes. I should account for those as well.</p>
<p>So I ask my client: would you like to have an optimistic or realistic estimate? In practice, my realistic estimate is simply the optimistic one, but multiplied by two or three, and represented as a range. For example: if my optimistic estimate is 2 weeks, I'll tell my client it'll take somewhere between 2 weeks and 4 or 5 weeks. If the optimistic estimate already spans months, I prefer to multiply by three, because the larger the estimate, the more things that can change.</p>
<p>I've been using this tactic for years now, and it seem to actually work pretty well.</p>
<p>What I think is key here, is that there's an open communication between my client and myself. There's a level of trust, and I feel safe to just tell them the truth, even though I know sometimes they might have liked a more optimistic version.</p>
<p>This level of trust and communication comes from working together for a couple of years though. It might be lacking at the start of a new project. That's why so many starting projects are under-estimated, and why there's almost always a point in the project where expectations need to be adjusted (with all the consequences that come with it, these usually aren't happy times in a project's lifespan).</p>
<p>So I try to ask clients up front: do you want an optimistic or realistic estimate? I tell them I know the realistic one will be better in the long run.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-07-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.1: before and after ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-81-before-and-after"/>

                <id>https://www.stitcher.io/blog/php-81-before-and-after</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>The release of <a href="/blog/new-in-php-81">PHP 8.1</a> will be here within a few months, and once again there are many features that get me excited! In this post I want to share the real-life impact that PHP 8.1 will have on my own code.</p>
<h2 id="enums"><a href="#enums" class="heading-anchor">#</a> Enums</h2>
<p>A long-awaited feature, <a href="/blog/php-enums">enums</a> are coming! There's little to be said about this one, besides that I'm looking forward to not having to use <a target="_blank" href="https://github.com/spatie/enum">spatie/enum</a> or <a target="_blank" href="https://github.com/myclabs/php-enum">myclabs/php-enum</a> anymore. Thanks for all the years of enum support to those packages, but they are the first I'll ditch when PHP 8.1 arrives and when I change this:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@method</span> static self draft()
 * <span class="hl-value">@method</span> static self published()
 * <span class="hl-value">@method</span> static self archived()
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">StatusEnum</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
}
</pre>
<p><em class="center small">PHP 8.0</em></p>
<p>To this:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">draft</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">published</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">archived</span>;
}
</pre>
<p><em class="center small">PHP 8.1</em></p>
<h2 id="array-unpacking-with-string-keys"><a href="#array-unpacking-with-string-keys" class="heading-anchor">#</a> Array unpacking with string keys</h2>
<p>This one might seem like a small one, but it has bothered me more than once: only list arrays could be unpacked before PHP 8.1:</p>
<pre><span class="hl-variable">$a</span> = [1, 2, 3];
<span class="hl-variable">$b</span> = [4, 5, 6];

<span class="hl-comment">// This is allowed</span>
<span class="hl-variable">$new</span> = [...<span class="hl-variable">$a</span>, ...<span class="hl-variable">$b</span>];
</pre>
<p><em class="center small">PHP 8.0</em></p>
<p>While arrays with string keys cannot:</p>
<pre><span class="hl-variable">$a</span> = ['<span class="hl-value">a</span>' =&gt; 1, '<span class="hl-value">b</span>' =&gt; 2, '<span class="hl-value">c</span>' =&gt; 3];
<span class="hl-variable">$b</span> = ['<span class="hl-value">d</span>' =&gt; 4, '<span class="hl-value">e</span>' =&gt; 5, '<span class="hl-value">f</span>' =&gt; 6];

<span class="hl-variable">$new</span> = [...<span class="hl-variable">$a</span>, ...<span class="hl-variable">$b</span>]; 

<span class="hl-comment">// You'd need to use array_merge in this case</span>
<span class="hl-variable">$new</span> = <span class="hl-property">array_merge</span>(<span class="hl-variable">$a</span>, <span class="hl-variable">$b</span>); 
</pre>
<p><em class="center small">PHP 8.0</em></p>
<p>And so, one of the great features of PHP 8.1 that will make my life easier, is that arrays with string keys can now be unpacked as well!</p>
<pre><span class="hl-variable">$a</span> = ['<span class="hl-value">a</span>' =&gt; 1, '<span class="hl-value">b</span>' =&gt; 2, '<span class="hl-value">c</span>' =&gt; 3];
<span class="hl-variable">$b</span> = ['<span class="hl-value">d</span>' =&gt; 4, '<span class="hl-value">e</span>' =&gt; 5, '<span class="hl-value">f</span>' =&gt; 6];

<span class="hl-comment">// :)</span>
<span class="hl-variable">$new</span> = [...<span class="hl-variable">$a</span>, ...<span class="hl-variable">$b</span>]; 
</pre>
<p><em class="center small">PHP 8.1</em></p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="class-properties:-initializers-and-readonly"><a href="#class-properties:-initializers-and-readonly" class="heading-anchor">#</a> Class properties: initializers and readonly</h2>
<p>Another stunning new feature is once again such a quality-of-life improvement that I've struggled with for years: default arguments in function parameters. Imagine you'd want to set a default state class for a <code>BlogData</code> object. Before PHP 8.1 you'd have to make it nullable and set it in the constructor:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">?BlogState</span> <span class="hl-property">$state</span> = <span class="hl-keyword">null</span>,
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span> ??= <span class="hl-keyword">new</span> <span class="hl-type">Draft</span>();
    }
}
</pre>
<p><em class="center small">PHP 8.0</em></p>
<p>PHP 8.1 allows that <code>new</code> call directly in the function definition. This will be <strong>huge</strong>:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">BlogState</span> <span class="hl-property">$state</span> = <span class="hl-keyword">new</span> <span class="hl-type">Draft</span>(),
    </span>) {
    }
}
</pre>
<p><em class="center small">PHP 8.1</em></p>
<p>Speaking of huge, have I mentioned yet that <strong>readonly</strong> properties are a <em>thing</em> now?!?</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>,
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">BlogState</span> <span class="hl-property">$state</span> = <span class="hl-keyword">new</span> <span class="hl-type">Draft</span>(),
    </span>) {
    }
}
</pre>
<p><em class="center small">PHP 8.1</em></p>
<p>Oh and don't worry about cloning, by the way: <a href="/blog/cloning-readonly-properties-in-php-81">I've got you covered</a>.</p>
<h2 id="first-class-callable-syntax"><a href="#first-class-callable-syntax" class="heading-anchor">#</a> First-class callable syntax</h2>
<p>As if that wasn't enough, there's now also the first-class callable syntax, which gives you a clean way of creating closures from callables.</p>
<p>Previously you'd had to write something like this:</p>
<pre><span class="hl-variable">$strlen</span> = <span class="hl-type">Closure</span>::<span class="hl-property">fromCallable</span>('<span class="hl-value">strlen</span>');
<span class="hl-variable">$callback</span> = <span class="hl-type">Closure</span>::<span class="hl-property">fromCallable</span>([<span class="hl-variable">$object</span>, '<span class="hl-value">method</span>']);
</pre>
<p><em class="center small">PHP 8.0</em></p>
<p>In PHP 8.1, you can do… this:</p>
<pre><span class="hl-variable">$strlen</span> = <span class="hl-property">strlen</span>(...);
<span class="hl-variable">$callback</span> = <span class="hl-variable">$object</span>-&gt;<span class="hl-property">method</span>(...);
</pre>
<p><em class="center small">PHP 8.1</em></p>
<hr />
<p>There are even <a href="/blog/new-in-php-81">more features</a> in PHP 8.1, but these are the ones I'm most excited about. What's your favourite one? Let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a>!</p>
 ]]></summary>

                <updated>2021-07-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ An event-driven mindset ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/an-event-driven-mindset"/>

                <id>https://www.stitcher.io/blog/an-event-driven-mindset</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm working on a new feature for our <a target="_blank" href="https://spatie.be">Spatie</a> website: I'm adding a lightweight form of gamification for our ±10,000 users.</p>
<p>Here's how it works: every time a user watches one of our course videos, every time they complete a video series or a pull request gets merged on GitHub, they'll receive experience points. On top of that, there are also some achievements to reward users for their efforts. For example, there's a "10 pull requests" achievement, as well as a "100 XP" achievement and a few others.</p>
<p>Getting an achievement will reward the user with a digital badge, and in some cases they'll get some kind of certificate as well.</p>
<p>As you can see, it's a small, contained system, with well-defined boundaries. And I'd like to discuss one aspect of it with you today.</p>
<hr />
<p>Let's zoom in on one of the possible flows: the pull request reward system. There are a few steps to it:</p>
<ul>
<li>Register a user's pull request</li>
<li>Award some XP for it</li>
<li>Check whether this pull request is eligible for an achievement</li>
<li>If that's the case, unlock a badge and notify the user</li>
</ul>
<p>Writing this flow down in bullets makes it feel like the pull request reward system is a linear process. In fact, we could write it like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">RegisterPullRequest</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">PullRequestData</span> $data</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// Persist the pull request</span>
        <span class="hl-variable">$pullRequest</span> = <span class="hl-type">PullRequest</span>::<span class="hl-property">create</span>(...<span class="hl-variable">$data</span>);
        
        <span class="hl-variable">$user</span> = <span class="hl-variable">$pullRequest</span>-&gt;<span class="hl-property">user</span>;
        
        <span class="hl-comment">// Award XP</span>
        <span class="hl-variable">$user</span>-&gt;<span class="hl-property">award</span>(10);
        
        <span class="hl-variable">$pullRequestCount</span> = <span class="hl-property">count</span>(<span class="hl-variable">$user</span>-&gt;<span class="hl-property">pullRequests</span>);
        
        <span class="hl-comment">// Determine whether an achievement should be triggered</span>
        <span class="hl-keyword">if</span> (<span class="hl-property">in_array</span>(<span class="hl-variable">$pullRequestCount</span>, [10, 50, 100])) {
            <span class="hl-variable">$achievement</span> = <span class="hl-keyword">new</span> <span class="hl-type">PullRequestAchievement</span>(<span class="hl-variable">$pullRequestCount</span>);
            
            <span class="hl-comment">// Persist the achievement  </span>
            <span class="hl-variable">$user</span>-&gt;<span class="hl-property">unlock</span>(<span class="hl-variable">$achievement</span>);
            
            <span class="hl-comment">// Notify the user</span>
            <span class="hl-variable">$user</span>-&gt;<span class="hl-property">notify</span>(<span class="hl-keyword">new</span> <span class="hl-type">AchievementNotification</span>(<span class="hl-variable">$achievement</span>));
        }
    }
}
</pre>
<p>You might want to refactor this code to separate methods or to use injected actions or service classes if you prefer that style of programming; but I wanted to keep this example concise, to easily clarify a flaw with this approach.</p>
<p>This code clearly represents the ordered steps we listed at first, but there are some hidden costs that come with it; costs that might not be apparent at the time of writing it. I can see two problems hidden within this implementation:</p>
<ul>
<li>We've hard-coded the flow of our program into a fixed order</li>
<li>We've mixed a bunch of responsibilities into one giant class</li>
</ul>
<p>Let's consider "awarding XP" and "unlocking achievements" for a moment. These are two equally important parts of our system. In fact, there's also an achievement for XP being awarded, which means that our current implementation is either lacking, or that there's some added functionality in <code>$user-&gt;award(10);</code> that we don't know about. Let's assume the latter for now.</p>
<p>Even though these two parts are equally important and not directly dependent on each other, we've combined them into one process because it seems like they belong together. However, an unfortunate side effect of doing so, is that our <code>RegisterPullRequest</code> class is growing larger and more complex. Making a change to how pull request achievements are handled, will inevitably take us to the same place where XP rewards are handled.</p>
<p>While you might find it still relatively easy to reason about this isolated (simplified) example, I think most of us can agree that yes, in fact, we're mixing several processes together into one: we're creating some kind of "god-class" that manages and oversees a complex process. We've created a single point of failure. And the more complex our business becomes, this code has the potential to grow larger, more complex and more difficult to reason about.</p>
<p>Speaking for myself, I've written these kinds of classes more than I'd like to admit, and I've seen it applied in many other code bases as well. And from experience, I can tell you they grow much larger than the example we're working with today.</p>
<p>I understand why we get to this point: we'll always need some kind of <em>entry-point</em> in our code, no? A complex process will need to be tied together somehow; we can't avoid that, right?</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>When I first learned about event-driven systems, I was hesitant, maybe even skeptical about them. Events introduce an unavoidable layer of indirectness to our code that makes it more difficult to follow the "flow of our program".  However, keeping everything tightly coupled together <em>also</em> makes it difficult to understand our program flow, just in another way.</p>
<p>The indirectness of event-driven systems is actually the solution to our problem. While event-driven architecture might feel overly complex at first glance, it offers exactly the kind of flexibility we need to model our processes in a clean way — and better yet: in a way that's scalable and maintainable for years to come, much more than our current solution.</p>
<p>In an event-driven system, both "XP rewards" and "achievement unlocks" are treated as two standalone systems. They don't need to know of each other. The only thing they need to know is when a pull request is merged — when an event happens.</p>
<p>Both our systems are now event listeners that will act whenever a <code>PullRequestMerged</code> event is dispatched:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">AchievementManager</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">PullRequestMerged</span> $event</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$pullRequestCount</span> = <span class="hl-type">User</span>::<span class="hl-property">find</span>(<span class="hl-variable">$event</span>-&gt;<span class="hl-property">userId</span>)
            -&gt;<span class="hl-property">pullRequests</span>
            -&gt;<span class="hl-property">count</span>();
        
        <span class="hl-keyword">if</span> (! <span class="hl-property">in_array</span>(<span class="hl-variable">$pullRequestCount</span>, [10, 50, 100])) {
            <span class="hl-keyword">return</span>;
        }
        
        <span class="hl-variable">$achievement</span> = <span class="hl-keyword">new</span> <span class="hl-type">PullRequestAchievement</span>(<span class="hl-variable">$pullRequestCount</span>);
        
        <span class="hl-variable">$user</span>-&gt;<span class="hl-property">unlock</span>(<span class="hl-variable">$achievement</span>);
        
        <span class="hl-variable">$user</span>-&gt;<span class="hl-property">notify</span>(<span class="hl-keyword">new</span> <span class="hl-type">AchievementNotification</span>(<span class="hl-variable">$achievement</span>));
    }
}
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ExperienceManager</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">PullRequestMerged</span> $event</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$user</span> = <span class="hl-type">User</span>::<span class="hl-property">find</span>(<span class="hl-variable">$event</span>-&gt;<span class="hl-property">userId</span>);
        
        <span class="hl-variable">$user</span>-&gt;<span class="hl-property">award</span>(10);
    }
}
</pre>
<p>Now that these two systems are separated, it's much easier to reason about them because they live in isolation.</p>
<p>It doesn't stop there, by the way. What about that "achievement for a given amount of XP" I mentioned at the beginning of this post? <code>ExperienceEarned</code> could be an event itself that our <code>AchievementManager</code> listens for as well:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">AchievementManager</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onPullRequestMerged</span>(<span class="hl-injection"><span class="hl-type">PullRequestMerged</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onExperienceEarned</span>(<span class="hl-injection"><span class="hl-type">ExperienceEarned</span> $event</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$user</span> = <span class="hl-type">User</span>::<span class="hl-property">find</span>(<span class="hl-variable">$event</span>-&gt;<span class="hl-property">userId</span>);
        
        <span class="hl-variable">$currentCount</span> = <span class="hl-variable">$user</span>-&gt;<span class="hl-property">experience</span>;
        
        <span class="hl-variable">$previousCount</span> = <span class="hl-variable">$currentCount</span> - <span class="hl-variable">$event</span>-&gt;<span class="hl-property">amount</span>;
        
        <span class="hl-keyword">if</span> (<span class="hl-variable">$previousCount</span> &gt;= 100) {
            <span class="hl-keyword">return</span>;
        }
        
        <span class="hl-keyword">if</span> (<span class="hl-variable">$currentCount</span> &lt; 100) {
            <span class="hl-keyword">return</span>;
        }
        
        <span class="hl-variable">$achievement</span> = <span class="hl-keyword">new</span> <span class="hl-type">ExperienceAchievement</span>('<span class="hl-value">100 XP!</span>');
        
        <span class="hl-variable">$user</span>-&gt;<span class="hl-property">unlock</span>(<span class="hl-variable">$achievement</span>);
        
        <span class="hl-variable">$user</span>-&gt;<span class="hl-property">notify</span>(<span class="hl-keyword">new</span> <span class="hl-type">AchievementNotification</span>(<span class="hl-variable">$achievement</span>));
    }
}
</pre>
<p>You might even begin to see some opportunities yourself: what about sending a mail after an achievement was unlocked? That could also be driven by an event, so that <code>AchievementManager</code> doesn't need to think about it — we could add a listener that handles mails. What about persisting the pull request to the database? That could be event-driven as well. Achievements that earn experience? The list goes on.</p>
<p>This is the beauty of event-driven systems: by removing tightly-coupled components, we allow room for much more flexibility, while keeping our individual components small and sustainable. Besides that, events are an excellent way of handling micro-service messaging, horizontal scaling and more — though, discussing all these benefits would be too much to cover in one blog post.</p>
<p>Of course, I'm also glossing over some important details: what about eventual consistency? Or what about persisting events themselves? There's much more to event-driven systems than what I showed today, but I <em>did</em> show you the power of thinking with events. That idea alone has revolutionized the way I look at code, and I hope you will give it some more thought as well.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>If you're really interested in the topic, I'd like to share my course on <a target="_blank" href="https://event-sourcing-laravel.com/">event sourcing in Laravel</a> with you. It's an in-depth course that covers many topics related to event-driven systems, and you don't need any prior Laravel or PHP knowledge to learn tons of stuff from it. You can read <a target="_blank" href="https://event-sourcing-laravel.com/starting-with-event-sourcing">a sample chapter</a> or <a target="_blank" href="https://event-sourcing-laravel.com/projectors-in-depth">two</a> if you'd like to know more.</p>
<p>With all of that being said, let me know your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> and leave a like if you appreciated this post, thanks!</p>
 ]]></summary>

                <updated>2021-07-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.1: cloning and changing readonly properties ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/cloning-readonly-properties-in-php-81"/>

                <id>https://www.stitcher.io/blog/cloning-readonly-properties-in-php-81</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><strong>Note: PHP 8.3 adds a built-in way of cloning readonly properties, although it's rather limited in its possibilities. <a href="/blog/cloning-readonly-properties-in-php-83">Read more</a>.</strong></p>
<p>In <a href="/blog/new-in-php-81">PHP 8.1</a>, <a href="/blog/php-81-readonly-properties">readonly properties</a> aren't allowed to be overridden as soon as they are initialized. That also means that cloning an object and changing one of its readonly properties isn't allowed. It's likely that PHP will get some kind of <code>clone with</code> functionality in the future, but for now we'll have to work around the issue.</p>
<p>Let's imagine a simple DTO class with readonly properties:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>, 
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$author</span>,
    </span>) {}
}
</pre>
<p>PHP 8.1 would throw an error when you'd clone a post object and tried to override one of its readonly properties:</p>
<pre><span class="hl-variable">$postA</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(<span class="hl-property">title</span>: '<span class="hl-value">a</span>', <span class="hl-property">author</span>: '<span class="hl-value">Brent</span>');

<span class="hl-variable">$postB</span> = <span class="hl-keyword">clone</span> <span class="hl-variable">$postA</span>;
<span class="hl-variable">$postB</span>-&gt;<span class="hl-property">title</span> = '<span class="hl-value">b</span>';

<span class="hl-property">Error</span>: Cannot modify <span class="hl-keyword">readonly</span> property <span class="hl-type">Post</span>::<span class="hl-property">$title</span>
</pre>
<p>The reason why this happens is because the current readonly implementation will only allow a value to be set as long as it's <a href="/blog/typed-properties-in-php-74#uninitialized">uninitialized</a>. Since we're cloning an object that already had a value assigned to its properties, we cannot override it.</p>
<p>It's very likely PHP will add some kind of mechanism to clone objects and override readonly properties in the future, but with the feature freeze for PHP 8.1 coming up, we can be certain this won't be included for now.</p>
<p>So, at least for PHP 8.1, we'll need a way around this issue. Which is exactly what I did, and why I created a package that you can use as well: <a target="_blank" href="https://github.com/spatie/php-cloneable">https://github.com/spatie/php-cloneable</a>.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>Here's how it works. First you download the package using composer, and next use the <code>Spatie\Cloneable\Cloneable</code> trait in all classes you want to be cloneable:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Spatie\Cloneable\Cloneable</span>;

<span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">Cloneable</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>, 
        <span class="hl-keyword">public</span> <span class="hl-keyword">readonly</span> <span class="hl-type">string</span> <span class="hl-property">$author</span>
    </span>) {}
}
</pre>
<p>Now our <code>Post</code> objects will have a <code>with</code> method that you can use to clone <em>and</em> override properties with:</p>
<pre><span class="hl-variable">$postA</span> = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(<span class="hl-property">title</span>: '<span class="hl-value">a</span>', <span class="hl-property">author</span>: '<span class="hl-value">Brent</span>');

<span class="hl-variable">$postB</span> = <span class="hl-variable">$postA</span>-&gt;<span class="hl-property">with</span>(<span class="hl-property">title</span>: '<span class="hl-value">b</span>');
<span class="hl-variable">$postC</span> = <span class="hl-variable">$postA</span>-&gt;<span class="hl-property">with</span>(<span class="hl-property">title</span>: '<span class="hl-value">c</span>', <span class="hl-property">author</span>: '<span class="hl-value">Freek</span>');
</pre>
<p>There are of course a few caveats:</p>
<ul>
<li>this package will skip calling the constructor when cloning an object, meaning any logic in the constructor won't be executed; and</li>
<li>the <code>with</code> method will be a shallow clone, meaning that nested objects aren't cloned as well.</li>
</ul>
<p>I imagine this package being useful for simple data-transfer and value objects; which are exactly the types of objects that readonly properties were designed for to start with.</p>
<p>For my use cases, this implementation will suffice. And since I believe in <a href="/blog/opinion-driven-design">opinion-driven design</a>, I'm also not interested in added more functionality to it: this package solves one specific problem, and that's good enough.</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-07-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What about typed request classes? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/what-about-request-classes"/>

                <id>https://www.stitcher.io/blog/what-about-request-classes</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In some of our larger Laravel projects, we prefer to map request data to data transfer objects. By doing so we gain static analysis insights in what kind of data we're actually dealing with.</p>
<p>Such a request/dto setup usually looks something like this. Here's the request class handling validation of raw incoming data:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostEditRequest</span> <span class="hl-keyword">extends</span> <span class="hl-type">Request</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">rules</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            '<span class="hl-value">title</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">string</span>', '<span class="hl-value">unique:posts,title</span>', '<span class="hl-value">max:255</span>'],
            '<span class="hl-value">status</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">string</span>'],
            '<span class="hl-value">body</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">string</span>'],
            '<span class="hl-value">date</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">date_format:Y-m-d</span>'],
            '<span class="hl-value">author_id</span>' =&gt; ['<span class="hl-value">nullable</span>', '<span class="hl-value">exists:authors,id</span>'],
            '<span class="hl-value">tags</span>' =&gt; [<span class="hl-keyword">new</span> <span class="hl-type">CollectionRule</span>(<span class="hl-type">Tag</span>::<span class="hl-keyword">class</span>)],
        ];
    }
}
</pre>
<p>And here's the DTO that represents that data in a way so that PHP, our IDE and external static analysers can understand it (note that I'm using our <a target="_blank" href="https://github.com/spatie/data-transfer-object">data-transfer-object</a> package here):</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostEditData</span> <span class="hl-keyword">extends</span> <span class="hl-type">DataTransferObject</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">PostStatus</span> <span class="hl-property">$status</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">Carbon</span> <span class="hl-property">$date</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">?string</span> <span class="hl-property">$authorId</span>;
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">CastWith</span>(<span class="hl-type">ArrayCaster</span>::<span class="hl-keyword">class</span>, <span class="hl-property">itemType</span>: <span class="hl-type">Tag</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$tags</span>;
}
</pre>
<p>Finally, there's the controller in between that converts the validated request data to a DTO and passes it to an action class to be used in our business processes:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostEditController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">UpdatePostAction</span> $updatePost,
        <span class="hl-type">Post</span> $post, 
        <span class="hl-type">PostEditRequest</span> $request,
    </span>) {
        <span class="hl-keyword">return</span> <span class="hl-variable">$updatePost</span>(
            <span class="hl-property">post</span>: <span class="hl-variable">$post</span>,
            <span class="hl-property">data</span>: <span class="hl-keyword">new</span> <span class="hl-type">PostEditData</span>(...<span class="hl-variable">$request</span>-&gt;<span class="hl-property">validated</span>()), 
        );
    }
}
</pre>
<p>I've been thinking about the overhead that's associated with this two-step request/dto transformation. In the end, we only really care about a valid, typed representation of the data that's sent to our server, we don't really care about working with an array of raw request data.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>So why not do exactly that: have a way for our request classes to be properly typed, without the overhead of having to transform it manually to a DTO?</p>
<p>I could build up some suspense here to get you all excited about it, but I trust my readers to be able to draw their own, informed conclusions, so I'm just going to show you what it would look like in the end:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostEditRequest</span> <span class="hl-keyword">extends</span> <span class="hl-type">Request</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Rule</span>(<span class="hl-type">UniquePostRule</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Max</span>(255)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">PostStatus</span> <span class="hl-property">$status</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>;
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Date</span>('<span class="hl-value">Y-m-d</span>')]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-type">Carbon</span> <span class="hl-property">$date</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">?string</span> <span class="hl-property">$authorId</span>;
    
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Rule</span>(<span class="hl-type">CollectionRule</span>::<span class="hl-keyword">class</span>, <span class="hl-property">type</span>: <span class="hl-type">Tag</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$tags</span>;
}
</pre>
<p>Some people might say we're combining two responsibilities in one class: validation and data representation. They are right, but I'd say the old approach wasn't any different. Take a look again at the <code>rules</code> method in our old request:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostEditRequest</span> <span class="hl-keyword">extends</span> <span class="hl-type">Request</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">rules</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            '<span class="hl-value">title</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">string</span>', '<span class="hl-value">unique:posts,title</span>', '<span class="hl-value">max:255</span>'],
            '<span class="hl-value">status</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">string</span>'],
            '<span class="hl-value">body</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">string</span>'],
            '<span class="hl-value">date</span>' =&gt; ['<span class="hl-value">required</span>', '<span class="hl-value">date_format:Y-m-d</span>'],
            '<span class="hl-value">author_id</span>' =&gt; ['<span class="hl-value">nullable</span>', '<span class="hl-value">exists:authors,id</span>'],
            '<span class="hl-value">tags</span>' =&gt; [<span class="hl-keyword">new</span> <span class="hl-type">CollectionRule</span>(<span class="hl-type">Tag</span>::<span class="hl-keyword">class</span>)],
        ];
    }
}
</pre>
<p>We're also validating type information here, it's just more hidden and can't be interpreted by an IDE or other static analyser. The only thing I suggest we do different is to properly use PHP's built-in type system to its full extent, and fill the gaps for more complex validation rules with <a target="_blank" href="/blog/attributes-in-php-8">attributes</a>.</p>
<p>Finally, our controller could be refactored like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostEditController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">UpdatePostAction</span> $updatePost,
        <span class="hl-type">Post</span> $post, 
        <span class="hl-type">PostEditRequest</span> $data,
    </span>) {
        <span class="hl-keyword">return</span> <span class="hl-variable">$updatePost</span>(
            <span class="hl-property">post</span>: <span class="hl-variable">$post</span>,            <span class="hl-property">data</span>: <span class="hl-keyword">new</span> <span class="hl-type">PostEditData</span>(...<span class="hl-variable">$request</span>-&gt;<span class="hl-property">validated</span>()),            <span class="hl-property">data</span>: <span class="hl-variable">$data</span>, 
        );
    }
}
</pre>
<p>I didn't just come up with this idea by the way, there are a number of modern web frameworks doing exactly this:</p>
<ul>
<li>
<a target="_blank" href="https://api.rocket.rs/master/rocket/form/validate/index.html">Rocket in Rust</a>
</li>
<li>
<a target="_blank" href="https://docs.microsoft.com/en-us/previous-versions/aspnet/hh882339(v=vs.110)">ASP.NET MVC</a>
</li>
<li>
<a target="_blank" href="https://docs.rs/actix-web-validator/2.1.1/actix_web_validator/">Actix in Rust</a>
</li>
</ul>
<p>And, finally: I don't think implementing this in Laravel would be all that difficult. We could even create a standalone package for it. All we need to do is build the request rules dynamically based on the public properties of the request, and fill them whenever a request comes in. I reckon the biggest portion of work is in creating the attributes to support all of Laravel's validation rules.</p>
<p>Anyway, I'm just throwing the idea out there to see what people think of it. Feel free to share your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd/status/1409808574860214276">Twitter</a> with me.</p>
 ]]></summary>

                <updated>2021-06-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP version stats: July, 2021 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-version-stats-july-2021"/>

                <id>https://www.stitcher.io/blog/php-version-stats-july-2021</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Last month, Jordi announced he'd be <a target="_blank" href="https://blog.packagist.com/sunsetting-the-php-version-stats-blog-series/">sunsetting</a> his PHP Version Stats blog series, so that he can focus on other types of content. As a replacement, he made <a target="_blank" href="https://packagist.org/php-statistics">a dashboard</a> with live version stats that you can check out any time you want.</p>
<p>I made sure to let Jordi know how much I appreciated all the work he put into this, but also told him I felt kind of sad the series would end. While real-time stats are definitely useful, I did enjoy the occasional post that popped up every 6 months or so. They were a good interpretation of the data, and always sparked interesting discussions.</p>
<p>So I asked Jordi if he'd be ok with me continuing the series, which he was. And so, here we are, with a brand new version stats update!</p>
<p>I will keep a slightly different schedule though: I'll post in July and January, because I'm interested in seeing early adaption of the newest PHP version a month or so after it's released (which is usually at the end of November). I admit I'm two days early with this one, that's because of some upcoming holiday plans.
And one more disclaimer: the <a target="_blank" href="https://packagist.org/php-statistics">data</a> used in this post only looks at the composer ecosystem, and while composer represents a large part of the PHP community, it doesn't represent the whole.</p>
<p>With all of that being said, let's dive in!</p>
<hr />
<h2 id="usage-statistics"><a href="#usage-statistics" class="heading-anchor">#</a> Usage Statistics</h2>
<p>Let's start with the raw numbers: the percentage of PHP versions being used:</p>
<table>
<tr class="table-head">
    <td>Version</td>
    <td>%</td>
</tr>
<tr>
    <td>8.0</td>
    <td>14.7</td>
</tr>
<tr>
    <td>7.4</td>
    <td>46.8</td>
</tr>
<tr>
    <td>7.3</td>
    <td>19.2</td>
</tr>
<tr>
    <td>7.2</td>
    <td>10.4</td>
</tr>
<tr>
    <td>7.1</td>
    <td>3.8</td>
</tr>
<tr>
    <td>7.0</td>
    <td>1.3</td>
</tr>
<tr>
    <td>5.6</td>
    <td>1.1</td>
</tr>
</table>
<p>Note that I've excluded versions with less than 1% usage, in practice this means everything older than 5.6, as well as 8.1 (which hasn't been released yet) is excluded. Let's visualise this year's data and compare it to last year's:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2021-july-01.svg"><img src="/resources/img/blog/version-stats/2021-july-01.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2021-july-01.svg">Evolution of version usage, now and in May, 2020</a></em></p>
<p>PHP 7.4 has seen significant growth compared to last year. In fact, it looks like many people went straight from older versions to 7.4. Let's hope we'll be able to observe the same trend next year for PHP 8. Major version updates tend to take a little longer though; I assume that's because developers are wary of the breaking changes associated with them. Good news though: the update from PHP 7.4 to PHP 8 is actually surprisingly easy, thanks to the deprecation work that has been done in the 7.x series. It might be worth considering updating soon, not only because active support for PHP 7.4 ends in <a target="_blank" href="https://www.php.net/supported-versions.php">less than half a year</a>, but also because PHP 8 brings tons of <a href="/blog/new-in-php-8">new and useful features</a>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>Next, let's take a look at the all-time evolution chart, which also clearly visualizes the growth of PHP 7.4:</p>
<div class="image-noborder image-wide"></div>
<p><a href="/resources/img/blog/version-stats/2021-july-02.svg"><img src="/resources/img/blog/version-stats/2021-july-02.svg" srcset="" sizes="" alt=""></img></a></p>
<p><em class="center small"><a href="/resources/img/blog/version-stats/2021-july-02.svg">All time evolution</a></em></p>
<p>I want to emphasize once more that the update from PHP 7.4 to 8 isn't all that hard, and truly worth investing a little time in. There are tools like <a target="_blank" href="https://getrector.org/">Rector</a> and <a target="_blank" href="https://github.com/FriendsOfPHP/PHP-CS-Fixer">PHP CS Fixer</a> that can help make the upgrade even more smooth.</p>
<h2 id="required-versions"><a href="#required-versions" class="heading-anchor">#</a> Required versions</h2>
<p>I've used Nikita's <a target="_blank" href="https://github.com/nikic/popular-package-analysis">popular package analyzer</a> to download the 1000 most popular composer packages, and wrote a little script to get the lowest version they support from their <code>composer.json</code>. Here are the results:</p>
<table>
<tr class="table-head">
    <td>Version</td>
    <td>#</td>
</tr>
<tr>
    <td>8.0</td>
    <td>117</td>
</tr>
<tr>
    <td>7.4</td>
    <td>56</td>
</tr>
<tr>
    <td>7.3</td>
    <td>133</td>
</tr>
<tr>
    <td>7.2</td>
    <td>142</td>
</tr>
<tr>
    <td>7.1</td>
    <td>182</td>
</tr>
<tr>
    <td>7.0</td>
    <td>31</td>
</tr>
<tr>
    <td>5.6</td>
    <td>61</td>
</tr>
<tr>
    <td>5.5</td>
    <td>43</td>
</tr>
<tr>
    <td>5.4</td>
    <td>41</td>
</tr>
<tr>
    <td>5.3</td>
    <td>97</td>
</tr>
<tr>
    <td>5.2</td>
    <td>12</td>
</tr>
<tr>
    <td>5.0</td>
    <td>2</td>
</tr>
</table>
<p>You'll notice there are a little less than 1000 packages included, that's because some of the 1000 most popular packages don't specifically require a PHP version.</p>
<p>It's interesting how 7.1 is still the minimum required version for almost 20% of the analysed packages. 7.2 adds another 15%. In fact, <strong>only 18% of the most popular packages require an actively supported version as their minimum</strong>.</p>
<p>I'm an open <a href="https://spatie.be/open-source?search=&amp;sort=-downloads">source maintainer</a> myself, and I believe we have a responsibility to the community to help keep their software stack safe and secure. This starts with only supporting active PHP versions. So I hope to see this number shift more towards PHP 8 in the near future because, remember, PHP 7.4 is already nearing its end!</p>
<p>That being said, it's clear that many users <em>are</em> moving towards a supported PHP version, despite lower package requirements. I am a little worried about the move to PHP 8 though, and I hope we'll see broader adoption soon.</p>
<hr />
<p>What are your thoughts on these stats? Are you looking forward to <a href="/blog/new-in-php-81">PHP 8.1</a>? Let me know your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> and subscribe to <a href="/newsletter/subscribe">my newsletter</a> if you want to be kept up-to-date about these posts!</p>
 ]]></summary>

                <updated>2021-06-28T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Opinion-driven design ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/opinion-driven-design"/>

                <id>https://www.stitcher.io/blog/opinion-driven-design</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/yBLVBwiAfrM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</p>
<p>I once worked at a company that wrote and maintained an in-house framework. Over the course of ten years, they probably
made around 250 websites and applications with it. Despite many shortcomings, the company kept using their framework for
a simple reason: they were in control.</p>
<p>Thanks to that control, they were able to tailor their framework to their own needs without any overhead. And, while I
would argue that using popular, community-backed frameworks is almost always the better
choice over writing your own , I can appreciate some of their reasoning.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>Except, in the end, they utterly failed in creating what they originally set out to do. Instead of a tool shaped
specifically for their needs, the framework's core developers often wanted flexibility: they dreamt of open sourcing
their framework and it growing popular, so it needed to handle as many cases as possible to reach as wide an audience as
possible. And thus, flexibility and configuration were often prioritized, even though they rarely added much — if any —
value to company projects. The core developers were always able to convince the not-so-technical managers; while in
reality, the design and flexibility of this framework was often just a burden for me and my colleagues to deal with.</p>
<p>This mindset of "high configurability and flexibility" is, unfortunately, common in software design. I'm not sure
why, but somehow programmers — myself included — often think they need to account for every possible outcome, even when those
outcomes aren't relevant to their use cases. Many of us deal with some kind of fear of losing our audience if the code we're writing isn't able to handle the most specific of specific edge cases. A very counter-productive thought.</p>
<hr />
<p>Lately I've come to appreciate an opinion-driven approach to software design. Especially in the <a target="_blank" href="https://spatie.be/open-source?search=&amp;sort=-downloads">open source</a> world, where you're writing code for others to use. I used to tell myself I'd need to write more code for more flexibility "if I want this package to grow popular".</p>
<p>I don't believe that anymore.</p>
<p>These days, I prefer one way of solving a problem, instead of offering several options. As an open source maintainer, I realise that not everyone might like the solutions I come up with as much as I do; but in the end, if the job gets done, if my code is reliable, clear and useful; there rarely are any complaints. So I started to prefer opinion-driven design when I realised that flexibility comes with a price that is often not worth paying.</p>
<p>I'm not the only one benefiting by the way. When users of my open source code only get one way of doing something, they
don't have to be worried about micro-decisions that wouldn't affect the end result. And that, for me, is good software
design: allowing programmers to focus on decisions that really matter and offer value to their projects and clients;
instead of wasting time on unnecessary details.</p>
<p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/yBLVBwiAfrM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2021-06-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What about config builders? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/what-about-config-builders"/>

                <id>https://www.stitcher.io/blog/what-about-config-builders</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been tinkering with a hobby project lately: a small framework to get more familiar with <a href="/blog/new-in-php-8">PHP 8</a>, and try out some random ideas floating in my head. It's nothing too serious, but it's a fun exercise.</p>
<p>Most of these ideas are born from my daily experience with Laravel, and more specifically from the little annoyances I have with it. Now, don't get me wrong: I think Laravel is one of the best frameworks out there when it comes to modern PHP development and it's only natural that it has a quirk here and there, after a decade of development.</p>
<p>So this definitely isn't a Laravel-rant, rather it's just a thought experiment in dealing with one of those little annoyances.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>So, Laravel has these PHP config files, right. Here's one example (this one is <code>auth.php</code>, if you're wondering):</p>
<pre>&lt;?php

<span class="hl-keyword">return</span> [

    <span class="hl-comment">/*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication &quot;guard&quot; and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */</span>

    '<span class="hl-value">defaults</span>' =&gt; [
        '<span class="hl-value">guard</span>' =&gt; '<span class="hl-value">web</span>',
        '<span class="hl-value">passwords</span>' =&gt; '<span class="hl-value">users</span>',
    ],

    <span class="hl-comment">/*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: &quot;session&quot;, &quot;token&quot;
    |
    */</span>

    '<span class="hl-value">guards</span>' =&gt; [
        '<span class="hl-value">web</span>' =&gt; [
            '<span class="hl-value">driver</span>' =&gt; '<span class="hl-value">session</span>',
            '<span class="hl-value">provider</span>' =&gt; '<span class="hl-value">users</span>',
        ],

        '<span class="hl-value">api</span>' =&gt; [
            '<span class="hl-value">driver</span>' =&gt; '<span class="hl-value">token</span>',
            '<span class="hl-value">provider</span>' =&gt; '<span class="hl-value">users</span>',
            '<span class="hl-value">hash</span>' =&gt; <span class="hl-keyword">false</span>,
        ],
    ],

    <span class="hl-comment">/*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: &quot;database&quot;, &quot;eloquent&quot;
    |
    */</span>

    '<span class="hl-value">providers</span>' =&gt; [
        '<span class="hl-value">users</span>' =&gt; [
            '<span class="hl-value">driver</span>' =&gt; '<span class="hl-value">eloquent</span>',
            '<span class="hl-value">model</span>' =&gt; <span class="hl-type">App\Models\User</span>::<span class="hl-keyword">class</span>,
        ],

        <span class="hl-comment">// 'users' =&gt; [</span>
        <span class="hl-comment">//     'driver' =&gt; 'database',</span>
        <span class="hl-comment">//     'table' =&gt; 'users',</span>
        <span class="hl-comment">// ],</span>
    ],

    <span class="hl-comment">/*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that the reset token should be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */</span>

    '<span class="hl-value">passwords</span>' =&gt; [
        '<span class="hl-value">users</span>' =&gt; [
            '<span class="hl-value">provider</span>' =&gt; '<span class="hl-value">users</span>',
            '<span class="hl-value">table</span>' =&gt; '<span class="hl-value">password_resets</span>',
            '<span class="hl-value">expire</span>' =&gt; 60,
            '<span class="hl-value">throttle</span>' =&gt; 60,
        ],
    ],

    <span class="hl-comment">/*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */</span>

    '<span class="hl-value">password_timeout</span>' =&gt; 10800,

];
</pre>
<p>While I think PHP configuration files are far superior to, for example, YAML or XML configuration; there's one thing that annoys me quite a lot with it: there are no IDE insights in what kind of config values are available in this array, let alone which type of values they require.</p>
<p>To counteract this problem, the official Laravel config files have these inline doc blocks explaining each config entry. Most serious third party packages also provide such doc blocks.</p>
<p>With PHP 8 and <a href="/blog/php-8-named-arguments">named arguments</a> though, there's a better solution available: config objects that know exactly what kind of data they'd need.</p>
<p>Here's what I'd imagine the <code>auth.php</code> would look like with it:</p>
<pre><span class="hl-keyword">return</span> <span class="hl-type">AuthConfig</span>::<span class="hl-property">make</span>()
    -&gt;<span class="hl-property">defaults</span>(
        <span class="hl-property">guard</span>: '<span class="hl-value">web</span>',
        <span class="hl-property">passwords</span>: '<span class="hl-value">users</span>',
    )
    -&gt;<span class="hl-property">guards</span>(
        <span class="hl-property">web</span>: <span class="hl-type">GuardConfig</span>::<span class="hl-property">make</span>()
            -&gt;<span class="hl-property">driver</span>('<span class="hl-value">session</span>')
            -&gt;<span class="hl-property">provider</span>('<span class="hl-value">users</span>'),
        <span class="hl-property">api</span>: <span class="hl-type">GuardConfig</span>::<span class="hl-property">make</span>()
            -&gt;<span class="hl-property">driver</span>('<span class="hl-value">token</span>')
            -&gt;<span class="hl-property">provider</span>('<span class="hl-value">users</span>')
            -&gt;<span class="hl-property">hash</span>(<span class="hl-keyword">false</span>),
    )
    -&gt;<span class="hl-property">providers</span>(
        <span class="hl-property">users</span>: <span class="hl-type">AuthProviderConfig</span>::<span class="hl-property">make</span>()
            -&gt;<span class="hl-property">driver</span>('<span class="hl-value">eloquent</span>')
            -&gt;<span class="hl-property">model</span>(<span class="hl-type">User</span>::<span class="hl-keyword">class</span>),
    )
    -&gt;<span class="hl-property">passwords</span>(
        <span class="hl-property">users</span>: <span class="hl-type">PasswordConfig</span>::<span class="hl-property">make</span>()
            -&gt;<span class="hl-property">provider</span>('<span class="hl-value">users</span>')
            -&gt;<span class="hl-property">table</span>('<span class="hl-value">password_resets</span>')
            -&gt;<span class="hl-property">expire</span>(60)
            -&gt;<span class="hl-property">throttle</span>(60)
    )
    -&gt;<span class="hl-property">passwordTimeout</span>(10800);
</pre>
<p>Thanks to named arguments and their support for <a href="/blog/php-8-named-arguments#named-arguments-in-depth">variadic functions</a>, we end up with a conciser syntax, while still having all documentation available to us: it's added as property types and doc blocks in these config objects, instead of being hard coded in the config files as text.</p>
<p>To me that's the most important value: your IDE tells you what you need to do, instead of having to read documentation — inline or external:</p>
<p><img src="/resources/img/blog/config/config-1.png" srcset="/resources/img/blog/config/config-1-1044x365.png 1044w, /resources/img/blog/config/config-1-852x298.png 852w, /resources/img/blog/config/config-1-1205x421.png 1205w, /resources/img/blog/config/config-1-602x210.png 602w, /resources/img/blog/config/config-1-1348x472.png 1348w" sizes="" alt=""></img></p>
<p>The only thing needed for this to work is some kind of interface that requires these config builders, as I like to call them, to implement a <code>toArray</code> method. You could go one step further and turn things around by always using config objects instead of arrays, which would allow you to also make use of their built-in documentation when reading config, and not only when initializing it. That's a bit more of a aggressive change though.</p>
<p>Here's what a config builder implementation would look like:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">AuthConfig</span> <span class="hl-keyword">extends</span> <span class="hl-type">ConfigBuilder</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">defaults</span>(<span class="hl-injection">
        <span class="hl-type">?string</span> $guard = <span class="hl-keyword">null</span>,
        <span class="hl-type">?string</span> $password = <span class="hl-keyword">null</span>,
        // …
    </span>): <span class="hl-type">self</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">config</span>['<span class="hl-value">defaults</span>']['<span class="hl-value">guard</span>'] = 
            <span class="hl-variable">$guard</span> 
            ?? <span class="hl-variable">$this</span>-&gt;<span class="hl-property">config</span>['<span class="hl-value">defaults</span>']['<span class="hl-value">guard</span>'] 
            ?? <span class="hl-keyword">null</span>;
            
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">config</span>['<span class="hl-value">defaults</span>']['<span class="hl-value">password</span>'] = 
            <span class="hl-variable">$password</span> 
            ?? <span class="hl-variable">$this</span>-&gt;<span class="hl-property">config</span>['<span class="hl-value">defaults</span>']['<span class="hl-value">password</span>'] 
            ?? <span class="hl-keyword">null</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">guards</span>(<span class="hl-injection">GuardConfig ...$guardConfigs</span>): <span class="hl-type">self</span>
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$guardConfigs</span> <span class="hl-keyword">as</span> <span class="hl-variable">$name</span> =&gt; <span class="hl-variable">$guardConfig</span>) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">config</span>['<span class="hl-value">guards</span>'][<span class="hl-variable">$name</span>] = <span class="hl-variable">$guardConfig</span>-&gt;<span class="hl-property">toArray</span>();
        }

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">passwordTimeout</span>(<span class="hl-injection"><span class="hl-type">int</span> $timeout</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">config</span>['<span class="hl-value">password_timeout</span>'] = <span class="hl-variable">$timeout</span>;
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
}
</pre>
<p>Another improvement I can come up with is by using <a href="/blog/php-enums">enums</a> instead of string values. They will be natively available in <a href="/blog/new-in-php-81">PHP 8.1</a>, but there are also <a href="/blog/php-enums-before-php-81">alternatives</a> out there for older PHP versions.</p>
<p>Let's just assume we're already running PHP 8.1, we could write parts of it like so:</p>
<pre>-&gt;<span class="hl-property">guards</span>(
    <span class="hl-property">web</span>: <span class="hl-type">GuardConfig</span>::<span class="hl-property">make</span>()
        -&gt;<span class="hl-property">driver</span>(<span class="hl-type">Driver</span>::<span class="hl-property">Session</span>)
        -&gt;<span class="hl-property">provider</span>(<span class="hl-type">Provider</span>::<span class="hl-property">Users</span>),
    <span class="hl-property">api</span>: <span class="hl-type">GuardConfig</span>::<span class="hl-property">make</span>()
        -&gt;<span class="hl-property">driver</span>(<span class="hl-type">Driver</span>::<span class="hl-property">Token</span>)
        -&gt;<span class="hl-property">provider</span>(<span class="hl-type">Provider</span>::<span class="hl-property">Users</span>)
        -&gt;<span class="hl-property">hash</span>(<span class="hl-keyword">false</span>),
)
</pre>
<p>These ideas aren't new, by the way. We've been using config objects in some of <a target="_blank" href="https://spatie.be/open-source?search=&amp;sort=-downloads">our packages</a> at Spatie, but we always start from a simple array and convert it when booting the application. There's also PHP CS that uses <a target="_blank" href="https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/v3.14.4/doc/config.rst">the same approach</a>. Also, Symfony just recently <a href="https://symfony.com/blog/new-in-symfony-5-3-config-builder-classes">added support</a> for a fluent interface to build their config files; great!</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>There's one advantage to tinkering with your own framework: you're not constrained by backwards compatibility and legacy. I imagine it might not be trivial to properly support config builders in Laravel, at least not as the default approach. They also become much less useful if you cannot use named arguments, which require PHP 8.</p>
<p>But, who knows? Maybe something similar might get added in the future in Laravel? Or maybe some third-party packages start doing it on their own first. Anyway, I'm going to tinker some more with my custom framework, just for fun!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<p>What's your opinion on config builders? Let me know your thoughts, via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or by <a target="_blank" href="/newsletter/subscribe">subscribing to my newsletter</a>.</p>
 ]]></summary>

                <updated>2021-06-18T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ A new major version of Laravel Event Sourcing ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-new-major-version-of-laravel-event-sourcing"/>

                <id>https://www.stitcher.io/blog/a-new-major-version-of-laravel-event-sourcing</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Today, we released a new version of <a target="_blank" href="https://github.com/spatie/laravel-event-sourcing">spatie/laravel-event-sourcing</a>, version 5 is probably one of the largest releases since the beginning of the package, we've worked several months on it and have been testing it extensively already in our own projects.</p>
<p>Credit where credit is due, many new features were inspired by <a target="_blank" href="https://docs.axoniq.io/reference-guide/">Axon</a>,<br />
a popular event sourcing framework in the Java world, and several people pitched in during the development process.</p>
<p>In this post, I'll walk you through all significant changes, but first I want to mention the course that we've built at Spatie over the last months about event sourcing. If you're working on an event sourced project or thinking about starting one, this course will be of great help. Check it out on <a target="_blank" href="https://event-sourcing-laravel.com/">https://event-sourcing-laravel.com/</a>!</p>
<p><div class="like-container">
    <div class="like placeholder">
        👍
    </div>
    <div class="like unliked hidden">
        👍
    </div>
    <div class="like liked hidden">
        👍 <span class="counter">0</span>
    </div>
</div>
</p>
<h3 id="consistent-event-handling"><a href="#consistent-event-handling" class="heading-anchor">#</a> Consistent event handling</h3>
<p>If you've used previous versions of our package, you might have struggled with how event handlers were registered across classes. Aggregate roots required you to write <code>applyEventName</code> functions, while projectors and reactors had an explicit event mapping.</p>
<p>Whatever class you're writing will now register event handlers the same way: by looking at the type of the event. You don't need any more configuration or naming conventions anymore.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CartAggregateRoot</span> <span class="hl-keyword">extends</span> <span class="hl-type">AggregateRoot</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartAdded</span>(<span class="hl-injection"><span class="hl-type">CartAdded</span> $event</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// Any `CartAdded` event will automatically be matched to this handler</span>
    }
}
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CartProjector</span> <span class="hl-keyword">extends</span> <span class="hl-type">Projector</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartAdded</span>(<span class="hl-injection"><span class="hl-type">CartAdded</span> $event</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// The same goes for projectors and reactors.</span>
    }
}
</pre>
<h3 id="event-queries"><a href="#event-queries" class="heading-anchor">#</a> Event Queries</h3>
<p>Event queries are a new feature that allow you to easily query an event stream without building database projections. You can think of them as in-memory projections that are rebuilt every time you call them.</p>
<p>Here's an example of it in action:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">EarningsForProductAndPeriod</span> <span class="hl-keyword">extends</span> <span class="hl-type">EventQuery</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">int</span> <span class="hl-property">$totalPrice</span> = 0;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">private</span> <span class="hl-type">Period</span> <span class="hl-property">$period</span>,
        <span class="hl-keyword">private</span> <span class="hl-type">Collection</span> <span class="hl-property">$products</span>
    </span>) {
        <span class="hl-type">EloquentStoredEvent</span>::<span class="hl-property">query</span>()
            -&gt;<span class="hl-property">whereEvent</span>(<span class="hl-type">OrderCreated</span>::<span class="hl-keyword">class</span>)
            -&gt;<span class="hl-property">whereDate</span>('<span class="hl-value">created_at</span>', '<span class="hl-value">&gt;=</span>', <span class="hl-variable">$this</span>-&gt;<span class="hl-property">period</span>-&gt;<span class="hl-property">getStart</span>())
            -&gt;<span class="hl-property">whereDate</span>('<span class="hl-value">created_at</span>', '<span class="hl-value">&lt;=</span>', <span class="hl-variable">$this</span>-&gt;<span class="hl-property">period</span>-&gt;<span class="hl-property">getEnd</span>())
            -&gt;<span class="hl-property">cursor</span>()
            -&gt;<span class="hl-property">each</span>(
                <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">EloquentStoredEvent</span> $event</span>) =&gt; <span class="hl-variable">$this</span>-&gt;<span class="hl-property">apply</span>(<span class="hl-variable">$event</span>)
            );
    }

    <span class="hl-keyword">protected</span> <span class="hl-keyword">function</span> <span class="hl-property">applyOrderCreated</span>(<span class="hl-injection"><span class="hl-type">OrderCreated</span> $orderCreated</span>): <span class="hl-type">void</span> 
    {
        <span class="hl-variable">$orderLines</span> = <span class="hl-property">collect</span>(<span class="hl-variable">$orderCreated</span>-&gt;<span class="hl-property">orderData</span>-&gt;<span class="hl-property">orderLineData</span>);

        <span class="hl-variable">$totalPriceForOrder</span> = <span class="hl-variable">$orderLines</span>
            -&gt;<span class="hl-property">filter</span>(<span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">OrderLineData</span> $orderLineData</span>) {
                <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">products</span>-&gt;<span class="hl-property">first</span>(
                    <span class="hl-keyword">fn</span>(<span class="hl-injection"><span class="hl-type">Product</span> $product</span>) =&gt; <span class="hl-variable">$orderLineData</span>-&gt;<span class="hl-property">productEquals</span>(<span class="hl-variable">$product</span>)
                ) !== <span class="hl-keyword">null</span>;
            })
            -&gt;<span class="hl-property">sum</span>(
                <span class="hl-keyword">fn</span>(<span class="hl-injection"><span class="hl-type">OrderLineData</span> $orderLineData</span>) =&gt; <span class="hl-variable">$orderLineData</span>-&gt;<span class="hl-property">totalPriceIncludingVat</span>
            );

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">totalPrice</span> += <span class="hl-variable">$totalPriceForOrder</span>;
    }
}
</pre>
<p>Note that these examples come from the <a target="_blank" href="https://event-sourcing-laravel.com/">Event Sourcing in Laravel</a> book.</p>
<h3 id="aggregate-partials"><a href="#aggregate-partials" class="heading-anchor">#</a> Aggregate Partials</h3>
<p>Aggregate partials allow you to split large aggregate roots into separate classes, while still keeping everything contained within the same aggregate. Partials can record and apply events just like an aggregate root, and can share state between them and their associated aggregate root.</p>
<p>Here's an example of an aggregate partial that handles everything related to item management within a shopping cart:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CartItems</span> <span class="hl-keyword">extends</span> <span class="hl-type">AggregatePartial</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addItem</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $cartItemUuid, 
        <span class="hl-type">Product</span> $product, 
        <span class="hl-type">int</span> $amount
    </span>): <span class="hl-type">self</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">recordThat</span>(<span class="hl-keyword">new</span> <span class="hl-type">CartItemAdded</span>(
            <span class="hl-property">cartItemUuid</span>: <span class="hl-variable">$cartItemUuid</span>,
            <span class="hl-property">productUuid</span>: <span class="hl-variable">$product</span>-&gt;<span class="hl-property">uuid</span>,
            <span class="hl-property">amount</span>: <span class="hl-variable">$amount</span>,
        ));

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">protected</span> <span class="hl-keyword">function</span> <span class="hl-property">applyCartItemAdded</span>(<span class="hl-injection">
        <span class="hl-type">CartItemAdded</span> $cartItemAdded
    </span>): <span class="hl-type">void</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">cartItems</span>[<span class="hl-variable">$cartItemAdded</span>-&gt;<span class="hl-property">cartItemUuid</span>] = <span class="hl-keyword">null</span>;
    }
}
</pre>
<p>And this is how the cart aggregate root would use it:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CartAggregateRoot</span> <span class="hl-keyword">extends</span> <span class="hl-type">AggregateRoot</span>
{
    <span class="hl-keyword">protected</span> <span class="hl-type">CartItems</span> <span class="hl-property">$cartItems</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">cartItems</span> = <span class="hl-keyword">new</span> <span class="hl-type">CartItems</span>(<span class="hl-variable">$this</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addItem</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $cartItemUuid,
        <span class="hl-type">Product</span> $product,
        <span class="hl-type">int</span> $amount
    </span>): <span class="hl-type">self</span> {
        <span class="hl-keyword">if</span> (! <span class="hl-variable">$this</span>-&gt;<span class="hl-property">state</span>-&gt;<span class="hl-property">changesAllowed</span>()) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">CartCannotBeChanged</span>();
        }

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">cartItems</span>-&gt;<span class="hl-property">addItem</span>(<span class="hl-variable">$cartItemUuid</span>, <span class="hl-variable">$product</span>, <span class="hl-variable">$amount</span>);

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
</pre>
<p>Aggregate partials come with the same testing capabilities as aggregate roots, and are a useful way of keeping aggregate-related code maintainable.</p>
<h3 id="command-bus"><a href="#command-bus" class="heading-anchor">#</a> Command bus</h3>
<p>We've added a command bus that can automatically map commands to handlers on aggregate roots:</p>
<pre><span class="hl-keyword">namespace</span> <span class="hl-type">Spatie\Shop\Cart\Commands</span>;

<span class="hl-keyword">use</span> <span class="hl-type">Spatie\Shop\Support\EventSourcing\Attributes\AggregateUuid</span>;
<span class="hl-keyword">use</span> <span class="hl-type">Spatie\Shop\Support\EventSourcing\Attributes\HandledBy</span>;
<span class="hl-keyword">use</span> <span class="hl-type">Spatie\Shop\Support\EventSourcing\Commands\Command</span>;

<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">HandledBy</span>(<span class="hl-type">CartAggregateRoot</span>::<span class="hl-keyword">class</span>)]</span></span>
<span class="hl-keyword">class</span> <span class="hl-type">AddCartItem</span> <span class="hl-keyword">implements</span><span class="hl-type"> Command
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-attribute">#[AggregateUuid]</span> <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$cartUuid</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$cartItemUuid</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">Product</span> <span class="hl-property">$product</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$amount</span>,
    </span>) {
    }
}
</pre>
<p>Whenever this command is dispatched, it will automatically be captured and handled by the associated aggregate root. It even works with aggregate partials:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CartItems</span> <span class="hl-keyword">extends</span> <span class="hl-type">AggregatePartial</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addItem</span>(<span class="hl-injection"><span class="hl-type">AddCartItem</span> $addCartItem</span>): <span class="hl-type">self</span>
    {
        <span class="hl-comment">// …</span>
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">removeItem</span>(<span class="hl-injection"><span class="hl-type">RemoveCartItem</span> $removeCartItem</span>): <span class="hl-type">self</span>
    {
        <span class="hl-comment">// …</span>
    }
}    
</pre>
<hr />
<p>Besides these new features, there are also some quality-of-life changes across the board:</p>
<ul>
<li>The minimum required PHP version is now 8.0</li>
<li>The minimum required Laravel version is now 8.0</li>
<li>There's better support for <a target="_blank" href="https://github.com/spatie/laravel-event-sourcing/discussions/214">handling concurrency</a> within the same aggregate root instance</li>
<li>There's a way to <a target="_blank" href="https://github.com/spatie/laravel-event-sourcing/discussions/181">fake reactors and projectors</a>
</li>
<li>There's an <a target="_blank" href="https://github.com/spatie/laravel-event-sourcing/blob/main/src/StoredEvents/Models/EloquentStoredEventQueryBuilder.php">improved event query builder</a>
</li>
<li>And <a target="_blank" href="https://github.com/spatie/laravel-event-sourcing/blob/v5/CHANGELOG.md">more</a>
</li>
</ul>
<hr />
<p>All in all, I'm very exited for this new release. All the new features are also used in our real-life projects, so we know from experience how useful they are in complex applications. Of course, a blog post can't discuss all the details and the thought process behind this new version, so make sure to read <a target="_blank" href="https://event-sourcing-laravel.com/">the book</a> if you want in-depth knowledge about all of these features, and more.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-06-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Why we need multi-line short closures in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/why-we-need-multi-line-short-closures-in-php"/>

                <id>https://www.stitcher.io/blog/why-we-need-multi-line-short-closures-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><a href="/blog/new-in-php-81">PHP 8.1</a> is already taking shape quite well, yet there's one feature I'd love to see added, that's still being discussed: multi-line short closures. The <a target="_blank" href="https://wiki.php.net/rfc/auto-capture-closure">RFC</a> calls them "Auto-capturing multi-statement closures" but I hope you don't mind me using the somewhat shorter name.</p>
<p>If you're on an <a target="_blank" href="https://www.php.net/supported-versions.php">actively supported</a> PHP version, you already know about <a href="/blog/short-closures-in-php">short closures</a> — a.k.a. "arrow functions". And, most importantly, one of their biggest drawbacks: they only <a href="/blog/short-closures-in-php#no-multi-line">support one-line expressions</a>, which are also used as the return value.</p>
<p>The multi-line short closures RFC by <a target="_blank" href="https://twitter.com/enunomaduro">Nuno</a> and <a target="_blank" href="https://twitter.com/crell">Larry</a> aims to solve that problem, in — what I think is — an elegant way.</p>
<p>Some people are skeptical about this RFC though, and I want to address their arguments and share why I think it's still a worthwhile addition. Though first, I'll show you what the RFC is about. Keep in mind this is a proposal, and not added to PHP yet!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>A quick refresher, this is what arrow functions in PHP look like today:</p>
<pre><span class="hl-variable">$getTitle</span> = <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) =&gt; <span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span>;
</pre>
<p>And this is what the RFC proposes:</p>
<pre><span class="hl-variable">$date</span> = <span class="hl-property">now</span>();

<span class="hl-variable">$getSlug</span> = <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {
    <span class="hl-variable">$slug</span> = <span class="hl-type">Str</span>::<span class="hl-property">slug</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span>);
    
    <span class="hl-keyword">return</span> <span class="hl-variable">$date</span> . <span class="hl-variable">$slug</span>;
}
</pre>
<p>There are two important things to note about multi-line short closures:</p>
<ul>
<li>they have access to the variables in the upper scope without needing <code>use</code>; and</li>
<li>they <em>don't</em> automatically return the last expression, which makes sense since there can be several expressions in a multi-line closure.</li>
</ul>
<p>You might have already noticed it, but the RFC introduces an elegant kind of symmetry in how you can create closures:</p>
<ul>
<li>on the one hand there's <code>function</code> and <code>fn</code>, the first one doesn't auto-capture variables from the outside, the second one does; and</li>
<li>on the other hand there's <code>{ … }</code> or <code>=&gt;</code>, using curly brackets allow you to write multiple lines, while <code>=&gt;</code> only accepts one expression, but also returns it.</li>
</ul>
<p>Because of this symmetry, all of the following code samples are possible and all of them behaving a little differently.</p>
<p>Here's a closure that doesn't auto-capture outer scope, with multiple lines:</p>
<pre><span class="hl-variable">$date</span> = <span class="hl-property">now</span>();

<span class="hl-variable">$getSlug</span> = <span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">Post</span> $post) use ($date</span>) {
    <span class="hl-variable">$slug</span> = <span class="hl-type">Str</span>::<span class="hl-property">slug</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span>);
    
    <span class="hl-keyword">return</span> <span class="hl-variable">$date</span> . <span class="hl-variable">$slug</span>;
}
</pre>
<p>Next, a closure that does capture outer scope and immediately returns the result:</p>
<pre><span class="hl-variable">$date</span> = <span class="hl-property">now</span>();

<span class="hl-variable">$getSlug</span> = <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) =&gt; <span class="hl-variable">$date</span> . <span class="hl-type">Str</span>::<span class="hl-property">slug</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span>);
</pre>
<p>And finally — proposed by the RFC — a closure that does capture outer scope, but still allows multiple lines:</p>
<pre><span class="hl-variable">$date</span> = <span class="hl-property">now</span>();

<span class="hl-variable">$getSlug</span> = <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">Post</span> $post</span>) {
    <span class="hl-variable">$slug</span> = <span class="hl-type">Str</span>::<span class="hl-property">slug</span>(<span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span>);
    
    <span class="hl-keyword">return</span> <span class="hl-variable">$date</span> . <span class="hl-variable">$slug</span>;
}
</pre>
<p>If you're counting, you know that one option is still missing: a closure that doesn't auto-capture outer scope and immediately returns a value:</p>
<pre>$date = now();

$getSlug = function (Post $post) use ($date) 
    =&gt; $date . Str::slug($post-&gt;title);
</pre>
<p>The RFC lists this last one as a possible future addition, but doesn't cover it right now.</p>
<hr />
<p>With the background info out of the way, let's look at some counter arguments as to why some people don't like this change.</p>
<h3 id="auto-capturing-outer-scope-can-lead-to-bugs"><a href="#auto-capturing-outer-scope-can-lead-to-bugs" class="heading-anchor">#</a> Auto-capturing outer scope can lead to bugs</h3>
<p>Some people voice their fear about auto-capturing variables from the outer scope, especially that it can lead to unclear code in the long run and thus, bugs.</p>
<p>I've got a few arguments against that fear.</p>
<p>First, auto-capturing is already supported by PHP in the current short closures, there's nothing about this RFC that changes that. The arrow function RFC passed with 51 votes for, and 8 against after a <a target="_blank" href="https://externals.io/message/104693#104693">thorough discussion</a>, and has been used extensively in lots of projects since — take a look at some popular OSS frameworks if you want some examples. Clear signs that this particular behaviour is wanted by the majority of people, whether you're afraid of it or not.</p>
<p>Nikita also shares this opinion:</p>
<blockquote>
<p>I'm generally in favor of supporting auto-capture for multi-line closures. I think that extensive experience in other programming languages has shown that auto-capture does not hinder readability of code, and I don't see any particular reason why the effects in PHP would be different. — <a target="_blank" href="https://externals.io/message/113740#114239">https://externals.io/message/113740#114239</a></p>
</blockquote>
<p>Auto-capturing outer scope might not be your preferred way of coding, but that doesn't mean the idea should be dismissed, as there are many people who <em>do</em> prefer this style.</p>
<p>Fear should never be the driving force in a programming language's design, we should look at facts instead.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h3 id="by-value-or-by-reference-passing"><a href="#by-value-or-by-reference-passing" class="heading-anchor">#</a> By-value or by-reference passing</h3>
<p>I believe the RFC gets it right when it says that outer-scope variables are always captured by-value, and not by-reference. This means that you won't be able to change the value of an outer-scope variable from within your closure — a good thing.</p>
<p>People might argue that this will cause confusion, because what happens if you <em>do</em> want to change the outer-scope variable? We could discuss about whether this would ever be a good idea or not, but it doesn't even matter since PHP already has the answer — remember that symmetry I talked about earlier?</p>
<p>If you want by-reference passing, you'll need to specifically say which variables you want access to — which is exactly what <code>function</code> allows:</p>
<pre>$date = now();

$getSlug = function (Post $post) use (&amp;$date) {
    $date = now()-&gt;addDay();
    
    // Please don't do this…
}
</pre>
<p>I'd argue that this RFC creates clear boundaries between what's possible with <code>function</code> and <code>fn</code>. It doesn't cause confusion; on the contrary: it creates consistency and clarity within PHP's syntax.</p>
<h3 id="there's-little-space-to-be-gained"><a href="#there's-little-space-to-be-gained" class="heading-anchor">#</a> There's little space to be gained</h3>
<p>Some people argue that there's no need for adding multi-line short closures because there's little to be gained when it comes to the amount of characters you're writing. That might be true if you're not relying on outer-scope values, but to be honest it's not about how many characters you write.</p>
<p>This RFC makes the language's syntax more consistent, and a consistent language allows for easier programming.</p>
<p>When writing code, I don't want to be bothered with having to change <code>fn</code> to <code>function</code> when refactoring a closure that suddenly does need to be written on two lines instead of the prior one.</p>
<p>It might seem like such a small detail, but it's those details that impact our day-by-day developer life. And isn't that what a maturing language should be about? Look at features like property promotion, named arguments, enums, attributes, the match operator, etc. You could argue that none of those feature are "necessary" to write working PHP code, but still they do improve my day-by-day life significantly — and I hope yours too.</p>
<h3 id="holding-on-to-the-past"><a href="#holding-on-to-the-past" class="heading-anchor">#</a> Holding on to the past</h3>
<p>Finally, some people might find it difficult to deal with change, and you really need to ask yourself that question if you're voting on RFCs. Yes, you might not see a need for a given feature but you're not only voting for yourself, you have a responsibility to the PHP community; there's more to this than just your projects and your team.</p>
<p>Do you know why closures right now don't auto-import variables from the outer scope? You might have gotten used to it, but do you know why they were designed this way 12 years ago? Larry <a target="_blank" href="https://externals.io/message/113740#113780">did some digging</a> in the mailing list archives, and discovered there were three reasons why <code>use</code> was introduced in the first place:</p>
<ul>
<li>there were performance concerns if variables of the outer-scope were auto-captured — concerns that are no longer relevant today;</li>
<li>it was used to avoid surprise by-reference value passing — which also isn't a problem since we're always using by-value passing; and</li>
<li>it allowed users to explicitly capture variables by-value or by-reference, which is now cleanly solved because of the distinction between <code>function</code> and <code>fn</code>.</li>
</ul>
<p>You might have gotten used to closures not auto-importing variables for the past decade, but keep in mind this behaviour was only added as a necessity back in the day. All arguments for only using explicit capture have been nullified by time, a great sign that PHP is maturing even more.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>With all of that being said, I'm looking forward to Nuno and Larry opening the vote on their RFC. PHP 8.1's feature freeze is planned for the 20th of July, 2021; so there's still some time to finalize the details. If you're voting on RFCs, I truly hope you can see the big picture, as this is one of the RFCs that will have a significant impact on many people's developer life.</p>
 ]]></summary>

                <updated>2021-06-03T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Running PHP code in parallel, the easy way ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/parallel-php"/>

                <id>https://www.stitcher.io/blog/parallel-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Less is more. You've heard that before, right? Keep it in mind, I'm going to show you something.</p>
<p>There are a few good and robust solutions to run PHP code in parallel already; and yet, we've made our own implementation. I want to explain why. First, let's set the scene: I want to run PHP code in parallel. Here are some of my use cases:</p>
<ul>
<li>to test race conditions for our command-bus, when running PHPUnit tests;</li>
<li>to do a bunch of HTTP requests in parallel; and also</li>
<li>to generate this blog faster by allowing my static generator to work on multiple processes.</li>
</ul>
<p>My use cases have two requirements in common: run a arbitrary amount of functions in parallel, and wait until all of them are finished. Let's look at the solutions available today.</p>
<p><strong>AmpPHP</strong> has a package called <a target="_blank" href="https://github.com/amphp/parallel-functions">parallel-functions</a>. It looks like this:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Amp\Promise</span>;
<span class="hl-keyword">use</span> <span class="hl-keyword">function</span> <span class="hl-type">Amp\ParallelFunctions\</span><span class="hl-property">parallelMap</span>;

<span class="hl-variable">$values</span> = Promise\<span class="hl-property">wait</span>(
    <span class="hl-property">parallelMap</span>([1, 2, 3], <span class="hl-keyword">function</span> (<span class="hl-injection">$time</span>) {
        \<span class="hl-property">sleep</span>(<span class="hl-variable">$time</span>);
    
        <span class="hl-keyword">return</span> <span class="hl-variable">$time</span> * <span class="hl-variable">$time</span>;
    })
);
</pre>
<p>For my use cases, I've got a few problems with this implementation:</p>
<ul>
<li>it uses promises, which are very good for more complex async work, but are only overhead for me;</li>
<li>Amp's API and its use of functions feels very clunky to me, but that's rather subjective, I realise that; and finally</li>
<li>if you need a framework in your child processes, you'll need to boot it manually.</li>
</ul>
<p>Moving on to <strong>ReactPHP</strong>, they don't have an out-of-the-box solution like Amp, but they do offer <a target="_blank" href="https://reactphp.org/child-process/">the low-level components</a>:</p>
<pre><span class="hl-variable">$loop</span> = <span class="hl-type">React\EventLoop\Factory</span>::<span class="hl-property">create</span>();

<span class="hl-variable">$process</span> = <span class="hl-keyword">new</span> <span class="hl-type">React\ChildProcess\Process</span>('<span class="hl-value">php child-process.php</span>');

<span class="hl-variable">$process</span>-&gt;<span class="hl-property">start</span>(<span class="hl-variable">$loop</span>);

<span class="hl-variable">$process</span>-&gt;<span class="hl-property">stdout</span>-&gt;<span class="hl-property">on</span>('<span class="hl-value">data</span>', <span class="hl-keyword">function</span> (<span class="hl-injection">$chunk</span>) {
    <span class="hl-keyword">echo</span> <span class="hl-variable">$chunk</span>;
});

<span class="hl-variable">$process</span>-&gt;<span class="hl-property">on</span>('<span class="hl-value">exit</span>', <span class="hl-keyword">function</span>(<span class="hl-injection">$exitCode, $termSignal</span>) {
    <span class="hl-keyword">echo</span> '<span class="hl-value">Process exited with code </span>' . <span class="hl-variable">$exitCode</span> . <span class="hl-property">PHP_EOL</span>;
});

<span class="hl-variable">$loop</span>-&gt;<span class="hl-property">run</span>();
</pre>
<p>A few caveats with this implementation:</p>
<ul>
<li>ReactPHP always requires you to manually create an event loop which, again, is overhead for me;</li>
<li>they also work with promises; and finally</li>
<li>they only offer the bare infrastructure to run processes in parallel, there's lots of manual setup work.</li>
</ul>
<p>Finally, there's <strong>Guzzle</strong> with its <a target="_blank" href="https://docs.guzzlephp.org/en/stable/quickstart.html#concurrent-requests">concurrent requests</a>:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">GuzzleHttp\Client</span>;
<span class="hl-keyword">use</span> <span class="hl-type">GuzzleHttp\Promise</span>;

<span class="hl-variable">$client</span> = <span class="hl-keyword">new</span> <span class="hl-type">Client</span>(['<span class="hl-value">base_uri</span>' =&gt; '<span class="hl-value">http://httpbin.org/</span>']);

<span class="hl-variable">$promises</span> = [
    '<span class="hl-value">image</span>' =&gt; <span class="hl-variable">$client</span>-&gt;<span class="hl-property">getAsync</span>('<span class="hl-value">/image</span>'),
    '<span class="hl-value">png</span>'   =&gt; <span class="hl-variable">$client</span>-&gt;<span class="hl-property">getAsync</span>('<span class="hl-value">/image/png</span>'),
    '<span class="hl-value">jpeg</span>'  =&gt; <span class="hl-variable">$client</span>-&gt;<span class="hl-property">getAsync</span>('<span class="hl-value">/image/jpeg</span>'),
    '<span class="hl-value">webp</span>'  =&gt; <span class="hl-variable">$client</span>-&gt;<span class="hl-property">getAsync</span>('<span class="hl-value">/image/webp</span>')
];

<span class="hl-variable">$responses</span> = <span class="hl-type">Promise\Utils</span>::<span class="hl-property">unwrap</span>(<span class="hl-variable">$promises</span>);
</pre>
<ul>
<li>Again, there's the overhead of promises; but more importantly</li>
<li>Guzzle only works with HTTP requests, which only solves part of my problem.</li>
</ul>
<hr />
<p>Of all of the above, Amp's approach would have my preference, were it not that it still has quite a lot of overhead  for my simple use cases. Honestly, all I wanted to do was to run some functions in parallel and wait until all of them are finished. I don't want to be bothered by looking up documentation about the particular API a framework is using. Did I have to import a function here? How to unwrap promises? How to wait for everything to finish?</p>
<p>All of the above examples are great solutions for the 10% cases that require people to have lots of control, but what about the 90% of cases where you just want to do one thing as simply as possible?</p>
<p>Less is more. We often forget that in software design. We overcomplicate our solution "just in case" someone might need it, and forget about the 90% use case. It leads to frustration because developers have to look up documentation in order to understand how to use a framework, or they have to write lots of boilerplate to get their generic case to work.</p>
<p>So with all of that being said, you now know why I decided to make another library that has one simple goal: run functions in parallel and wait for the result. Here's what it looks like:</p>
<pre><span class="hl-variable">$rssFeeds</span> = <span class="hl-type">Fork</span>::<span class="hl-keyword">new</span>()
    -&gt;<span class="hl-property">run</span>(
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-property">file_get_contents</span>('<span class="hl-value">https://stitcher.io/rss</span>'),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-property">file_get_contents</span>('<span class="hl-value">https://freek.dev/rss</span>'),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-property">file_get_contents</span>('<span class="hl-value">https://spatie.be/rss</span>'),
    );
</pre>
<p>And that's it. It does one job, and does it well. And don't be mistaken: it's not because there's a simple API that it only offers simple functionality! Let me share a few more examples.</p>
<p>Parallel functions are able to return anything, including objects:</p>
<pre><span class="hl-variable">$dates</span> = <span class="hl-type">Fork</span>::<span class="hl-keyword">new</span>()
    -&gt;<span class="hl-property">run</span>(
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>('<span class="hl-value">2021-01-01</span>'),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>('<span class="hl-value">2021-01-02</span>'),
    );
</pre>
<p>They use process forks instead of fresh processes, meaning you don't need to manually boot your framework in every child process:</p>
<pre>[<span class="hl-variable">$users</span>, <span class="hl-variable">$posts</span>, <span class="hl-variable">$news</span>] = <span class="hl-type">Fork</span>::<span class="hl-keyword">new</span>()
    -&gt;<span class="hl-property">run</span>(
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">User</span>::<span class="hl-property">all</span>(),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">Post</span>::<span class="hl-property">all</span>(),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">News</span>::<span class="hl-property">all</span>(),
    );
</pre>
<p>They allow before and after bindings, just in case you need to do a little more setup work. In the previous example, Laravel actually needs to reconnect to the database in the child processes before it would work:</p>
<pre>[<span class="hl-variable">$users</span>, <span class="hl-variable">$posts</span>, <span class="hl-variable">$news</span>] = <span class="hl-type">Fork</span>::<span class="hl-keyword">new</span>()
    -&gt;<span class="hl-property">before</span>(<span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">DB</span>::<span class="hl-property">connection</span>('<span class="hl-value">mysql</span>')-&gt;<span class="hl-property">reconnect</span>())
    -&gt;<span class="hl-property">run</span>(
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">User</span>::<span class="hl-property">all</span>(),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">Post</span>::<span class="hl-property">all</span>(),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">News</span>::<span class="hl-property">all</span>(),
    );
</pre>
<p>And finally, before and after bindings can be run both in the child process and parent process; and also notice how individual function output can be passed as a parameter to these <code>after</code> callbacks:</p>
<pre><span class="hl-type">Fork</span>::<span class="hl-keyword">new</span>()
    -&gt;<span class="hl-property">after</span>(
        <span class="hl-property">child</span>: <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">DB</span>::<span class="hl-property">connection</span>('<span class="hl-value">mysql</span>')-&gt;<span class="hl-property">close</span>(),
        <span class="hl-property">parent</span>: <span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">int</span> $amountOfPages</span>) =&gt; 
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">progressBar</span>-&gt;<span class="hl-property">advance</span>(<span class="hl-variable">$amountOfPages</span>),
    )
    -&gt;<span class="hl-property">run</span>(
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">Pages</span>::<span class="hl-property">generate</span>('<span class="hl-value">1-20</span>'),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">Pages</span>::<span class="hl-property">generate</span>('<span class="hl-value">21-40</span>'),
        <span class="hl-keyword">fn</span> () =&gt; <span class="hl-type">Pages</span>::<span class="hl-property">generate</span>('<span class="hl-value">41-60</span>'),
    );
</pre>
<p>There are of course a few things this package doesn't do:</p>
<ul>
<li>there's no pool managing the amount of concurrent processes, you're in charge if you need to;</li>
<li>there are no promises;</li>
<li>
<a target="_blank" href="https://www.php.net/manual/en/book.pcntl.php">pcntl</a> doesn't work on Windows and doesn't run in web requests;</li>
<li>there's no behind the scenes exception handling, if a child fails it'll throw an exception and stop the process flow.</li>
</ul>
<p>In other words: it's the perfect solution for the 90% case where you just want to run some functions in parallel and be done with it. If you need anything more than that, then the solutions listed above are a great start. There's also another package of ours called <a target="_blank" href="https://github.com/spatie/async"><code>spatie/async</code></a> that doesn't work with promises but does offer pool configuration and extensive exception handling.</p>
<p>If you want to know more or want to try the package yourself, you can check it out on GitHub: <a target="_blank" href="https://github.com/spatie/fork"><code>spatie/fork</code></a>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>Less is more. That's one of my core principles when coding. I prefer code that forces me to do something one way but always works, instead of a highly configurable framework that makes me wonder how to use it every time I look at it. I feel that many developers often get lost in a maze of high configurability and extensibility and forget their original end goal by doing so.</p>
<p>I hope this package can be of help for that group of people who fall in the 90% category.</p>
 ]]></summary>

                <updated>2021-04-28T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP in 2021 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-in-2021"/>

                <id>https://www.stitcher.io/blog/php-in-2021</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Once a year, I look back at the recent developments in the PHP world, and also look forward to what's to come. And just like in <a href="/blog/php-in-2020">2020</a> and <a href="/blog/php-in-2019">2019</a>, we're at it again!</p>
<iframe width="560" height="400" src="https://www.youtube.com/embed/W3p8BGeiTwQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>Like I said time and time again: PHP isn't the same language it was ten years ago, and we're very thankful for that. It's a fast and reliable language, used to build large applications at scale. So let's discuss some of the most notable changes of PHP in the last year, to the language <em>and</em> the community.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="php-8-and-beyond"><a href="#php-8-and-beyond" class="heading-anchor">#</a> PHP 8 and beyond</h2>
<p>The new major version, <a href="/blog/new-in-php-8">PHP 8</a>, arrived late last year. I've written an extensive amount on the topic, and I won't copy/paste all of that here. As always, performance is only improving, as shown by the <a target="_blank" href="https://kinsta.com/blog/php-benchmarks/">benchmarks</a> done by Kinsta.</p>
<p>There's also <a href="/blog/jit-in-real-life-web-applications">the JIT</a> that does seem to improve performance of some projects here and there, as well as <a href="/blog/php-preload-benchmarks">preloading</a> that has an overall positive impact if you're not using shared hosting.</p>
<p>I think that features like <a href="/blog/attributes-in-php-8">attributes</a> (a.k.a. "annotations"), <a href="/blog/php-8-named-arguments">named arguments</a> and <a href="/blog/constructor-promotion-in-php-8">promoted properties</a> also deserve a mention, as they have definitely contributed towards PHP 8 being such a great release.</p>
<p>Meanwhile, the core team is already working on the next version, <a href="/blog/new-in-php-81">PHP 8.1</a>, which will be released somewhere by the end of 2021. For now, the most significant features are enums and fibers, I'll mention both of them again later in this post.</p>
<p>Year after year, the core team succeeds in bringing a new stable release to the community, packed with a bunch of features and quality-of-life improvements. The upgrade path also isn't all that difficult anymore. I upgraded some of my own projects from PHP 7.4 to PHP 8, and it took only an hour or so per project. There really isn't any good reason to stay behind!</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="php's-type-system"><a href="#php's-type-system" class="heading-anchor">#</a> PHP's type system</h2>
<p>There's actually some very exciting news when it comes to types: <a href="/blog/php-enums">enums</a> will be added in <a href="/blog/new-in-php-81">PHP 8.1</a>. On top of that we've also seen some of the maintainers of static analysis tools contributing to PHP's source code by landing their first RFC. This one adds the <a href="/blog/new-in-php-81#new-never-type-rfc"><code>never</code></a> type, a useful addition for static analysis.</p>
<p>Speaking of static analysis tools, PhpStorm has <a target="_blank" href="https://blog.jetbrains.com/phpstorm/2020/07/phpstan-and-psalm-support-coming-to-phpstorm/">added</a> built-in support for <a target="_blank" href="https://psalm.dev/">Psalm</a> and <a target="_blank" href="https://github.com/phpstan/phpstan">PhpStan</a>, which is a great step towards broader adaptation; our favourite IDE now also supports <a href="https://blog.jetbrains.com/phpstorm/2021/07/phpstorm-2021-2-beta/">generics as docblocks</a>, which makes them a lot more useful.</p>
<p>Still no support for first-class generics, unfortunately. There are some major road blockers, especially since we're still dealing with a dynamically typed language. Nikita has outlined the problems <a target="_blank" href="https://github.com/PHPGenerics/php-generics-rfc/issues/45">here</a>. Personally, my approach would be the easy way out: only support <a href="/blog/we-dont-need-runtime-type-checks">runtime-erased generics</a> and rely on static analysis. This requires more than a technical solution though, it also requires a mind shift in the PHP community as a whole. Maybe one day it becomes a viable option, but not as of yet.</p>
<h2 id="async-php"><a href="#async-php" class="heading-anchor">#</a> Async PHP</h2>
<p>There was some big news recently: PHP is getting coroutines — aka. green threads — in PHP 8.1! Although, fibers — that's what they are called — might <a href="/blog/fibers-with-a-grain-of-salt">not be as big a game-changer as you might think</a>.</p>
<p>Even though fibers themselves might only be a small cog in what is the large async machine, the RFC has spiked interest in the async community again, which we can only be happy about. Async frameworks like <a target="_blank" href="https://amphp.org/">Amphp</a> and <a target="_blank" href="https://reactphp.org/">ReactPHP</a> are growing in popularity, and recently Laravel <a target="_blank" href="https://laravel-news.com/laravel-octane">announced</a> built-in support for <a target="_blank" href="https://www.swoole.co.uk/">Swoole</a>.</p>
<h2 id="the-community"><a href="#the-community" class="heading-anchor">#</a> The community</h2>
<p>I can't go on without mentioning Composer, the de-facto standard package manager. It has had a new major release in October, 2020: <a target="_blank" href="https://blog.packagist.com/composer-2-0-is-now-available/">Composer 2.0</a>. This version comes with several UX improvements, but most importantly sees extreme performance improvements, sometimes even tripling its speed on clean installs.</p>
<p>Speaking of composer, I like to measure the current state of PHP's ecosystem by looking at the available packages over time. Last year I spoke about ±25 million downloads a day, today that number has more than doubled and we're looking at ±60 million daily downloads.</p>
<p>Finally, take a look at this graph, listing the amount of packages and versions over time. It can also be found on <a target="_blank" href="https://packagist.org/statistics">their website</a>. You can clearly see a healthy ecosystem growing, and there's no end in sight.</p>
<p><img src="/resources/img/blog/php-in-2021/01.png" srcset="/resources/img/blog/php-in-2021/01-1863x782.png 1863w, /resources/img/blog/php-in-2021/01-2151x902.png 2151w, /resources/img/blog/php-in-2021/01-1521x638.png 1521w, /resources/img/blog/php-in-2021/01-1075x451.png 1075w, /resources/img/blog/php-in-2021/01-2406x1010.png 2406w" sizes="" alt=""></img></p>
<h2 id="the-language"><a href="#the-language" class="heading-anchor">#</a> The language</h2>
<p>Let's end with a reminder of everything that's been added to PHP these recent years. If you haven't kept up with its development, you really want to check this list out. I think it shows the growth of the community and core development team within recent years, and I'm confident there's more to come.</p>
<ul>
<li>
<a href="/blog/php-enums">Enums</a>
</li>
<li>
<a href="/blog/fibers-with-a-grain-of-salt">Fibers</a>
</li>
<li>
<a href="/blog/attributes-in-php-8">Attributes</a>
</li>
<li>
<a href="/blog/php-8-named-arguments">Named Arguments</a>
</li>
<li>
<a href="/blog/php-8-match-or-switch">Match</a>
</li>
<li>
<a href="/blog/constructor-promotion-in-php-8">Constructor Property Promotion</a>
</li>
<li>
<a href="/blog/short-closures-in-php">Short closures</a>
</li>
<li>
<a href="/blog/shorthand-comparisons-in-php#null-coalescing-operator">Null coalescing operator</a>
</li>
<li>
<a target="_blank" href="https://www.php.net/manual/en/language.oop5.traits.php">Traits</a>
</li>
<li>
<a href="/blog/typed-properties-in-php-74">Typed properties</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/argument_unpacking">Spread operator</a>
</li>
<li>
<a href="/blog/php-jit">The JIT</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/ffi">FFI</a>
</li>
<li>
<a target="_blank" href="https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration">Return type declarations</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/generators">Generators</a>
</li>
<li>
<a href="/blog/new-in-php-8">Lots more</a>
</li>
</ul>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>All of that to say: PHP is alive and doing very well. Every year I feel happier with the direction the language is going, and am looking forward to using it for many years to come!</p>
<p>If you're excited as well, you probably want to subscribe to <a target="_blank" href="/newsletter/subscribe">my newsletter</a> to stay up-to-date about PHP's development, as well as <a target="_blank" href="https://twitter.com/brendt_gd">follow me on Twitter</a>. Let me know your thoughts via Twitter or email, and share this post with your audience if you found it useful, thanks!</p>
 ]]></summary>

                <updated>2021-04-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Fibers with a grain of salt ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/fibers-with-a-grain-of-salt"/>

                <id>https://www.stitcher.io/blog/fibers-with-a-grain-of-salt</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="sidenote">
<h2>Do you prefer to listen?</h2>
<p>I've created an audio version of this post. You can listen <a target="_blank" href="https://www.youtube.com/watch?v=UJM_27mapTc&amp;ab_channel=BrentRoose">on YouTube</a> or by subscribing to my podcast feed on <a target="_blank" href="https://podcasts.apple.com/be/podcast/rant-with-brent/id1462956030">Apple Podcasts</a>, <a target="_blank" href="https://www.stitcher.com/s?fid=403581&amp;refid=stpr.">Stitcher</a> or <a target="_blank" href="https://open.spotify.com/show/43sF0kY3BWepaO9CkLvVdJ?si=R-MIXaMHQbegQyq3gQm7Yw">Spotify</a></p>
</div>
<p>So I was going to write an in-depth blogpost about using fibers in <a href="/blog/new-in-php-81">PHP 8.1</a>. We were going to start with a basic example to explain them from the ground up. The idea was to send async HTTP requests and process them in parallel using fibers.</p>
<p>But playing around with them, I learned that the <a target="_blank" href="https://wiki.php.net/rfc/fibers">RFC</a> wasn't kidding when it said "The Fiber API is not expected to be used directly in application-level code. Fibers provide a basic, low-level flow-control API to create higher-level abstractions that are then used in application code".</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>So instead of going down this path and make things way too complicated, we'll discuss what fibers are conceptually, why they are barely usable in application code, and how you can make use of async PHP after all.</p>
<p>First, a little bit of theory.</p>
<hr />
<p>Imagine you want to send three HTTP requests and process their combined result. The synchronous way of doing so is by sending the first one, waiting for the response, then sending the second one, waiting, etc.</p>
<p>Let's represent such a program flow with as easy a chart as possible. You need to read this chart from the top down, and time progresses the further down you go. Each colour represents one HTTP request. The coloured pieces of each request represent PHP code actually running, where the CPU on your server is doing work, the transparent blocks represent waiting times: the request needs to be sent over the wire, the other server needs to process it and send it back. It's only when the response arrives that we can work again.</p>
<p><img src="/resources/img/blog/fiber/sync.png" srcset="/resources/img/blog/fiber/sync-1001x1787.png 1001w, /resources/img/blog/fiber/sync-867x1548.png 867w, /resources/img/blog/fiber/sync-1120x2000.png 1120w, /resources/img/blog/fiber/sync-708x1264.png 708w, /resources/img/blog/fiber/sync-500x892.png 500w" sizes="" alt=""></img></p>
<p>This is a synchronous execution flow: send, wait, process, repeat.</p>
<p>In the world of parallel processing, we send the request but <em>don't</em> wait. Then we send the next request, followed by another. Only <em>then</em> do we wait for all requests. And while waiting we periodically check whether one of our requests is already finished. If that's the case we can process it immediately.</p>
<p><img src="/resources/img/blog/fiber/async.png" srcset="/resources/img/blog/fiber/async-1120x1280.png 1120w, /resources/img/blog/fiber/async-867x990.png 867w, /resources/img/blog/fiber/async-500x571.png 500w, /resources/img/blog/fiber/async-1001x1144.png 1001w, /resources/img/blog/fiber/async-708x809.png 708w" sizes="" alt=""></img></p>
<p>You can see how such an approach reduces execution time because we're using the waiting time more optimally.</p>
<p>Fibers are a new mechanism in PHP 8.1 that allow you to manage those parallel execution paths more efficiently. It was already possible by using generators and <code>yield</code>, but fibers are a significant improvement, since they are specifically designed for this use case.</p>
<p>You would create one fiber for each request, and pause the fiber after the request is sent. After you've created all three fibers, you'd loop over them, and resume them one by one. By doing so, the fiber checks whether the request is already finished, if not it pauses again, otherwise it can process the response and eventually finish.</p>
<p>You see, fibers are a mechanism to start, pause and resume the execution flow of an isolated part of your program. Fibers are also called "green threads": threads that actually live in the same process. Those threads aren't managed by the operating system, but rather the runtime — the PHP runtime in our case. They are a cost efficient way of managing <em>some</em> forms of parallel programming.</p>
<p>But note how they don't add anything truly asynchronous: all fibers live in the same PHP process, and only one can run at a time. It's the main process that loops over them and checks them while waiting, and that loop is often called the "event loop".</p>
<p>The difficult part about parallelism isn't about how you loop over fibers or generators or whatever mechanism you want to use; it's about being able to start an operation, hand it over to an external service and only check the result when you want to, in a non-blocking way.</p>
<p>See, in the previous examples, we assumed that we could just send off a request and check its response later when we want to, but that actually isn't as easy as it sounds.</p>
<p>That's right: most of PHP's functions that deal with I/O don't have this non-blocking functionality built-in. In fact, there's only a handful of functions that do, and using them is quite cumbersome.</p>
<p>There's the example of sockets, which can be set to be non-blocking, like so:</p>
<pre>[<span class="hl-variable">$read</span>, <span class="hl-variable">$write</span>] = <span class="hl-property">stream_socket_pair</span>(
    <span class="hl-type">STREAM_PF_UNIX</span>,
    <span class="hl-type">STREAM_SOCK_STREAM</span>,
    <span class="hl-type">STREAM_IPPROTO_IP</span>
);
 
<span class="hl-property">stream_set_blocking</span>(<span class="hl-variable">$read</span>, <span class="hl-keyword">false</span>);
<span class="hl-property">stream_set_blocking</span>(<span class="hl-variable">$write</span>, <span class="hl-keyword">false</span>);
</pre>
<p>By using <code>stream_socket_pair()</code>, two sockets are created that can be used for bidirectional communication. And as you can see, they can be set to be non-blocking using <code>stream_set_blocking()</code>.</p>
<p>Say we'd want to implement our example, sending three requests. We could use sockets to do so, but we'd need to implement the HTTP protocol ourselves on top of it. That's exactly what <a href="https://github.com/nox7/async-php-8-io-http">nox7</a> did, a user who shared a small proof of concept on <a target="_blank" href="https://www.reddit.com/r/PHP/comments/mk15gd/php_fibers_a_pure_php_example_with_http_get/">Reddit</a> to show how to send HTTP GET requests using fibers and sockets. Do you really want to be concerned with doing so in your application code?</p>
<p>The answer, for me at least, is "no". Which is exactly what the RFC warned about; I'm not mad about that. Instead, we're encouraged to use one of the existing async frameworks: <a target="_blank" href="https://amphp.org/">Amp</a> or <a target="_blank" href="https://reactphp.org/">ReactPHP</a>.</p>
<p>With ReactPHP, for example, we could write something like this:</p>
<pre><span class="hl-variable">$loop</span> = <span class="hl-type">React\EventLoop\Factory</span>::<span class="hl-property">create</span>();

<span class="hl-variable">$browser</span> = <span class="hl-keyword">new</span> <span class="hl-type">Clue\React\Buzz\Browser</span>(<span class="hl-variable">$loop</span>);

<span class="hl-variable">$promises</span> = [
    <span class="hl-variable">$browser</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">https://example.com/1</span>'),
    <span class="hl-variable">$browser</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">https://example.com/2</span>'),
    <span class="hl-variable">$browser</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">https://example.com/3</span>'),
];

<span class="hl-variable">$responses</span> = Block\<span class="hl-property">awaitAll</span>(<span class="hl-variable">$promises</span>, <span class="hl-variable">$loop</span>);
</pre>
<p>That's a better example compared to manually creating socket connections. And that's what the RFC means: application developers shouldn't need to worry about fibers, it's an implementation detail for frameworks like Amp or ReactPHP.</p>
<p>That brings us to the question though: what are the benefits of fibers compared to what we already could do with generators? Well the RFC explains it this way:</p>
<blockquote>
<p>Unlike stack-less Generators, each Fiber has its own call stack, allowing them to be paused within deeply nested function calls. A function declaring an interruption point (i.e., calling Fiber::suspend()) need not change its return type, unlike a function using yield which must return a Generator instance.</p>
<p>Fibers can be suspended in any function call, including those called from within the PHP VM, such as functions provided to array_map or methods called by foreach on an Iterator object.</p>
</blockquote>
<p>It's clear that fibers are a significant improvement, both syntax-wise and in flexibility. But they are nothing yet compared to, for example, Go, with its "<a target="_blank" href="https://golangbot.com/goroutines/">goroutines</a>".</p>
<p>There's still lots of functionality missing for async PHP to become mainstream without the overhead of frameworks, and fibers are a good step in the right direction, but we're not there yet.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>So there's that. There actually isn't much to say about fibers if you're not a maintainer of either Amp, ReactPHP or a smaller async PHP framework. Maybe even more frameworks or libraries will start incorporating them?</p>
<p>Meanwhile, there's also <a target="_blank" href="https://www.swoole.co.uk/">Swoole</a> — a PHP extension that actually modifies several core functions to be non-blocking. Swoole itself is a Chinese project and often not very well documented when it comes to English, but recently Laravel <a target="_blank" href="https://laravel-news.com/laravel-octane">announced</a> first party-integration with it. Maybe this is the better strategy when it comes to moving PHP towards a more async model: optionally integrate Swoole or other extensions with frameworks like Laravel and Symfony?</p>
<p>It'll be interesting to see what the future will bring!</p>
 ]]></summary>

                <updated>2021-04-12T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Starting with event sourcing ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/what-event-sourcing-is-not-about"/>

                <id>https://www.stitcher.io/blog/what-event-sourcing-is-not-about</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>For many developers, event sourcing is a magical beast that's used to build extremely complex, often distributed projects. And there's good reason for that: event sourcing is a pattern that forces code to be built in a way that fits those complex projects exceptionally well.</p>
<p>Words like "modularized", "distributed", "scalable" and "versatile" come to mind to describe it; characteristics you can't do without if you're building applications at scale. Think about a popular webshop or a bank, handling maybe thousands if not millions of transactions per second. Those are the kinds of projects event sourcing most often is associated with.</p>
<p>And thus, event sourcing is rarely every used in smaller projects, the ones many developers deal with, the ones many of my regular blog readers work on.</p>
<p>I think the reason for this, is because of a fundamental mistake of what we think event sourcing is.</p>
<p>When I discuss event sourcing, people often assume that it comes with significant overhead, and that that overhead isn't justified in smaller projects. What they say is that there's some kind of pivot point, determined by the scope of the project, where event sourcing actually reduces costs, while in smaller projects it would introduce a cost overhead.</p>
<p>Something like this:</p>
<p><img src="/resources/img/blog/event-sourcing-basics/01.png" srcset="/resources/img/blog/event-sourcing-basics/01-1508x968.png 1508w, /resources/img/blog/event-sourcing-basics/01-1305x838.png 1305w, /resources/img/blog/event-sourcing-basics/01-1066x684.png 1066w, /resources/img/blog/event-sourcing-basics/01-754x484.png 754w, /resources/img/blog/event-sourcing-basics/01-1686x1083.png 1686w" sizes="" alt=""></img></p>
<p>And, of course, this is an oversimplification, but it visualizes the argument very well: we should only use event sourcing in projects where we're sure it'll be worth it.</p>
<p>The problem with this statement is that it doesn't talk about <em>just</em> event sourcing, it talks about event sourcing <em>with</em> all its associated patterns as well: aggregates, sagas, snapshots, serialization, versioning, commands, …</p>
<p>Which is why I'd say our graph should look something more like this:</p>
<p><img src="/resources/img/blog/event-sourcing-basics/02.png" srcset="/resources/img/blog/event-sourcing-basics/02-1066x684.png 1066w, /resources/img/blog/event-sourcing-basics/02-1686x1083.png 1686w, /resources/img/blog/event-sourcing-basics/02-754x484.png 754w, /resources/img/blog/event-sourcing-basics/02-1305x838.png 1305w, /resources/img/blog/event-sourcing-basics/02-1508x968.png 1508w" sizes="" alt=""></img></p>
<p>But does it even make sense to use event sourcing without the patterns that build on top it? There's a good reason why those patterns exist. That are the questions I want to answer today.</p>
<hr />
<p>Here's <a target="_blank" href="https://www.martinfowler.com/eaaDev/EventSourcing.html">Martin Fowler's</a> vision on what event sourcing is:</p>
<p><em>"We can query an application's state to find out the current state of the world, and this answers many questions. However there are times when we don't just want to see where we are, we also want to know how we got there.</em></p>
<p><em>Event Sourcing ensures that all changes to application state are stored as a sequence of events. Not just can we query these events, we can also use the event log to reconstruct past states, and as a foundation to automatically adjust the state to cope with retroactive changes.</em></p>
<p><em>The fundamental idea of Event Sourcing is that of ensuring every change to the state of an application is captured in an event object, and that these event objects are themselves stored in the sequence they were applied for the same lifetime as the application state itself.</em>"</p>
<p>In other words: event sourcing is about storing changes, instead of their result. It's those changes that make up the final state of a project.</p>
<p>With event sourcing, the question of "is a cart checked out" should be answered by looking at the events that happened related to that cart, and not by looking at a cart's status.</p>
<p>That sounds like overhead indeed, so what are the benefits of such an approach? Fowler lists three:</p>
<ul>
<li>
<strong>Complete Rebuild</strong>: the application's state can be thrown away and rebuilt only by looking at events. This gives lots of flexibility when you know changes to the program flow or data structure will happen in the future — I'll give an example of this later in this post, don't worry if it sounds a little abstract for now.</li>
<li>
<strong>Temporal Query</strong>: you can actually query events themselves to see what happened in the past. There's not just the end result of what happened, there's also the log of events themselves.</li>
<li>
<strong>Event Replay</strong>: if you want to, you can make changes to the event log to correct mistakes, and replay events from that point on to rebuild a correct application state.</li>
</ul>
<p>There's one important thing missing in Fowler's list though: events model time extremely well. In fact, they are much closer to how we humans perceive the world than CRUD is.</p>
<p>Think of some kind of process of your daily life. It could be your morning routine, it could be you doing groceries, maybe you attended a class or had a meeting at work; anything goes, as long as there were several steps involved.</p>
<p>Now try to explain that process in as much detail as possible. I'll take the morning routine as an example:</p>
<ul>
<li>I got up at 5 AM</li>
<li>Brushed my teeth — dental hygiene is important — and got dressed</li>
<li>Went downstairs to make a coffee</li>
<li>Went to my home office (with my coffee)</li>
<li>Read up on mails</li>
<li>Started writing this post</li>
</ul>
<p>Thinking with events comes natural to us, much more natural than having a table containing the state of what's happening right now, as with a CRUD approach.</p>
<p>If there's already a "flow of time" to be discovered in something as mundane as my morning routine, what about any kind of process for our client projects? Making bookings, sending invoices, managing inventories, you name it; "time" is very often a crucial aspect, and CRUD isn't all that good in managing it since it only shows the current state.</p>
<hr />
<p>I'm going to give you an example of how extremely simple event sourcing can be, without the need for any kind of framework or infrastructure, and where there's no overhead compared to CRUD, in fact, there's less.</p>
<p>I have a blog, this one; and I use Google Analytics to anonymously track visitors, page views, etc. Of course I know Google isn't the most privacy-focussed so I was tinkering with alternatives. One day I wondered if, instead of relying on client side tracking, I could just rely on my server logs to determine how many pages and which were visited.</p>
<p>So, I wrote a little script that monitors my nginx access log; it filters out traffic like bots, crawlers etc, and stores each visit as a line in a database table. Such a visit has some data associated with it: the URL, the timestamp, the user agent, etc.</p>
<p>And that's it.</p>
<p>Oh were you expecting more? Well, I did end up writing a little more code to make my life easier, but in essence, what we have here already is event sourcing: I keep a chronological log of everything that happened in my application and I can use SQL queries to aggregate the data, for example, to show visits per day.</p>
<p>Now, of course, with millions of visits over time, running raw SQL queries can become tedious, so I added one pattern that builds on event sourcing: projections; also known as the "read model" in CQRS.</p>
<p>Every time I store a visit in the table, I also dispatch it as an event. There are several subscribers that handle them, for example there's a subscriber that groups visits per day, it keeps track of them in a table with two columns: <code>day</code> and <code>count</code>. It's literally only a few lines of code:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">VisitsPerDay</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection"><span class="hl-type">PageVisited</span> $event</span>): <span class="hl-type">void</span>
    {
        <span class="hl-type">DB</span>::<span class="hl-property">insert</span>(
            '<span class="hl-property">INSERT</span> <span class="hl-property">INTO</span> visits_per_day (`day`, `count`) 
            <span class="hl-type">VALUES</span> (?, ?) 
            <span class="hl-type">ON</span> <span class="hl-property">DUPLICATE</span> <span class="hl-property">KEY</span> <span class="hl-property">UPDATE</span> `count` = `count` + 1',
            [
                <span class="hl-variable">$event</span>-&gt;<span class="hl-property">date</span>-&gt;<span class="hl-property">format</span>('<span class="hl-value">Y-m-d</span>'), 
                1,
            ]
        );
    }
}
</pre>
<p>Do you want visits per month? Per URL? I'll just make new subscribers. Here's the kicker though: I can add them after my application is deployed, and replay all previously stored events on them. So even when I make a change to my projectors or add new ones, I can always replay them from the point I started storing events, and not just from when I deployed a new feature.</p>
<p>This was especially useful in the beginning: there was lots of data coming in that were bots or traffic that weren't real users. I let the script run for a few days, observed the results, added some extra filtering, threw away all projection data and simply replayed all visits again. This way I wouldn't need to start all over again every time I made a change to the data.</p>
<p>And can make a guess how long it took to set up this event sourced project? 2 hours, from start to a working production version. Of course I used a framework for a DBAL and an event bus, but nothing specifically event sourcing related. Over the next days I did some fine tuning, added some charts based on my projection tables etc; but the event sourcing setup was absolutely easy to build.</p>
<p>And so, here's the point I'm trying to make: the event sourcing mindset is extremely powerful in many kinds of projects. Not just the ones that require a team of 20 developers to work on for five years. There are many problems where "time" plays a significant role, and most of those problems can be solved using a very simple form of event sourcing, without any overhead at all.</p>
<p>In fact, a CRUD approach would have cost me way more time to build this analytics project. Every time I made a change I would have to wait a few days to ensure this change was effective with real life visits. Event sourcing allowed me, a single developer, to actually be much more productive; which is the opposite of what many people believe event sourcing can achieve.</p>
<hr />
<p>Now, don't get me wrong. I'm not saying event sourcing will simplify complex domain problems. Complex projects will take lots of time and resources, with or without event sourcing. Event sourcing simplifies some problems within those projects, and makes others a little harder.</p>
<p>But remember I'm not trying to make any conclusions about the absolute cost of using event sourcing or not. I only want people to realise that event sourcing in itself doesn't have to be extremely complex, and might indeed be a better solution for some projects, even when they are relatively small ones.</p>
<p>Greg Young, the one who came up with the term "event sourcing" more than 10 years ago; <a target="_blank" href="https://www.youtube.com/watch?v=LDW0QWie21s&amp;t=1925s">said that</a> if your starting point for event sourcing is a framework, you're doing it wrong. It's a state of mind first, without needing any infrastructure. I actually hope that more developers can see it this way, that they remove the mental layer of complexity at first, and only add it back when actually needed. You can start with event sourcing today, without any special framework, and it might actually improve your workflow.</p>
<hr />
<p>If you've made it this far, I assume you're intrigued by what I wrote — or very angry because of it, that's fine too. If you want to stay up-to-date about my content, consider subscribing to <a target="_blank" href="/newsletter/subscribe">my newsletter</a>, I occasionally send a mail about stuff I'm working on.</p>
<p>Finally, if you're interested in more, you can check out the footnotes!</p>
 ]]></summary>

                <updated>2021-04-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Thoughts on Event Sourcing ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/thoughts-on-event-sourcing"/>

                <id>https://www.stitcher.io/blog/thoughts-on-event-sourcing</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I was flattered being asked to write a guest post for Event Store — the company originally founded by Greg Young, who pioneered event sourcing more than ten years ago.</p>
<p>I wrote about my experience with Event Sourcing, and how it's a shift in "mental framework" for all of us who were taught proper MVC and CRUD to build web applications with.</p>
<p>I hope you like it: <a target="_blank" href="https://www.eventstore.com/blog/php-and-event-sourcing">https://www.eventstore.com/blog/php-and-event-sourcing</a>.</p>
<p>If you want to listen to the audio version, you can head over here: <a target="_blank" href="https://www.youtube.com/watch?v=LXDnjtgfl2k">https://www.youtube.com/watch?v=LXDnjtgfl2k</a>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-04-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Honesty ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/honesty"/>

                <id>https://www.stitcher.io/blog/honesty</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="sidenote">
<h2>You can listen to this post</h2>
<p>If you prefer listening over reading, you can listen to this post <a target="_blank" href="https://www.youtube.com/watch?v=bNvQezGO02M&amp;ab_channel=BrentRoose">on YouTube</a> or by subscribing to my podcast feed on <a target="_blank" href="https://podcasts.apple.com/be/podcast/rant-with-brent/id1462956030">Apple Podcasts</a>, <a target="_blank" href="https://www.stitcher.com/s?fid=403581&amp;refid=stpr.">Stitcher</a> or <a target="_blank" href="https://open.spotify.com/show/43sF0kY3BWepaO9CkLvVdJ?si=R-MIXaMHQbegQyq3gQm7Yw">Spotify</a></p>
</div>
<p>Do you sometimes lie?</p>
<p>Perhaps that's a too confrontational question. Do you sometimes bend the truth a little for the benefit of others or yourself? Do you still consider it a lie if all parties involved benefit from it?</p>
<p><a target="_blank" href="https://www.ted.com/talks/pamela_meyer_how_to_spot_a_liar?referrer=playlist-5_talks_on_the_truth_about_lyi#t-406482">Studies show</a> that all humans lie to a certain extent. It's a natural part of how we interact with each other. Still there's a category of lies that's not accepted by society: lies that intentionally deceive others for your own benefit, sometimes even causing harm.</p>
<p>This is a story about those kinds of lies. Not the ones you and I tell, but the ones people close to us might. The ones that, when witnessing them makes you feel uncomfortable, makes you want to step in and tell the truth. But you don't, because if you do, it might cause you harm instead.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>I was a junior developer, straight out of school. I was working at a company that made websites for small to medium sized businesses. Think your average marketing site with some added complexity like CRM or lead management, stuff like that.</p>
<p>I'd been working with a team of developers on one of the larger projects for half a year, maybe eight months. The project was already in production by this time, but there still was lots of new functionality to build.</p>
<p>One day, the client makes a somewhat angry call to my project manager — the one who's directly above me, who I work with every day. They tell her there's a bug in a recently deployed feature and they ask her to get it fixed immediately. My project manager tells them she'll review the matter internally and get back to them within the hour.</p>
<p>Fast forward an hour; I can see her nervously picking up the phone. By the way, we're in an open office, so everyone's able to hear whatever others say.</p>
<p>She tells our client that the colleague who built that feature is sick for the rest of the week but we'll put another developer on the issue. It might take a bit longer and probably won't get done until tomorrow, maybe even the day after that.</p>
<p>I gave a puzzled look to the guy sitting next to me, that's the colleague our PM is talking about and he's just fine, not sick at all.</p>
<hr />
<p>Let me paint you the broader picture for a moment. The relation with this client, remember: our largest up until then; it had been a little… tense. Ever since the application was deployed to production — or maybe ever since it became clear that the project estimates weren't as accurate as the client had hoped; they were noticeably frustrated.</p>
<p>We did those estimates together as a team, with our PM and boss. The boss was the one who actually made the sales pitch and had contact with the client before the project started.</p>
<p>We roughly estimated — if memory serves me right — that we'd need a year to deliver the project.
Of course, it's a rough estimate on this timescale, no one is able to accurately estimate a project this size. So naturally we told our boss that we'd need to consider enough margins.</p>
<p>That answer wasn't satisfying though. Our boss knew the expectations of the client, they were half of what we proposed. They would surely go with another party if we kept to this estimate. So our boss promised what we, developers and project manager said was impossible: he cut the estimate in half, and gave it to the client. Same features, just half the available time.</p>
<p>We knew from day one this wasn't anywhere near achievable. But "we'll see", our boss said when we voiced our concerns. "Right now it's most important to win this pitch, we'll worry about the practical details later."</p>
<p>Naturally, our client wasn't happy when we told them it would take a little longer than "anticipated" to get an initial version running on production. I'd say we did a pretty good job after all: only 2 months over time instead of the 6 we expected.</p>
<p>But you can imagine the toll these things take on the team. There was a constant atmosphere of stress, and we — as a company — were piling lie upon lie upon lie.</p>
<hr />
<p>I talked with our PM in private after that phone call, actually I stumbled upon her crying in the hallway. After the client initially called, she went to discuss the situation with our boss.</p>
<p>The colleague in question was currently working on another project (which was also under-estimated by the way) and it would have a significant impact if he'd need to spend an extra day back on the other project again. The boss told our PM to simply say the colleague is out sick, and that it would take more time than strictly required to fix the issue because of this. In his mind it was a win: the colleague can continue working on the other project, we get a few more days to fix the issue and we could invoice more work than actually needed — making up for the losses we made because of our wrong estimation in the beginning.</p>
<p>This situation, together with <a href="/blog/dont-get-stuck">other reasons</a>, is why I quit that job shortly after. The PM handed in her resignation as well, a month after I left.</p>
<p>These days, I'm fortunate to have found a workplace that does value honesty between them and their clients. I now realise this is <em>not</em> the case for every company. In the end, that company I used to work for did take a turn for the better; I believe they realised there's little to no value in relationships based on lies. Even though a lie might serve you right now, it's never a long lasting solution.</p>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2021-03-31T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Don&#039;t write your own framework ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/dont-write-your-own-framework"/>

                <id>https://www.stitcher.io/blog/dont-write-your-own-framework</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="sidenote">
<h2>You can listen to this post</h2>
<p>If you prefer listening over reading, you can listen to this post <a target="_blank" href="https://www.youtube.com/watch?v=oy0b2U9fyRo&amp;ab_channel=BrentRoose">on YouTube</a> or by subscribing to my podcast feed on <a target="_blank" href="https://podcasts.apple.com/be/podcast/rant-with-brent/id1462956030">Apple Podcasts</a>, <a target="_blank" href="https://www.stitcher.com/s?fid=403581&amp;refid=stpr.">Stitcher</a> or <a target="_blank" href="https://open.spotify.com/show/43sF0kY3BWepaO9CkLvVdJ?si=R-MIXaMHQbegQyq3gQm7Yw">Spotify</a></p>
</div>
<p>We were sitting with 5 or 6 backend developers around the large meeting table. It was 10 in the morning on a Monday, and we were all silently working on our laptops. There was a hasty atmosphere, and everyone tried to concentrate on the task ahead.</p>
<p>Less than 2 hours before, I walked into the office, not yet aware of any harm. I was immediately called to the meeting room at the back, there was no time to sit at my desk. Still I quickly grabbed a coffee, and went to the back where a few other colleagues already gathered.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>With them was our boss, a nice guy; there wasn't any "upper management" culture or anything, we were just colleagues. The other people in the room already knew what was going on, so he explained to me personally.</p>
<p>There was a bug, in our in-house framework.</p>
<p>"It sure isn't the first one" — I remember thinking.</p>
<p>At this point we'd used this custom-built framework for several years; 200 websites were affected, more or less.</p>
<p>The bug was a stupid mistake — after all, which bug isn't?</p>
<p>Our framework router would take a URL and filter out repeated slashes, so <code>//admin</code> would become <code>/admin</code>. This is, I believe, part of some HTTP spec; at least I was told so, I never double checked. The problem however, was in the authorisation layer: <code>/admin</code> was a protected URL, but <code>//admin</code> was not. So the router would resolve <code>//admin</code> and all its underlying pages to the admin section, and the authoriser wouldn't recognise it as a location you'd need admin privileges for.</p>
<p>In other words: the admin section of all our websites could be entered without any login, by simply replacing <code>/admin</code> with <code>//admin</code>.</p>
<p>I don't remember drinking my coffee after that.</p>
<p>So we did the only thing we could do: manually update all of our websites, some running a very outdated version of our framework. It took us 3 days to do this with 5 or 6 developers. You can do the math on how much it cost.</p>
<p>In the end we never actually got to know whether the bug had been exploited: it was discovered by accident by one of our colleagues over the weekend, and we didn't keep access logs longer than a few days. So nobody could tell whether someone had unauthorised access to one of our sites over the past years; let alone know if, and which data had been leaked.</p>
<p>Don't write your own framework, at least not when you're building websites for paying clients; who trust your work to be professional and secure. Whatever framework you use, make sure it's backed by a large community.</p>
<p>Want to share your thoughts? Let's discuss them on <a target="_blank" href="https://news.ycombinator.com/item?id=23508370">HN</a>.</p>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2021-03-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8.1: Enums ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-enums"/>

                <id>https://www.stitcher.io/blog/php-enums</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>They are finally coming — built-in support for enums will be added in <a href="/blog/new-in-php-81">PHP 8.1</a>! Some might consider them long overdue, but you don't hear me complain; I'm glad they made it! This post is dedicated to looking at the newly added feature in-depth. If you want to stay up to date about these kinds of changes and new features in PHP, make sure to <a target="_blank" href="/newsletter/subscribe">subscribe to my newsletter</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>As usual with my PHP feature posts, we start with a high level overview of what enums look like:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span>;
}
</pre>
<p>The benefit of enums is that they represent a collection of constant values, but most importantly those values can be typed, like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogPost</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>, 
    </span>) {}
}
</pre>
<p>In this example, creating an enum and passing it to a <code>BlogPost</code> looks like this:</p>
<pre><span class="hl-variable">$post</span> = <span class="hl-keyword">new</span> <span class="hl-type">BlogPost</span>(<span class="hl-type">Status</span>::<span class="hl-property">DRAFT</span>);
</pre>
<p>That's the basics out of the way, as you can see there's nothing complex at all about them. There are lots of side notes to be made though, let's look at enums in depth!</p>
<h3 id="enum-methods"><a href="#enum-methods" class="heading-anchor">#</a> Enum methods</h3>
<p>Enums can define methods, just like classes. This is a very powerful feature, especially in combination with the <code>match</code> operator:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">color</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-variable">$this</span>) 
        {
            <span class="hl-type">Status</span>::<span class="hl-property">DRAFT</span> =&gt; '<span class="hl-value">grey</span>',   
            <span class="hl-type">Status</span>::<span class="hl-property">PUBLISHED</span> =&gt; '<span class="hl-value">green</span>',   
            <span class="hl-type">Status</span>::<span class="hl-property">ARCHIVED</span> =&gt; '<span class="hl-value">red</span>',   
        };
    }
}
</pre>
<p>Methods can be used like so:</p>
<pre><span class="hl-variable">$status</span> = <span class="hl-type">Status</span>::<span class="hl-property">ARCHIVED</span>;

<span class="hl-variable">$status</span>-&gt;<span class="hl-property">color</span>(); <span class="hl-comment">// 'red'</span>
</pre>
<p>Static methods are allowed as well:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">make</span>(): <span class="hl-type">Status</span>
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>And you can also use <code>self</code> within an enum:</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">color</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span>(<span class="hl-variable">$this</span>) 
        {
            <span class="hl-type">self</span>::<span class="hl-property">DRAFT</span> =&gt; '<span class="hl-value">grey</span>',   
            <span class="hl-type">self</span>::<span class="hl-property">PUBLISHED</span> =&gt; '<span class="hl-value">green</span>',   
            <span class="hl-type">self</span>::<span class="hl-property">ARCHIVED</span> =&gt; '<span class="hl-value">red</span>',   
        };
    }
}
</pre>
<h3 id="enum-interfaces"><a href="#enum-interfaces" class="heading-anchor">#</a> Enum interfaces</h3>
<p>Enums can implement interfaces, just like normal classes:</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">HasColor</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">color</span>(): <span class="hl-type">string</span>;
}
</pre>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span> <span class="hl-keyword">implements</span><span class="hl-type"> HasColor
</span>{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">color</span>(): <span class="hl-type">string</span> { <span class="hl-comment">/* … */</span> }
}
</pre>
<h3 id="enum-values-—-aka-&quot;backed-enums&quot;"><a href="#enum-values-—-aka-"backed-enums"" class="heading-anchor">#</a> Enum values — aka "Backed enums"</h3>
<p>Enum values are represented by objects internally, but you can assign a value to them if you want to; this is useful for eg. serializing them into a database.</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>: <span class="hl-type">string</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span> = '<span class="hl-value">draft</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span> = '<span class="hl-value">published</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span> = '<span class="hl-value">archived</span>';
}
</pre>
<p>Note the type declaration in the enum definition. It indicates that all enum values are of a given type. You could also make it an <code>int</code>. Take note that only <code>int</code> and <code>string</code> are allowed as enum values.</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>: <span class="hl-type">int</span>
{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span> = 1;
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span> = 2;
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span> = 3;
}
</pre>
<p>The technical term for typed enums is called "backed enums" since they are "backed" by a simpler value. If you decide to assign enum values, all cases should have a value. You cannot mix and match them. Enums that aren't "backed" are called "pure enums".</p>
<h3 id="backed-enums-with-interfaces"><a href="#backed-enums-with-interfaces" class="heading-anchor">#</a> Backed enums with interfaces</h3>
<p>If you're combining backed enums and interface, the enum type must come directly after the enum name, before the <code>implements</code> keyword.</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span>: <span class="hl-type">string</span> <span class="hl-keyword">implements</span><span class="hl-type"> HasColor
</span>{
    <span class="hl-keyword">case</span> <span class="hl-property">DRAFT</span> = '<span class="hl-value">draft</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">PUBLISHED</span> = '<span class="hl-value">published</span>';
    <span class="hl-keyword">case</span> <span class="hl-property">ARCHIVED</span> = '<span class="hl-value">archived</span>';
    
    <span class="hl-comment">// …</span>
}
</pre>
<h3 id="serializing-backed-enums"><a href="#serializing-backed-enums" class="heading-anchor">#</a> Serializing backed enums</h3>
<p>If you're assigning values to enum cases, you probably want a way to serialize and deserialize them. Serializing them means you need a way to access the enum's value. That's done with a readonly public property:</p>
<pre><span class="hl-variable">$value</span> = <span class="hl-type">Status</span>::<span class="hl-property">PUBLISHED</span>-&gt;<span class="hl-property">value</span>; <span class="hl-comment">// 2</span>
</pre>
<p>Restoring an enum from a value can be done by using <code>Enum::from</code>:</p>
<pre><span class="hl-variable">$status</span> = <span class="hl-type">Status</span>::<span class="hl-property">from</span>(2); <span class="hl-comment">// Status::PUBLISHED</span>
</pre>
<p>There's also a <code>tryFrom</code> that returns <code>null</code> if an unknown value is passed. If you'd use <code>from</code> there would be an exception.</p>
<pre><span class="hl-variable">$status</span> = <span class="hl-type">Status</span>::<span class="hl-property">from</span>('<span class="hl-value">unknown</span>'); <span class="hl-comment">// ValueError</span>
<span class="hl-variable">$status</span> = <span class="hl-type">Status</span>::<span class="hl-property">tryFrom</span>('<span class="hl-value">unknown</span>'); <span class="hl-comment">// null</span>
</pre>
<p>Note that you can also use the built-in <code>serialize</code> and <code>unserialize</code> functions on enums. Furthermore, you can use <code>json_encode</code> in combination with backed enums, its result will be the enum value. This behaviour can be overridden by implementing <code>JsonSerializable</code>.</p>
<h3 id="listing-enum-values"><a href="#listing-enum-values" class="heading-anchor">#</a> Listing enum values</h3>
<p>You can use the static <code>Enum::cases()</code> method to get a list of all available cases within an enum:</p>
<pre><span class="hl-type">Status</span>::<span class="hl-property">cases</span>();

<span class="hl-comment">/* [
    Status::DRAFT, 
    Status::PUBLISHED, 
    Status::ARCHIVED
] */</span>
</pre>
<p>Note that this array contains the actual enum objects:</p>
<pre><span class="hl-property">array_map</span>(
    <span class="hl-keyword">fn</span>(<span class="hl-injection"><span class="hl-type">Status</span> $status</span>) =&gt; <span class="hl-variable">$status</span>-&gt;<span class="hl-property">color</span>(), 
    <span class="hl-type">Status</span>::<span class="hl-property">cases</span>()
);
</pre>
<h3 id="enums-are-objects"><a href="#enums-are-objects" class="heading-anchor">#</a> Enums are objects</h3>
<p>I already mentioned that enums values are represented as objects, in fact those are singleton objects. That means that you can do comparisons with them like so:</p>
<pre><span class="hl-variable">$statusA</span> = <span class="hl-type">Status</span>::<span class="hl-property">PENDING</span>;
<span class="hl-variable">$statusB</span> = <span class="hl-type">Status</span>::<span class="hl-property">PENDING</span>;
<span class="hl-variable">$statusC</span> = <span class="hl-type">Status</span>::<span class="hl-property">ARCHIVED</span>;

<span class="hl-variable">$statusA</span> === <span class="hl-variable">$statusB</span>; <span class="hl-comment">// true</span>
<span class="hl-variable">$statusA</span> === <span class="hl-variable">$statusC</span>; <span class="hl-comment">// false</span>
<span class="hl-variable">$statusC</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Status</span>; <span class="hl-comment">// true</span>
</pre>
<h3 id="enums-as-array-keys"><a href="#enums-as-array-keys" class="heading-anchor">#</a> Enums as array keys</h3>
<p>Because enums values are actually objects, it's currently not possible to use them as array keys. The following will result in an error:</p>
<pre><span class="hl-variable">$list</span> = [
    <span class="hl-type">Status</span>::<span class="hl-property">DRAFT</span> =&gt; '<span class="hl-value">draft</span>',
    <span class="hl-comment">// …</span>
];
</pre>
<p>There is <a target="_blank" href="https://wiki.php.net/rfc/object_keys_in_arrays">an RFC</a> to change this behaviour, but it hasn't been voted yet.</p>
<p>This means you can only use enums as keys in <code>SplObjectStorage</code> and <code>WeakMaps</code>.</p>
<h3 id="traits"><a href="#traits" class="heading-anchor">#</a> Traits</h3>
<p>Enums can use traits just like classes, but with some more restrictions. You're not allowed to override built-in enum methods, and they can't contain class properties — those are prohibited on enums.</p>
<h3 id="reflection-and-attributes"><a href="#reflection-and-attributes" class="heading-anchor">#</a> Reflection and attributes</h3>
<p>As expected, there are a few reflection classes added for dealing with enums: <code>ReflectionEnum</code>, <code>ReflectionEnumUnitCase</code> and <code>ReflectionEnumBackedCase</code>. There's also a new <code>enum_exists</code> function which does what its name suggests.</p>
<p>Just like normal classes and properties, enums and their cases can be annotated using <a href="/blog/attributes-in-php-8">attributes</a>. Note that <code>TARGET_CLASS</code> filter will also include enums.</p>
<p>One last thing: enums also have a read only property <code>$enum-&gt;name</code>, which the RFC mentions is an implementation detail and should probably only be used for debugging purposes. It's still worth mentioning though.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>That's about all there is to say about enums, I'm very much looking forward to using them as soon as <a href="/blog/new-in-php-81">PHP 8.1 arrives</a>, and also to sunset my own <a target="_blank" href="https://github.com/spatie/enum">userland implementation</a>.</p>
 ]]></summary>

                <updated>2021-02-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP Enums before PHP 8.1 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-enums-before-php-81"/>

                <id>https://www.stitcher.io/blog/php-enums-before-php-81</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="sidenote">
<h2 id="native-support-in-php-8.1!"><a href="#native-support-in-php-8.1!" class="heading-anchor">#</a> Native support in PHP 8.1!</h2>
<p>You can read all about built-in enums in PHP 8.1 in <a href="/blog/php-enums">this post</a>. If you're looking for more information on userland implementations of enums before PHP 8.1, you can continue to read this post.</p>
</div>
<p>If you came here looking for our enum implementation in PHP, that's <a target="_blank" href="https://github.com/spatie/enum">this way</a>. If you're interested in the design philosophy behind it, read on!</p>
<hr />
<p>An enumeration type, "enum" for short, is a data type to categorise named values.
Enums can be used instead of hard coded strings to represent, for example,
the status of a blog post in a structured and typed way.</p>
<p>PHP doesn't have a native enum type.
It offers a very basic <a target="_blank" href="http://php.net/manual/en/class.splenum.php">SPL implementation</a>,
but this really doesn't cut the mustard.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>There's a popular package written by <a target="_blank" href="https://mobile.twitter.com/matthieunapoli">Matthieu Napoli</a>
called <a target="_blank" href="https://github.com/myclabs/php-enum">myclabs/php-enum</a>.
It's a package I and many others have been using in countless projects.
It's really awesome.</p>
<p>Today I want to explore some of the difficulties we encounter when solving problems like enums in userland.
I'll talk about my personal take on enums, and we'll ponder on core support.</p>
<p>One last note:
I will assume that you know what enums are,
and that you know on how to use them in real life projects.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="imagine-if:"><a href="#imagine-if:" class="heading-anchor">#</a> Imagine if:</h2>
<p>We could write something like this in PHP…</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setStatus</span>(<span class="hl-injection"><span class="hl-type">PostStatus</span> $status</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">status</span> = <span class="hl-variable">$status</span>;
    }
}
</pre>
<p>… and be sure that the value of <code>Post::$status</code> is always one of three strings:
<code>draft</code>, <code>published</code> or <code>archived</code>.</p>
<p>Say we'd save this <code>Post</code> in a database, its status would automatically be represented as a string.</p>
<p>The <code>myclabs/php-enum</code> package allows us to write this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostStatus</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
    <span class="hl-keyword">const</span> <span class="hl-property">DRAFT</span> = '<span class="hl-value">draft</span>';
    <span class="hl-keyword">const</span> <span class="hl-property">PUBLISHED</span> = '<span class="hl-value">published</span>';
    <span class="hl-keyword">const</span> <span class="hl-property">ARCHIVED</span> = '<span class="hl-value">archived</span>';
}
</pre>
<p>We could use the constant values directly like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setStatus</span>(<span class="hl-injection"><span class="hl-type">string</span> $status</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">status</span> = <span class="hl-variable">$status</span>;
    }
}

<span class="hl-comment">// …</span>

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">setStatus</span>(<span class="hl-type">PostStatus</span>::<span class="hl-property">DRAFT</span>);
</pre>
<p>But this prevents us to do proper type checking, as every string could be passed to <code>Post::setStatus()</code>.</p>
<p>A better approach is to use a little magic introduced by the library:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostStatus</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">DRAFT</span> = '<span class="hl-value">draft</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PUBLISHED</span> = '<span class="hl-value">published</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">ARCHIVED</span> = '<span class="hl-value">archived</span>';
}

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">setStatus</span>(<span class="hl-type">PostStatus</span>::<span class="hl-property">DRAFT</span>());
</pre>
<p>Using the magic method <code>__callStatic()</code> underneath, an object of the class <code>PostStatus</code> is constructed,
with the <code>'draft'</code> value in it.</p>
<p>Now we can type check for <code>PostStatus</code>
and ensure the input is one of the three things defined by the "enum".</p>
<p>Here's the problem with the <code>myclabs/php-enum</code> package though:
by relying on <code>__callStatic()</code>, we lose static analysis benefits like auto completion and refactoring:</p>
<p><img src="/resources/img/blog/enum/no-autocomplete.gif" srcset="/resources/img/blog/enum/no-autocomplete-894x573.gif 894w, /resources/img/blog/enum/no-autocomplete-774x496.gif 774w, /resources/img/blog/enum/no-autocomplete-447x286.gif 447w, /resources/img/blog/enum/no-autocomplete-1000x642.gif 1000w, /resources/img/blog/enum/no-autocomplete-632x405.gif 632w" sizes="" alt=""></img></p>
<p>As you can see in this case, your IDE is unaware of the <code>PostsStatus::DRAFT()</code> method.</p>
<p>Luckily, this problem is solvable with docblock type hints:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@method</span> static self DRAFT()
 * <span class="hl-value">@method</span> static self PUBLISHED()
 * <span class="hl-value">@method</span> static self ARCHIVED()
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">PostStatus</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">DRAFT</span> = '<span class="hl-value">draft</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PUBLISHED</span> = '<span class="hl-value">published</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">ARCHIVED</span> = '<span class="hl-value">archived</span>';
}

<span class="hl-variable">$post</span>-&gt;<span class="hl-property">setStatus</span>(<span class="hl-type">PostStatus</span>::<span class="hl-property">DRAFT</span>());
</pre>
<p>But now we're in trouble when refactoring an enum's value.
Say we want to rename <code>DRAFT</code> to <code>NEW</code>:</p>
<p><img src="/resources/img/blog/enum/no-refactor.gif" srcset="/resources/img/blog/enum/no-refactor-632x524.gif 632w, /resources/img/blog/enum/no-refactor-1000x830.gif 1000w, /resources/img/blog/enum/no-refactor-894x742.gif 894w, /resources/img/blog/enum/no-refactor-774x642.gif 774w, /resources/img/blog/enum/no-refactor-447x371.gif 447w" sizes="" alt=""></img></p>
<p>Also we're maintaining duplicate code: there's the constant values, and the doc blocks.</p>
<p>At this point it's time to stop and think.
In an ideal world, we'd have built-in enums in PHP:</p>
<pre>enum PostStatus {
    DRAFT, PUBLISHED, ARCHIVED;
}
</pre>
<p>Since that's not the case right now, we're stuck with userland implementations.</p>
<p>Extending PHP's type system in userland most likely means two things: magic and reflection.</p>
<p>If we're already relying on these two elements,
why not go full-out and make our lives as simple as possible?</p>
<p>Here's how I write enums today:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@method</span> static self DRAFT()
 * <span class="hl-value">@method</span> static self PUBLISHED()
 * <span class="hl-value">@method</span> static self ARCHIVED()
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">PostStatus</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
}
</pre>
<p>Opinionated, right? It's less code to maintain though, with more benefits.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>I <em>know</em> this is far from an ideal situation.
It would be amazing to see built-in support for enums in PHP one day.
But until then, this has to do.</p>
<p>If you want to, you can try out my implementation <a target="_blank" href="https://github.com/spatie/enum">here</a>.</p>
<p>So, what's your take on enums? Do you want them in core PHP?
Let's talk about it on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a>!</p>
 ]]></summary>

                <updated>2021-02-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ A storm in a glass of water ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-storm-in-a-glass-of-water"/>

                <id>https://www.stitcher.io/blog/a-storm-in-a-glass-of-water</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I just read a post about PHP 8 that I couldn't just silently ignore. If you want to read it first, go <a target="_blank" href="https://24daysindecember.net/2020/12/21/a-perfect-storm/">check it out</a>.</p>
<p>With a fitting title "A Perfect Storm", the author voices their concerns about how upgrading to PHP 8 isn't an easy path, and how open source maintainers have to struggle to be able to support PHP 8 on top of their existing codebase.</p>
<p>There's no denying that PHP 8 introduces <a href="/blog/new-in-php-8">some breaking changes</a>. Especially the addition of union types, named arguments and consequently the changes made to the reflection API might feel like a pain.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>What the author seems to forget when calling PHP 8 "a nightmare" and claiming it'll take years before being able to use it, is that PHP 8 is a major version, and things are allowed to break. Better yet: it's the entire purpose of a major release.</p>
<p>I don't blame the author for this sentiment, it lives in lots of people's mind. I think it's a side effect from a long and stable period of releases during the 7.x era. We've got used to easy updates, and we find it difficult when our code breaks because of one.</p>
<p>The problem however isn't with PHP growing and maturing, it's with developers and companies not being able to adapt quickly enough. Here's the brutal truth: PHP 7.4 has <a target="_blank" href="https://www.php.net/supported-versions.php">less than one year</a> of active support to go. By the end of 2021, PHP 8 will be the only version (together with the future PHP 8.1) that's still actively worked on. You <em>need</em> to get on board, or you risk becoming stuck in legacy land. Believe it or not, but PHP 7.4 will one day be what we perceive PHP 5.4 or PHP 5.6 to be: completely outdated, insecure and slow.</p>
<p>Instead of shifting the blame on the perfectly healthy and stable release cycle of PHP, we should look at ourselves and our companies.</p>
<hr />
<p>If you're still here and wanting to ride along, let's discuss a few things that <em>you</em> can do to prevent ending up in legacy land.</p>
<p>First: learn and use the proper <strong>tools</strong>. A <a href="/blog/craftsmen-know-their-tools">craftsman is nothing without proper knowledge of his tools</a>. These tools include <a target="_blank" href="https://psalm.dev/">static analysers</a>, <a target="_blank" href="https://github.com/FriendsOfPHP/PHP-CS-Fixer">code formatters</a>, <a target="_blank" href="https://www.jetbrains.com/phpstorm/">IDEs</a>, <a target="_blank" href="https://phpunit.de/">test frameworks</a> and <a target="_blank" href="https://github.com/rectorphp/rector">automatic updaters</a>. Most problems you face during upgrades are actually solved automatically if only you'd use the proper tools.</p>
<p>While you're at it, consider buying the people maintaining those projects a drink, they are going to save you hours upon hours of manual and boring labour; they are worth a few bucks. We recently upgraded a large project to PHP 8. It took a few hours of preparation and research, and only 2 hours to do the actual upgrade; it's doable.</p>
<p>Next: if you're an <strong>open source maintainer</strong>. Don't bother supporting all of PHP 7 and 8 in the same version. Embrace PHP 8 as your main target and support 7.4 if it doesn't cause any problems. If you really need to actively support older versions, you'll have to support separate branches.</p>
<p>What baffles me about the "open source argument" made by many against PHP 8, is that they seem to forget that their old tags will keep working just fine. It's not because code isn't actively maintained any more that you're prohibited from using it. If your users really need to support an older PHP version, have them use an older version of your packages. If there's a crucial feature missing from those older versions, they are free to fork the package and do whatever they want with it. There shouldn't be anything holding you back from only supporting the active PHP versions. If anything, you're encouraging the majority of your users to upgrade faster, you're doing the PHP community a favour.</p>
<p>Finally, if you're in <strong>management or running a company</strong>: sticking with older PHP versions will always make you lose money in the end. Every year you hold off on updating your codebase, it becomes more difficult and time-consuming to catch up. Can you imagine what will happen when a critical security issue is discovered in your old version? On top of that: employees really worth their money won't stick with your legacy project forever. One day they'll seize a new opportunity if you don't keep them happy. If you're not keeping up to date, you're loosing in the end.</p>
<hr />
<p>Part of being a professional developer is to be able to deal with these kinds of situations. Sure, I'd rather spend those hours spent updating on something else, but I know it's a small investment for a lot of joy in the long run.</p>
<p>Don't get dragged along the negativity, embrace the maturing language that is PHP and follow along. You won't regret it.</p>
 ]]></summary>

                <updated>2021-01-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP reimagined ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-reimagined"/>

                <id>https://www.stitcher.io/blog/php-reimagined</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>If it were up to me, I'd change a thing or two about PHP.
Of course, I don't have anything to say about PHP's development, and that's ok. I still find it an interesting thought experiment to discover what changes I'd like to make to the language I use on a day-by-day basis and I'd love to hear <a target="_blank" href="https://twitter.com/brendt_gd">your thoughts</a> as well.
To be clear: it's a very subjective list and in no way a critique on the amazing work the core team is doing.</p>
<p>This is an updated version of an older post of mine, since PHP is <a href="/blog/new-in-php-8">growing and evolving</a> year by year. Let's dive in!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="final-by-default"><a href="#final-by-default" class="heading-anchor">#</a> Final by default</h2>
<p>A <a target="_blank" href="https://front-line-php.com/object-oriented">common misconception</a> about OO programming is that it's all about inheritance.
Inheritance and polymorphism have their place, but OO is way more than that.</p>
<p>Because these principles are more often than not abused by programmers who claim they write "OO" code,
I think the language should help prevent us making these mistakes.</p>
<p>That's why I would make all classes final by default:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
}
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
}
</pre>
<p>Going even one step further: classes are only allowed to extend from abstract classes or implement interfaces.
This way we can prevent deep inheritance chains of concrete classes.</p>
<h2 id="void-by-default"><a href="#void-by-default" class="heading-anchor">#</a> Void by default</h2>
<p>Void is a strange thing when you think about it: it a "type", indicating the lack of a type.
Why not go with the obvious way: no return type, means nothing is returned.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>(): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>()
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
    }
}
</pre>
<p>Now you might be thinking: what if a function wants to return two types, that's the next point.</p>
<h2 id="no-mixed-type"><a href="#no-mixed-type" class="heading-anchor">#</a> No <code>mixed</code> type</h2>
<p>The <code>mixed</code> type basically means:
"you've got no idea what this function needs or will return, figure it out on your own".</p>
<p>Such a loose type system can be the source of many bugs.
If you feel the need to use two different types in the same function,
you should either make two implementations — this is where polymorphism has its place;
or you should program to an interface.</p>
<p>Either way, there's <em>always</em> a better solution then relying on <code>mixed</code>.
In my version of PHP, the language would ensure we always choose the better solution.</p>
<h2 id="all-parameters-must-by-typed"><a href="#all-parameters-must-by-typed" class="heading-anchor">#</a> All parameters must by typed</h2>
<p>We already established that my version of PHP would make return types required.
It's no surprise that the same goes for function parameters.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection">$bar</span>)
{
}
</pre>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection"><span class="hl-type">Bar</span> $bar</span>)
{
}
</pre>
<h2 id="class-properties-must-be-typed"><a href="#class-properties-must-be-typed" class="heading-anchor">#</a> Class properties must be typed</h2>
<p>The same rules apply to class properties.
Luckily for us, PHP 7.4 will introduce <a href="/blog/new-in-php-74#typed-properties-rfc">typed properties</a>.
I'd make them required though.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-property">$bar</span>;
}
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">Bar</span> <span class="hl-property">$bar</span>;
}
</pre>
<h2 id="visibility-modifiers-are-required"><a href="#visibility-modifiers-are-required" class="heading-anchor">#</a> Visibility modifiers are required</h2>
<p>Explicitness eliminates room for confusion.
That's why all methods and class variables must have a visibility modifier.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">function</span> <span class="hl-property">bar</span>()
    {
        <span class="hl-comment">// …</span>
    }
} 
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>()
    {
        <span class="hl-comment">// …</span>
    }
} 
</pre>
<h2 id="final-on-variables"><a href="#final-on-variables" class="heading-anchor">#</a> Final on variables</h2>
<p>I started this list by saying I'd drop the <code>final</code> keyword, that is on classes and methods.
<code>final</code> would be a valid keyword to mark class variables as "read only".</p>
<p>A final variable may be set on construct, and not be changed afterwards.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">final</span> Bar <span class="hl-property">$bar</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">__construct(Bar</span> <span class="hl-property">$bar</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">bar</span> = <span class="hl-variable">$bar</span>;
    }
}
</pre>
<pre><span class="hl-variable">$foo</span> = <span class="hl-keyword">new</span> <span class="hl-type">Foo</span>(<span class="hl-variable">$bar</span>);

<span class="hl-variable">$foo</span>-&gt;<span class="hl-property">bar</span> = <span class="hl-keyword">new</span> <span class="hl-type">Bar</span>();
</pre>
<h2 id="no-more-uninitialized-state"><a href="#no-more-uninitialized-state" class="heading-anchor">#</a> No more uninitialized state</h2>
<p>Right now, <a href="/blog/typed-properties-in-php-74">Typed properties</a> can be initialized after construction. This is valid PHP</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$bar</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>() {
        <span class="hl-comment">// Don't initialize bar</span>
    }
}

<span class="hl-variable">$foo</span> = <span class="hl-keyword">new</span> <span class="hl-type">Foo</span>();

<span class="hl-variable">$foo</span>-&gt;<span class="hl-property">bar</span> = '<span class="hl-value">abc</span>';
</pre>
<p>PHP only throws an error when the property is accessed before it's initialised.</p>
<pre><span class="hl-variable">$foo</span> = <span class="hl-keyword">new</span> <span class="hl-type">Foo</span>();

<span class="hl-keyword">echo</span> <span class="hl-variable">$foo</span>-&gt;<span class="hl-property">bar</span>; <span class="hl-comment">// Error</span>
</pre>
<p>I'd say to get rid rid of this behaviour. If a typed property isn't initialised after the object was constructed, you get an error.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="named-parameters"><a href="#named-parameters" class="heading-anchor">#</a> Named parameters</h2>
<p>Named parameters were originally on this list, but fortunately are <a href="/blog/php-8-named-arguments">possible as of PHP 8</a>!</p>
<h2 id="better-closures"><a href="#better-closures" class="heading-anchor">#</a> Better closures</h2>
<p>I originally listed "multiline short closures" here, but I think it's a little bit more complex. What I'd like to see is a combination of <code>function/fn</code> and <code>=&gt;/{</code>. I'd make all combinations possible:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">a</span>() {
    <span class="hl-keyword">return</span> <span class="hl-comment">/* … */</span>;
}

<span class="hl-keyword">function</span> <span class="hl-property">b</span>() =&gt; 1;

<span class="hl-keyword">fn</span> <span class="hl-property">c</span>() {
    <span class="hl-keyword">return</span> <span class="hl-comment">/* … */</span>;
}

<span class="hl-keyword">fn</span> <span class="hl-property">d</span>() =&gt; 1;
</pre>
<p>Here's the difference: when using the <code>function</code> keyword, there's no automatic access to the outer scope, in other words you'll have to use <code>use</code> to access variables outside the closure. Using <code>fn</code> doesn't have this restriction.</p>
<p>If you're using the bracket notation for the closure's body <code>{}</code>, you'll be allowed to write multiline functions, but there's no magic return statement. <code>=&gt;</code> on the other hand only allows a single expression, which is immediately returned.</p>
<h2 id="scalar-types-are-also-objects"><a href="#scalar-types-are-also-objects" class="heading-anchor">#</a> Scalar types are also objects</h2>
<p>One of the few things I think that we're all in agreement about:
the current PHP function names and definitions are inconsistent and kind of sucky.</p>
<p>Let's treat all scalar types as objects,
allowing them to contain what otherwise would be standalone functions.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(): <span class="hl-type">string</span>
{
    <span class="hl-keyword">return</span> &quot;<span class="hl-value">a, b, c</span>&quot;;
}

<span class="hl-variable">$this</span>-&gt;<span class="hl-property">handle</span>()-&gt;<span class="hl-property">explode</span>('<span class="hl-value">,</span>');
</pre>
<h2 id="improved-variance"><a href="#improved-variance" class="heading-anchor">#</a> Improved variance</h2>
<p>You may have noticed a trend in the above changes.
Most of them relate to PHP's type system.
If all them were added, we'd also need to make the current type system more flexible.</p>
<p>Luckily again, PHP 7.4 already introduces <a href="/blog/new-in-php-74#improved-type-variance-rfc">improvements regarding type variance</a>.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span> { <span class="hl-comment">/* … */</span> }
</pre>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection"><span class="hl-type">Bar</span> $bar</span>): <span class="hl-type">Foo</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">B</span> <span class="hl-keyword">implements</span><span class="hl-type"> A
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection"><span class="hl-type">Foo</span> $bar</span>): <span class="hl-type">Bar</span>
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<h2 id="always-strict-type-checking"><a href="#always-strict-type-checking" class="heading-anchor">#</a> Always strict type checking</h2>
<p>Strict type checking is done by default, you should never <code>declare(strict_types=1);</code> anymore.</p>
<h2 id="generics"><a href="#generics" class="heading-anchor">#</a> Generics</h2>
<p>After several improvements to the type system, I'd add some more improved ways to actually use it.</p>
<p>First a feature that probably most of the PHP world is waiting for: generics.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">List</span>&lt;<span class="hl-property">T</span>&gt;
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">current</span>(): <span class="hl-type">T</span>
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<h2 id="enums"><a href="#enums" class="heading-anchor">#</a> Enums</h2>
<p>Next up: built-in enums.
Based on the <a target="_blank" href="https://github.com/myclabs/php-enum">several</a> <a target="_blank" href="https://github.com/marc-mabe/php-enum">userland</a>
<a target="_blank" href="https://github.com/spatie/enum">implementations</a>
it's clear that the community would benefit from a built-in enum type.</p>
<pre><span class="hl-keyword">enum</span> <span class="hl-type">Status</span> 
{
    <span class="hl-type">DRAFT</span>, <span class="hl-property">STATUS</span>, <span class="hl-property">PUBLISHED</span>;
}
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Bar</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">Status</span> <span class="hl-property">$status</span>;
}
</pre>
<pre><span class="hl-variable">$bar</span>-&gt;<span class="hl-property">status</span> = <span class="hl-type">Status</span>::<span class="hl-property">DRAFT</span>;
</pre>
<p>It's interesting to note that a new RFC <a target="_blank" href="https://wiki.php.net/rfc/enumerations_and_adts">popped up</a> that might add enums in PHP 8.1. It's still being discussed though, so nothing concrete yet.</p>
<h2 id="structs"><a href="#structs" class="heading-anchor">#</a> Structs</h2>
<p>To end this list: structs.
One of my own packages I use all the time is the <a target="_blank" href="https://github.com/spatie/data-transfer-object">data transfer object</a> package.
It allows us to define strongly typed objects.
In essence, they are a userland implementation of what structs are meant to solve.</p>
<pre>struct Point {
    int <span class="hl-variable">$x</span>;
    int <span class="hl-variable">$y</span>;
}
</pre>
<pre><span class="hl-variable">$point</span> = Point {1, 2}
</pre>
<h2 id="what-would-you-like-to-change?"><a href="#what-would-you-like-to-change?" class="heading-anchor">#</a> What would you like to change?</h2>
<p>Let me know <a target="_blank" href="https://twitter.com/brendt_gd">what's on your PHP wishlist</a>! If you want to be kept in the loop, feel free to subscribe to <a href="https://stitcher.io/newsletter/subscribe">my newsletter</a>.</p>
 ]]></summary>

                <updated>2021-01-13T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Websites should be more like Star Wars ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/websites-like-star-wars"/>

                <id>https://www.stitcher.io/blog/websites-like-star-wars</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I have to admit I'm not the biggest Star Wars fan, but I can enjoy one of the movies from time to time. Whenever I watch one there is <em>one</em> thing that always stands out: the movement in everything Star Wars related feels… odd.</p>
<p>Here's what I mean with that: whenever a door slides open or a non-human character speaks, whenever a droid walks or moves; those movements feel a little unnatural to me. It makes the characters feel like puppets, and it makes objects like sliding doors feel like they have no actual weight.</p>
<p>Here's an example:</p>
<p>
    <img src="/resources/img/static/star-wars/star-wars.gif"/>
</p>
<p>Baby Yoda feels like it's a hand played puppet, its movements don't seem natural at all. There is, of course, a good reason that Star Wars uses this approach: it's a style they continued to use ever since the oldest movies which, back in the day, had to deal with much more technical limitations and where the puppet-like feeling was unavoidable. They decided to continue to use the same style of movement, not because it was necessary, but because of the charm and nostalgia feeling.</p>
<p>So what does that have to do with websites?</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>I was a toddler when the internet began to grow, so I'm too young to have witnessed its rise first hand. Still I got into web development at an early age, starting with HTML when I was 12. These were times when the web was still shaping itself to what we know today. Just like Star Wars, the web had to deal with lots of technical limitations but with those limitations came creativity.</p>
<p>When I browse the web today, there's little creativity left to find. Sure, most websites are as polished as can be, but compare their design to ten others in the same niche, and you'll quickly start to see pattern emerging. While so many websites these days are pixel-perfect, they lack the soul and personality the web used to have.</p>
<p>Test it yourself: think about a topic and do a simple google search. Whether it's email campaigns, travel blogs, social media or news sites; there's little distinction between them.</p>
<p>I wish more websites aimed to be more like Star Wars: not sticking to the modern day rules and instead hold on to the things that give character, that make your website unique. We're allowed to break free from best practices, we're allowed to experiment.</p>
<p>The web still allows you to do so, the only thing holding us back is us.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2021-01-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ How to be right on the internet ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/how-to-be-right-on-the-internet"/>

                <id>https://www.stitcher.io/blog/how-to-be-right-on-the-internet</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>The internet is a wonderful place. It's full of knowledge, it enables us to stay close to family and friends, and sometimes there are people who get under your skin and cause an immense amount of frustration. I've been on both sides: the one dealing with troublemakers, but also the troublemaker himself.</p>
<p>Arguments and fights on the internet can make you feel exhausted, often having an effect on your mood in real life. So today I'd like to share a few guidelines with you on managing such situations. You can apply these rules to every situation: whether you've found yourself unwillingly dragged into a conversation that's quickly spiralling out of control, or whether you're the one who's getting a little heated yourself.</p>
<p>Finally, before diving in, I want to mention a very popular book on the topic of "how to deal with people": <a target="_blank" href="https://en.wikipedia.org/wiki/The_7_Habits_of_Highly_Effective_People">The 7 Habits of Highly Effective People</a> by Stephen Covey. It's one of the most popular resources on people management, and part of this post was inspired by Covey's principles.</p>
<h2 id="the-meaning-of-conflict"><a href="#the-meaning-of-conflict" class="heading-anchor">#</a> The meaning of conflict</h2>
<p>First things first: I use the term "conflict" and I want to make sure we're all on the same page on what it means. Let's look at the Oxford Dictionary's definition:</p>
<blockquote>
<p>a situation in which people, groups or countries disagree strongly or are involved in a serious argument</p>
</blockquote>
<p>Note how it doesn't say anything about the feelings of those people, groups or countries. This is the definition I'll assume when I use the term "conflict" throughout this post. It's a situation where a tension between people exists, but it doesn't mean that that situation needs to deteriorate into one where feelings are hurt and frustration arises.</p>
<p>When I say "conflict", it means there is a situation where people don't agree, but it doesn't mean they are fighting over it.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="five-rules"><a href="#five-rules" class="heading-anchor">#</a> Five rules</h2>
<p>Instead of the seven habits described by Covey (which cover more than conflict resolving), we'll stick with five rules.</p>
<p>I've managed several online communities in the past years and most recently I've been moderating /r/php on Reddit. I wouldn't say I have to deal with conflicts every day, but they are very real and very abundant indeed. That's why I always try to follow these five rules when having a conversation, and I find they work very well.</p>
<p>The first four rules focus on conflict resolving in a constructive way. They have in common that they focus on a positive outcome. They assume a level of empathy and understanding.
The fifth rule is for dealing with conflicts when there's no other way out. It's the emergency break when you notice the conversation is derailing. It's the most drastic one, but in some cases it's better to prevent further escalation.</p>
<p>Also note that you can use these rules, even when the other party doesn't agree to them. That's truly the power of these rules: you can apply them yourself even when the other side doesn't have the same constructive intentions. You'll notice that in most cases they'll even start copying your way of communication throughout a conflict, and start being constructive themselves, without even knowing.</p>
<p>Let's look at these rules one by one.</p>
<h3 id="right-or-wrong"><a href="#right-or-wrong" class="heading-anchor">#</a> Right or Wrong</h3>
<p>Rule number one: there seldom is one absolute truth. Most times there's only our personal interpretation of any given situation. All of us have a background and context; things like education, programming languages, frameworks, projects and workplace have a tangible impact on our opinion, our view of the world.</p>
<p>There's a lot of power in realizing that both you and the other party are not neutral. I even think this offers a significant learning opportunity: a conflict where both parties are open to the context of the other one can result in valuable lessons for both.</p>
<p>We're only  into rule one, and we've already identified a secondary goal: we can not only prevent conflicts from devolving into chaos, but we can seize the given opportunities to learn and grow. Even when the other party isn't interested in your context, it's still possible for you to grow.</p>
<h3 id="perspective"><a href="#perspective" class="heading-anchor">#</a> Perspective</h3>
<p>You're on the internet, written text can — and will — be interpreted in other ways than intended. I'd say that written text is one of the worst mediums to resolve conflicts with, since there's very little nuance you can make with dry text.</p>
<p>This is why people on the internet often come across as more rude than they'd be in real life. While many simply forget about the downsides of text, some know it very well and abuse that "freedom" the internet gives. The way some people act online is mind-boggling to me: surely they can't be like this in real life? Realizing this reality will help you put heated conflicts into perspective.</p>
<p>But there's also something to say the other way around: you have to make sure the other party doesn't misinterpret what you wrote. That's why I try to explain my perspective clearly enough when dealing with a conflict. It often looks something like this:</p>
<p>"<em>I want to make sure this doesn't come across as rude. I genuinely believe my point of view is the correct one, but I don't want to insult you by phrasing it in a rude or hurtful way.</em>"</p>
<p>Addressing your perspective and acknowledging that there can be differences is often enough to defuse tensions entirely.</p>
<h3 id="expectations-instead-of-assumptions"><a href="#expectations-instead-of-assumptions" class="heading-anchor">#</a> Expectations instead of assumptions</h3>
<p>When reading someone's comments, you might be inclined to assume an undertone, an emotion, maybe even an unspoken opinion. These assumptions might trigger you in writing a more offensive response. You should be aware that all of this can happen unconsciously, and protect yourself from it.</p>
<p>The most effective way of doing so is by describing how you interpreted any given kind of text. Next you should allow the other party to correct your assumptions.</p>
<p>"<em>I interpreted what you've written here as such and such, and want to make it clear that my answer is based on that interpretation. If you didn't mean it the way I interpreted it, please let me know.</em>"</p>
<p>From your point of view, you can be one step ahead and clarify your emotions and possible underlying feelings within the text. Furthermore, by reviewing what you've written, you can often identify parts that might be misconstrued and rewrite them. In some cases it even helps identify that you as well were driven by emotions without knowing and help prevent further escalation by rephrasing before posting.</p>
<h3 id="conflict-resolving"><a href="#conflict-resolving" class="heading-anchor">#</a> Conflict resolving</h3>
<p>One important thing to keep in mind at all times is that resolving a conflict doesn't mean all parties have to agree. It's perfectly fine to step away without agreement. There are conflicts that can't be resolved, and you'll have to find a way of dealing with such situations. Sometimes this means that you both agree to disagree, but other times it can also result in one of the parties stepping away from a project or community. Conflict resolving can be drastic indeed, but it should always be done in a respectful and civilized manner.</p>
<p>If you keep the goal of resolving a conflict in mind, you can steer the conversation in the right way.</p>
<h3 id="the-power-of-silence"><a href="#the-power-of-silence" class="heading-anchor">#</a> The power of silence</h3>
<p>Like I said before, the fifth rule is the emergency break. There are conflicts that you don't want to engage in or where the other party doesn't seem to be open to any kind of other opinion. You'll always have the power to simply step away from those conversations.</p>
<p>In such cases, it would be most polite to let the other party know you won't be engaging this conversation any further, but there might be cases where even such a message wouldn't be welcome. Just step away. You don't <em>have</em> to reply, you don't <em>have</em> to engage. Decide what's worth your time and what's not.</p>
<p>You shouldn't consider "stepping away" as failing: in some cases it's actually the better and smarter thing to do.</p>
<h2 id="in-summary"><a href="#in-summary" class="heading-anchor">#</a> In summary</h2>
<ol>
<li>There is rarely one absolute truth, more often there are our interpretations, influenced by our personal context.</li>
<li>Written text is one of the worst mediums to accurately describe your feelings. Use text to your advantage and clearly describe what your intentions are.</li>
<li>Voice your assumptions instead of letting them guide you unintentionally.</li>
<li>Resolving a conflict doesn't mean you have to agree with each other.</li>
<li>If all else fails, you have the power to step away.</li>
</ol>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2020-12-31T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ When I lost a few hundred leads ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/when-i-lost-a-few-hundred-leads"/>

                <id>https://www.stitcher.io/blog/when-i-lost-a-few-hundred-leads</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="sidenote">
<h2>Before you start…</h2>
<p>Some readers have reached out to me and talked about solutions to the technical problems described in this post. I'd like to make clear that this post isn't about how to deal with or prevent bugs. It's about how I felt during a rather bad and stressful time, to talk about emotions and how to self-reflect and improve. With that out of the way, I hope you find value in this post.</p>
</div>
<p>I went home that evening anxious and stressed out. I'm not ashamed to admit I had to fight back a few tears on the train during my commute back home. Those weren't tears of sadness, mind you, rather tears of fear.</p>
<p>It had only been a few hours since my manager came to me saying that one of our clients complained that someone called them, saying they expected to have gotten a call after filling in the contact form and they never did.
They asked me to look into it.</p>
<p>See, this client sold a particular service to people, and they could fill in a form on the website to ask for a quote. Depending on their residence the closest office would call them back after they'd filled in that form. This wasn't a super complex form, it had three steps, and asked some information about people's project, some check boxes, radio buttons and drop downs — you've seen such forms before. Every request submitted is called "a lead" (a potential client), hence the name we internally gave the form: "the lead form".</p>
<p>When one of those leads called our client's office to complain about never receiving a phone call, the office manager was clever enough to ask for the lead's email address, making my job easier. All I had to do was go in the database, find the form submission for that lead's email address, and look at what went wrong.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>As a junior developer, my first thought was to look for external problems. Every time a lead submitted the form, an email would be sent to the corresponding office with all information, my guess was that either that email ended up in spam for some reason, or that maybe there had been a problem with our mailing service.</p>
<p>I couldn't find an entry in our database for that email address though.</p>
<p>"The address is probably wrong" — I remember thinking. See, the first thing that happens when the form is submitted is that its contents are saved into the database. That way we always have a copy of the data, in case something went wrong with mailing the office. So I told my manager to contact our client, telling them the email address they gave me is probably wrong, and went on with my day.</p>
<p>A few minutes later and my manager tells me that the email address is absolutely correct.</p>
<p>Ok, that means that the form was never submitted then? I sigh out loud: "it probably has to do with all third party javascript trackers and marketing tools we're using on the site". Team marketing was quite into using A/B testing libraries or tools like Mouseflow to record a user's screen so that they can analyse how people interact with the website. I wouldn't be surprised if one of those tools messed up the form submission.</p>
<p>So I call their marketing team and ask if they know anything more about this lead. They tell me they'll look into it and I, again, went on with my day. An hour goes by and I've already forgotten about the whole affair thanks to my "not my problem" mentality. Suddenly my manager's back again: team marketing wants to speak to me and he hands me the phone.</p>
<p>They have found the screen recording for that particular lead. Around 50% of all sessions were recorded, so we were pretty lucky finding it. It turns out the lead actually submitted the form, they'll send me the recording now.</p>
<p>This is the point where I start to consider that it <em>might</em> be my problem after all, but let's not jump to conclusions. I watch the recording, and yes indeed: the lead fills in step one, step two, step three, submits it and… that's not the right page. He should see a "thank you" page after submitting the form. Instead he sees a page with the header and footer of the website, but without any content on it.</p>
<p>That's not good.</p>
<p>I go into the test environment and submit the form with exactly the same data. I end up on the same blank page, and sure enough my submission isn't saved into the database. is this page? I've never seen it before. So I look at the logs. An error: <code>null passed instead of boolean</code>. That's a type error deep down in <em>my</em> code.</p>
<hr />
<p>Before moving on, let me tell you about the error, why it happened and why no one knew of it.</p>
<p>So this form had a bunch of input fields, including check boxes. Whenever a lead request was submitted, we captured the data and prepared to save it into the database. It looked something like this:</p>
<pre><span class="hl-variable">$formSubmission</span> = <span class="hl-keyword">new</span> <span class="hl-type">FormSubmission</span>();

<span class="hl-variable">$formSubmission</span>-&gt;<span class="hl-property">name</span> = <span class="hl-variable">$form</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">name</span>');
<span class="hl-variable">$formSubmission</span>-&gt;<span class="hl-property">email</span> = <span class="hl-variable">$form</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">email</span>');
<span class="hl-comment">// …</span>

<span class="hl-variable">$entityManager</span>-&gt;<span class="hl-property">save</span>(<span class="hl-variable">$formSubmission</span>);
</pre>
<p>The bug, simple as it may sound, was a simple typo:</p>
<pre>$formSubmission-&gt;more_feedback_required = 
    $form-&gt;get('more_feedback_requierd');
</pre>
<p>Can you spot the <code>requierd</code> when calling <code>$form-&gt;get()</code>?</p>
<p>As it turns out, our form library — written by us for our in-house framework — wouldn't give an error when you're trying to get an unknown property, it simply returns <code>null</code>.</p>
<p>The database however expected a boolean value, and thus an error was thrown.</p>
<p>This isn't that big of a problem, albeit not that no one knew of it. The second part of the bug was the empty page: this one was served directly from nginx whenever an error would occur — we didn't want visitors to be bothered by error pages. It turned out that one of my colleagues had set it up a few months ago, and I didn't know of it. When a lead saw the empty page, they probably thought the form was submitted just fine, they didn't know there should be a "thank you" page instead.</p>
<p>Next, we never saw the error happening during testing, because the erroneous code only ran in specific cases, and no one thought about testing those. The form itself was unit tested, but not all edge cases were.</p>
<p>Finally we weren't automatically notified of errors in production, which meant no one knew about it until the client complained. At the time, the company didn't do any error monitoring on production, that might seem completely bonkers, but yes: it happens.</p>
<hr />
<p>I deployed a fix for the typo (which I wrote to begin with), I told my manager about the problem and that it's fixed. In turn he asks me how many people were affected by it. I tell him to check up on this. I go back to my desk and check when this bug was committed and deployed to production. A month ago.</p>
<p>I remember a sickening feeling starting to rise from this point on.</p>
<p>I check the log files, and scan for the error. I'm stunned for a few moments. It's not just a few errors. It's hundreds. Hundreds of leads that we lost over the past month. I started to shake a little. After a few minutes I reported back to my manager. I again explained the bug itself, why it had been undetected for a month, and finally gave him the hard numbers. There was nothing we could do: those leads were lost.</p>
<h2 id="the-aftermath"><a href="#the-aftermath" class="heading-anchor">#</a> The aftermath</h2>
<p>The following days were probably the most stressful in my career up until today. I'm thankful that no one blamed me directly: we all agreed that this was the team's responsibility and not my own. Still I was the one who wrote the typo, I was the one tasked with testing and deploying the changes to the form a month earlier.</p>
<p>I can honestly tell you that I had a hard time dealing with this feeling of guilt, even though my manager and colleagues were understanding.</p>
<p>I could of course point fingers to others: we shouldn't have used our own framework with its quirky form validation; devops should have installed some kind of error tracking; the empty error page should have been more clear. I admit I thought all these thoughts the days after, I even felt anger towards some of my colleagues for a while. But I learned that anger didn't get me anywhere. I better spent my time looking at how <em>I</em> could learn from all of this, instead of pointing fingers at others.</p>
<p>So, after a few weeks of processing, what felt to me like a trauma; I found the courage to look at what I could have done differently. What I could learn from this.</p>
<p>First of: ask my colleagues for reviews. It doesn't matter if I'm a junior or senior; a fresh look on my code is always valuable. I've learned that most people are busy themselves and won't help you unless you specifically ask them to. To this day I often ask my colleagues to review a PR. Even when I might have more years of experience, I highly value my colleagues' input. No matter how long I've been doing this, I still make mistakes, and I shouldn't be too proud to admit that.</p>
<p>Next: I don't use tools I don't know or trust. This <a href="/blog/dont-write-your-own-framework">wasn't the first time</a> I stumbled upon the limitations of a custom, in-house framework. I've learned that it's better to use tools that are supported by a large open source community. It wasn't my decision which framework to use on that particular project, but it was a requirement for my next job: I only want to use well-known, community supported frameworks when it comes to client projects in production.</p>
<p>Third: I should test better myself, I shouldn't assume that a checkbox is just a checkbox. I should be skeptical towards every line of code I write. This incident is one of the reasons I came to love strongly typed systems more and more. I don't want a language that tries to be smart and juggle types here and there. I want a language that crashes hard when something happens that shouldn't happen, the stronger the type system, the better.</p>
<p>Next: I tend to code more defensively. I constantly ask myself: are null values possible? Anything unexpected that could happen? I prefer to add an extra check rather than assuming it'll work fine.</p>
<p>And finally: I learned not to blame others first. I think it's a trait of many junior developers to think the problem happened somewhere else. It was an important and humbling lesson to learn, and I tend to be more cautious when blaming an external party these days.</p>
<hr />
<p>It's strange writing this blogpost. I was a young developer when this happened to me, and it's something that I think has had a lasting impact on my programming career. I also think we don't talk about this often enough. I lay awake at night thinking about how angry the client would be, what the impact would be on the company I worked for. Even though I realise most of my feelings were exaggerated, they still were there. I wasn't able to just turn them off. I felt fear and shame, and had little people to talk about it.</p>
<p>We write about our success stories, but what about our mistakes? What about the impact of these kinds of experiences on our mental health? Many of us in the software industry are introverts, or feel like we can't talk about our deepest emotions.</p>
<p>Let's keep an eye out for each other instead.</p>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2020-11-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Announcing Blogs for Devs ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/blogs-for-devs"/>

                <id>https://www.stitcher.io/blog/blogs-for-devs</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="sidenote blogs-for-devs index">
    <h2>Index</h2>

    <ul>
        <li><a href="/blogs-for-devs/01-intro">01 – Intro</a></li>
        <li><a href="/blogs-for-devs/02-content-is-king">02 – Content is King</a></li>
        <li><a href="/blogs-for-devs/03-the-stack">03 – The Stack</a></li>
        <li><a href="/blogs-for-devs/04-your-audience">04 – Your Audience</a></li>
        <li><a href="/blogs-for-devs/05-interaction">05 – Interaction</a></li>
        <li><a href="/blogs-for-devs/06-stay-in-touch">06 – Stay in Touch</a></li>
        <li><a href="/blogs-for-devs/07-be-searchable">07 – Be Searchable</a></li>
        <li><a href="/blogs-for-devs/08-analytics">08 – Analytics</a></li>
        <li><a href="/blogs-for-devs/09-social-channels">09 – Social Channels</a></li>
        <li><a href="/blogs-for-devs/10-monetize">10 – Monetize</a></li>
    </ul>
</div>
</p>
<p>When I started my blog in 2017 I never imagined it'd be as successful as now. I never seriously invested in SEO or did any aggressive marketing campaigns, and yet here we are: closing in to 2 million sessions, and the end is no where near.</p>
<p><a target="_blank" href="/resources/img/blogs-for-devs/01-01.png"><img src="/resources/img/blogs-for-devs/01-01.png" srcset="/resources/img/blogs-for-devs/01-01-670x399.png 670w, /resources/img/blogs-for-devs/01-01-1500x894.png 1500w, /resources/img/blogs-for-devs/01-01-1341x799.png 1341w, /resources/img/blogs-for-devs/01-01-1161x691.png 1161w, /resources/img/blogs-for-devs/01-01-948x565.png 948w" sizes="" alt="Cumulated amount of sessions per week"><em class="small center">Cumulated amount of sessions per week</em></img></a></p>
<p>I did of course do something to put my content out there. Over the years I found ways to reach people who might be interested in reading what I wrote. But still, there wasn't much effort involved: I'd share a link from time to time; I'd listen to feedback (a thick skin is an asset if you're writing a blog, people on the internet <em>love</em> to tell you you're wrong); I tried to improve my writing.</p>
<p>I guess the reason it feels like little effort is because it's something I actually really enjoy doing. Even though I'm making some money with my blog now, I still consider it a hobby project. There has never been any pressure to write when I didn't want to. I ignored most of the "blogging best practices" because they asked way too much of my free time. I managed to find my own way of doing things, and it turns out it works.</p>
<p>Throughout this series I'll share everything I learned during my blogging journey with you: how to start, how to grow, how to analyse, how to engage with your audience, how to make money by writing on the internet. I'm a developer so some topics will be technical, but even if you've got no programming experience, you'll be able to learn lots — I'll keep things as simple as possible.</p>
<p>So, are you a blogger? Has it been your long-time dream of starting a blog? I'm happy to share my experience with you!</p>
<p><div class="sidenote blogs-for-devs">
    <h2>Do you enjoy this series?</h2>

    <p>I write about much more technical and blog related topics, if you want to you can subscribe to stay up to date about my content.</p>

    <form
            action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0"
            method="post"
            class="newsletter-form"
            target="_blank"
    >
        <input type="hidden" name="tags" value="blogs-for-devs">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Keep me posted!</button>
    </form>

    <em class="small center">You can also subscribe via <a href="/blogs-for-devs/rss" target="_blank" rel="noopener noreferrer">RSS</a>.</em>
    <br>
</div>
</p>
 ]]></summary>

                <updated>2020-11-28T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Upgrade to PHP 8 with Homebrew on Mac ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-8-upgrade-mac"/>

                <id>https://www.stitcher.io/blog/php-8-upgrade-mac</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="upgrading-with-homebrew"><a href="#upgrading-with-homebrew" class="heading-anchor">#</a> Upgrading with Homebrew</h2>
<p>Start by making sure brew is up-to-date:</p>
<pre>brew update
</pre>
<p>Next, upgrade PHP. You can either use the built-in php recipe, use tap <code>shivammathur/homebrew-php</code>. I'd recommend the second approach, since it allows you to easily install several PHP versions and switch between them.</p>
<h3 id="normal-upgrade"><a href="#normal-upgrade" class="heading-anchor">#</a> Normal upgrade</h3>
<pre>brew upgrade php
</pre>
<h3 id="upgrade-with-shivammathur/homebrew-php"><a href="#upgrade-with-shivammathur/homebrew-php" class="heading-anchor">#</a> Upgrade with <code>shivammathur/homebrew-php</code></h3>
<pre>brew tap shivammathur/php
brew install shivammathur/php/php@8.0
</pre>
<p>To switch between versions, use the following command:</p>
<pre>brew link --overwrite --force php@8.0
</pre>
<p>You can read more in the <a target="_blank" href="https://github.com/shivammathur/homebrew-php">repository</a>.</p>
<h3 id="next-steps"><a href="#next-steps" class="heading-anchor">#</a> Next steps</h3>
<p>Check the current version by running <code>php -v</code>:</p>
<pre>php -v
</pre>
<p>Restart Nginx or Apache:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<p>And make sure that your local web server also uses PHP 8 by visiting this script:</p>
<pre># index.php, accessible to your web server

<span class="hl-property">phpinfo</span>();
</pre>
<p><em class="small center">The version should show <code>8.0.x</code>.</em></p>
<p>Note: if you're using Laravel Valet, please keep on reading,
you need some extra steps in order for the web server to properly work.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="valet"><a href="#valet" class="heading-anchor">#</a> Valet</h2>
<p>If you're using Laravel Valet, you should do the following steps to upgrade it:</p>
<pre>composer global update
</pre>
<p>You can use <code>valet use</code> to switch between PHP versions:</p>
<pre>valet use php@8.0
valet use php@7.4
</pre>
<p>Note that if you're using an older Valet version (prior to v2.13.18), when switching from PHP 8 to PHP 7.4 there was a bug that didn't properly update the changes. This was fixed in Valet 2.13.18 so that it now automatically removes the valet socket after having run <code>valet use php@7.4</code>. If you need to do this manually, you can run:</p>
<pre>cd ~/.config/valet
rm valet.sock
valet restart
</pre>
<h2 id="extensions"><a href="#extensions" class="heading-anchor">#</a> Extensions</h2>
<p>PHP extensions are installed using pecl. I personally use Imagick, Redis and Xdebug. They can be installed like so:</p>
<pre>pecl install imagick
pecl install redis
pecl install xdebug
</pre>
<p>You can run <code>pecl list</code> to see which extensions are installed:</p>
<pre>pecl list

# Installed packages, channel pecl.php.net:
# =========================================
# Package Version State
# imagick 3.4.4   stable
# redis   5.1.1   stable
# xdebug  2.8.0   stable
</pre>
<p>You can search for other extensions using <code>pecl search</code>:</p>
<pre>pecl search pdf

# Retrieving data...0%
# ..
# Matched packages, channel pecl.php.net:
# =======================================
# Package Stable/(Latest) Local
# pdflib  4.1.2 (stable)        Creating PDF on the fly with the PDFlib library
</pre>
<p>Make sure to restart your web server after installing new packages:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<p>If you're using Laravel Valet, you should restart it as well.</p>
<pre>valet restart
</pre>
<p>Make sure all extensions are correctly installed and loaded by checking both your PHP webserver and CLI installs:</p>
<pre>php -i | grep redis
</pre>
<pre><span class="hl-property">var_dump</span>(<span class="hl-property">extension_loaded</span>('<span class="hl-value">redis</span>'));
</pre>
<p>If extensions aren't properly loaded, there are two easy fixes.</p>
<p>First, make sure the extensions are added in the correct ini file. You can run <code>php --ini</code> to know which file is loaded:</p>
<pre>Configuration File (php.ini) Path: /usr/local/etc/php/7.4
Loaded Configuration File:         /usr/local/etc/php/7.4/php.ini
Scan for additional .ini files in: /usr/local/etc/php/7.4/conf.d
Additional .ini files parsed:      /usr/local/etc/php/7.4/conf.d/ext-opcache.ini,
/usr/local/etc/php/7.4/conf.d/php-memory-limits.ini
</pre>
<p>Now check the ini file:</p>
<pre>extension=&quot;redis.so&quot;
extension=&quot;imagick.so&quot;
zend_extension=&quot;xdebug.so&quot;
</pre>
<p>Note that if you're testing installed extensions via the CLI, you don't need to restart nginx, apache or Valet when making changes to ini settings.</p>
<p>The second thing you can do, if you're updating from an older PHP version which also used pecl to install extension; is to reinstall every extension individually.</p>
<pre>pecl uninstall imagick
pecl install imagick
</pre>
<h2 id="last-step"><a href="#last-step" class="heading-anchor">#</a> Last step</h2>
<p>Finally you should test and upgrade your projects for <a href="/blog/new-in-php-8">PHP 8 compatibility</a>.</p>
 ]]></summary>

                <updated>2020-11-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What&#039;s new in PHP 8 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-in-php-8"/>

                <id>https://www.stitcher.io/blog/new-in-php-8</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8 was released on November 26, 2020. You can <a target="_blank" href="https://www.php.net/releases/8.0/en.php">download it here</a>. It's a new major version, which means that there are some breaking changes, as well as lots of new features and performance improvements.</p>
<p>Because of the breaking changes, there's a higher chance you'll need to make some changes in your code to get it running on PHP 8. If you've kept up to date with the latest releases though, the upgrade shouldn't be too hard, since most breaking changes were deprecated before in the 7.* versions. And don't worry, all these deprecations are listed in this post.</p>
<p>Besides breaking changes, PHP 8 also brings a nice set of new features such as <a href="#jit-rfc">the JIT compiler</a>, <a href="#union-types-rfc">union types</a>, <a href="#attributes-rfc">attributes</a>, and more.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="new-features"><a href="#new-features" class="heading-anchor">#</a> New features</h2>
<p>Let's start with all new features, it's quite a list!</p>
<hr />
<h3 id="union-types-rfc"><a href="#union-types-rfc" class="heading-anchor">#</a> Union types <small><a target="_blank" href="https://wiki.php.net/rfc/union_types_v2">RFC</a></small></h3>
<p>Given the dynamically typed nature of PHP, there are lots of cases where union types can be useful. Union types are a collection of two or more types which indicate that either one of those can be used.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-type">Foo|Bar</span> $input</span>): <span class="hl-type">int|float</span>;
</pre>
<p>Note that <code>void</code> can never be part of a union type, since it indicates "no return value at all". Furthermore, <code>nullable</code> unions can be written using <code>|null</code>, or by using the existing <code>?</code> notation:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-type">Foo|null</span> $foo</span>): <span class="hl-type">void</span>;

<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>(<span class="hl-injection"><span class="hl-type">?Bar</span> $bar</span>): <span class="hl-type">void</span>;
</pre>
<h3 id="jit-rfc"><a href="#jit-rfc" class="heading-anchor">#</a> JIT <small><a target="_blank" href="https://wiki.php.net/rfc/jit">RFC</a></small></h3>
<p>The JIT — just in time — compiler promises significant performance improvements, albeit not always within the context of web requests. I've done my <a href="/blog/jit-in-real-life-web-applications">own benchmarks</a> on real-life web applications, and it seems like the JIT doesn't make that much of a difference, if any, on those kinds of PHP projects.</p>
<p>If you want to know more about what the JIT can do for PHP, you can read another post I wrote about it <a href="/blog/php-jit">here</a>.</p>
<hr />
<h3 id="the-nullsafe-operator-rfc"><a href="#the-nullsafe-operator-rfc" class="heading-anchor">#</a> The nullsafe operator <small><a target="_blank" href="https://wiki.php.net/rfc/nullsafe_operator">RFC</a></small></h3>
<p>If you're familiar with the <a href="/blog/shorthand-comparisons-in-php#null-coalescing-operator">null coalescing operator</a> you're already familiar with its shortcomings: it doesn't work on method calls. Instead you need intermediate checks, or rely on <code>optional</code> helpers provided by some frameworks:</p>
<pre><span class="hl-variable">$startDate</span> = <span class="hl-variable">$booking</span>-&gt;<span class="hl-property">getStartDate</span>();

<span class="hl-variable">$dateAsString</span> = <span class="hl-variable">$startDate</span> <span class="hl-operator">?</span> <span class="hl-variable">$startDate</span>-&gt;<span class="hl-property">asDateTimeString</span>() : <span class="hl-keyword">null</span>;
</pre>
<p>With the addition of the nullsafe operator, we can now have null coalescing-like behaviour on methods!</p>
<pre><span class="hl-variable">$dateAsString</span> = <span class="hl-variable">$booking</span>-&gt;<span class="hl-property">getStartDate</span>()?-&gt;<span class="hl-property">asDateTimeString</span>();
</pre>
<p>You can read all about the nullsafe operator <a href="/blog/php-8-nullsafe-operator">here</a>.</p>
<hr />
<h3 id="named-arguments-rfc"><a href="#named-arguments-rfc" class="heading-anchor">#</a> Named arguments <small><a target="_blank" href="https://wiki.php.net/rfc/named_params">RFC</a></small></h3>
<p><a href="/blog/php-8-named-arguments">Named arguments</a> allow you to pass in values to a function, by specifying the value name, so that you don't have to take their order into consideration, and you can also skip optional parameters!</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-type">string</span> $a, <span class="hl-type">string</span> $b, <span class="hl-type">?string</span> $c = <span class="hl-keyword">null</span>, <span class="hl-type">?string</span> $d = <span class="hl-keyword">null</span></span>) 
{ <span class="hl-comment">/* … */</span> }

<span class="hl-property">foo</span>(
    <span class="hl-property">b</span>: '<span class="hl-value">value b</span>', 
    <span class="hl-property">a</span>: '<span class="hl-value">value a</span>', 
    <span class="hl-property">d</span>: '<span class="hl-value">value d</span>',
);
</pre>
<p>You can read about them in-depth <a href="/blog/php-8-named-arguments">in this post</a>.</p>
<hr />
<h3 id="attributes-rfc"><a href="#attributes-rfc" class="heading-anchor">#</a> Attributes <small><a target="_blank" href="https://wiki.php.net/rfc/attributes_v2">RFC</a></small></h3>
<p><a href="/blog/attributes-in-php-8">Attributes</a>, commonly known as <em>annotations</em> in other languages, offers a way to add meta data to classes, without having to parse docblocks.</p>
<p>As for a quick look, here's an example of what attributes look like, from the RFC:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">App\Attributes\ExampleAttribute</span>;

<span class="hl-attribute">#[<span class="hl-type">ExampleAttribute</span>]</span>
<span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-attribute">#[<span class="hl-type">ExampleAttribute</span>]</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">FOO</span> = '<span class="hl-value">foo</span>';
 
    <span class="hl-attribute">#[<span class="hl-type">ExampleAttribute</span>]</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$x</span>;
 
    <span class="hl-attribute">#[<span class="hl-type">ExampleAttribute</span>]</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-attribute">#[ExampleAttribute]</span> $bar</span>) { }
}
</pre>
<pre><span class="hl-attribute">#[<span class="hl-type">Attribute</span>]</span>
<span class="hl-keyword">class</span> <span class="hl-type">ExampleAttribute</span>
{
    <span class="hl-keyword">public</span> <span class="hl-property">$value</span>;
 
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">$value</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> = <span class="hl-variable">$value</span>;
    }
}
</pre>
<p>Note that this base <code>Attribute</code> used to be called <code>PhpAttribute</code> in the original RFC, but was changed with <a target="_blank" href="https://wiki.php.net/rfc/attribute_amendments">another RFC</a> afterwards. If you want to take a deep dive in how attributes work, and how you can build your own; you can read about <a href="/blog/attributes-in-php-8">attributes in depth</a> on this blog.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h3 id="match-expression-rfc"><a href="#match-expression-rfc" class="heading-anchor">#</a> Match expression <small><a target="_blank" href="https://wiki.php.net/rfc/match_expression_v2">RFC</a></small></h3>
<p>You could call it the big brother of the <code>switch</code> expression: <code>match</code> can return values, doesn't require <code>break</code> statements, can combine conditions, uses strict type comparisons and doesn't do any type coercion.</p>
<p>It looks like this:</p>
<pre><span class="hl-variable">$result</span> = <span class="hl-keyword">match</span>(<span class="hl-variable">$input</span>) {
    0 =&gt; &quot;<span class="hl-value">hello</span>&quot;,
    '<span class="hl-value">1</span>', '<span class="hl-value">2</span>', '<span class="hl-value">3</span>' =&gt; &quot;<span class="hl-value">world</span>&quot;,
};
</pre>
<p>You can read up on the match expression in detail, <a href="/blog/php-8-match-or-switch">over here</a>.</p>
<hr />
<h3 id="constructor-property-promotion-rfc"><a href="#constructor-property-promotion-rfc" class="heading-anchor">#</a> Constructor property promotion <small><a target="_blank" href="https://wiki.php.net/rfc/constructor_promotion">RFC</a></small></h3>
<p>This RFC adds syntactic sugar to create value objects or data transfer objects. Instead of specifying class properties and a constructor for them, PHP can now combine them into one.</p>
<p>Instead of doing this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Money</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-type">Currency</span> <span class="hl-property">$currency</span>;
 
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$amount</span>;
 
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">Currency</span> $currency,
        <span class="hl-type">int</span> $amount,
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">currency</span> = <span class="hl-variable">$currency</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">amount</span> = <span class="hl-variable">$amount</span>;
    }
}
</pre>
<p>You can now do this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Money</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">Currency</span> <span class="hl-property">$currency</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$amount</span>,
    </span>) {}
}
</pre>
<p>There's a lot more to tell about property promotion, you can read about them <a href="/blog/constructor-promotion-in-php-8">in this dedicated post</a>.</p>
<hr />
<h3 id="new-static-return-type-rfc"><a href="#new-static-return-type-rfc" class="heading-anchor">#</a> New <code>static</code> return type <small><a target="_blank" href="https://wiki.php.net/rfc/static_return_type">RFC</a></small></h3>
<p>While it was already possible to return <code>self</code>, <code>static</code> wasn't a valid return type until PHP 8. Given PHP's dynamically typed nature, it's a feature that will be useful to many developers.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">test</span>(): <span class="hl-keyword">static</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">static</span>();
    }
}
</pre>
<hr />
<h3 id="new-mixed-type-rfc"><a href="#new-mixed-type-rfc" class="heading-anchor">#</a> New <code>mixed</code> type <small><a target="_blank" href="https://wiki.php.net/rfc/mixed_type_v2">RFC</a></small></h3>
<p>Some might call it a necessary evil: the <code>mixed</code> type causes many to have mixed feelings. There's a very good argument to make for it though: a missing type can mean lots of things in PHP:</p>
<ul>
<li>A function returns nothing or null</li>
<li>We're expecting one of several types</li>
<li>We're expecting a type that can't be type hinted in PHP</li>
</ul>
<p>Because of the reasons above, it's a good thing the <code>mixed</code> type is added. <code>mixed</code> itself means one of these types:</p>
<ul>
<li>
<code>array</code>
</li>
<li>
<code>bool</code>
</li>
<li>
<code>callable</code>
</li>
<li>
<code>int</code>
</li>
<li>
<code>float</code>
</li>
<li>
<code>null</code>
</li>
<li>
<code>object</code>
</li>
<li>
<code>resource</code>
</li>
<li>
<code>string</code>
</li>
</ul>
<p>Note that <code>mixed</code> can also be used as a parameter or property type, not just as a return type.</p>
<p>Also note that since <code>mixed</code> already includes <code>null</code>, it's not allowed to make it nullable. The following will trigger an error:</p>
<pre><span class="hl-comment">// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.</span>
<span class="hl-keyword">function</span> <span class="hl-property">bar</span>(): <span class="hl-type">?mixed</span> {}
</pre>
<hr />
<h3 id="throw-expression-rfc"><a href="#throw-expression-rfc" class="heading-anchor">#</a> Throw expression <small><a target="_blank" href="https://wiki.php.net/rfc/throw_expression">RFC</a></small></h3>
<p>This RFC changes <code>throw</code> from being a statement to being an expression, which makes it possible to throw exception in many new places:</p>
<pre><span class="hl-variable">$triggerError</span> = <span class="hl-keyword">fn</span> () =&gt; <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">MyError</span>();

<span class="hl-variable">$foo</span> = <span class="hl-variable">$bar</span>['<span class="hl-value">offset</span>'] ?? <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">OffsetDoesNotExist</span>('<span class="hl-value">offset</span>');
</pre>
<hr />
<h3 id="inheritance-with-private-methods-rfc"><a href="#inheritance-with-private-methods-rfc" class="heading-anchor">#</a> Inheritance with private methods <small><a target="_blank" href="https://wiki.php.net/rfc/inheritance_private_methods">RFC</a></small></h3>
<p>Previously, PHP used to apply the same inheritance checks on public, protected and private methods. In other words: private methods should follow the same method signature rules as protected and public methods. This doesn't make sense, since private methods won't be accessible by child classes.</p>
<p>This RFC changed that behaviour, so that these inheritance checks are not performed on private methods anymore. Furthermore, the use of <code>final private function</code> also didn't make sense, so doing so will now trigger a warning:</p>
<pre>Warning: Private methods cannot be final as they are never overridden by other classes
</pre>
<hr />
<h3 id="weak-maps-rfc"><a href="#weak-maps-rfc" class="heading-anchor">#</a> Weak maps <small><a target="_blank" href="https://wiki.php.net/rfc/weak_maps">RFC</a></small></h3>
<p>Built upon the <a target="_blank" href="https://wiki.php.net/rfc/weakrefs">weakrefs RFC</a> that was added in PHP 7.4, a <code>WeakMap</code> implementation is added in PHP 8. <code>WeakMap</code> holds references to objects, which don't prevent those objects from being garbage collected.</p>
<p>Take the example of ORMs, they often implement caches which hold references to entity classes to improve the performance of relations between entities. These entity objects can not be garbage collected, as long as this cache has a reference to them, even if the cache is the <em>only</em> thing referencing them.</p>
<p>If this caching layer uses weak references and maps instead, PHP will garbage collect these objects when nothing else references them anymore. Especially in the case of ORMs, which can manage several hundreds, if not thousands of entities within a request; weak maps can offer a better, more resource friendly way of dealing with these objects.</p>
<p>Here's what weak maps look like, an example from the RFC:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span> 
{
    <span class="hl-keyword">private</span> <span class="hl-type">WeakMap</span> <span class="hl-property">$cache</span>;
 
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getSomethingWithCaching</span>(<span class="hl-injection"><span class="hl-type">object</span> $obj</span>): <span class="hl-type">object</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">cache</span>[<span class="hl-variable">$obj</span>]
           ??= <span class="hl-variable">$this</span>-&gt;<span class="hl-property">computeSomethingExpensive</span>(<span class="hl-variable">$obj</span>);
    }
}
</pre>
<hr />
<h3 id="allowing-::class-on-objects-rfc"><a href="#allowing-::class-on-objects-rfc" class="heading-anchor">#</a> Allowing <code>::class</code> on objects <small><a target="_blank" href="https://wiki.php.net/rfc/class_name_literal_on_object">RFC</a></small></h3>
<p>A small, yet useful, new feature: it's now possible to use <code>::class</code> on objects, instead of having to use <code>get_class()</code> on them. It works the same way as <code>get_class()</code>.</p>
<pre>$foo = new Foo();

var_dump($foo::class);
</pre>
<hr />
<h3 id="non-capturing-catches-rfc"><a href="#non-capturing-catches-rfc" class="heading-anchor">#</a> Non-capturing catches <small><a target="_blank" href="https://wiki.php.net/rfc/non-capturing_catches">RFC</a></small></h3>
<p>Whenever you wanted to catch an exception before PHP 8, you had to store it in a variable, regardless whether you used that variable or not. With non-capturing catches, you can omit the variable, so instead of this:</p>
<pre><span class="hl-keyword">try</span> {
    <span class="hl-comment">// Something goes wrong</span>
} <span class="hl-keyword">catch</span> (MySpecialException <span class="hl-variable">$exception</span>) {
    <span class="hl-type">Log</span>::<span class="hl-property">error</span>(&quot;<span class="hl-value">Something went wrong</span>&quot;);
}
</pre>
<p>You can now do this:</p>
<pre><span class="hl-keyword">try</span> {
    <span class="hl-comment">// Something goes wrong</span>
} <span class="hl-keyword">catch</span> (<span class="hl-type">MySpecialException</span>) {
    <span class="hl-type">Log</span>::<span class="hl-property">error</span>(&quot;<span class="hl-value">Something went wrong</span>&quot;);
}
</pre>
<p>Note that it's required to always specify the type, you're not allowed to have an empty <code>catch</code>. If you want to catch all exceptions and errors, you can use <code>Throwable</code> as the catching type.</p>
<hr />
<h3 id="trailing-comma-in-parameter-lists-rfc"><a href="#trailing-comma-in-parameter-lists-rfc" class="heading-anchor">#</a> Trailing comma in parameter lists <small><a target="_blank" href="https://wiki.php.net/rfc/trailing_comma_in_parameter_list">RFC</a></small></h3>
<p>Already possible when calling a function, trailing comma support was still lacking in parameter lists. It's now allowed in PHP 8, meaning you can do the following:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $parameterA,
    <span class="hl-type">int</span> $parameterB,
    <span class="hl-type">Foo</span> $objectfoo,
</span>) {
    <span class="hl-comment">// …</span>
}
</pre>
<p>As a sidenote: trailing commas are also supported in the <code>use</code> list of closures, this was an oversight and now added via a <a href="https://wiki.php.net/rfc/trailing_comma_in_closure_use_list">separate RFC</a>.</p>
<hr />
<h3 id="create-datetime-objects-from-interface"><a href="#create-datetime-objects-from-interface" class="heading-anchor">#</a> Create <code>DateTime</code> objects from interface</h3>
<p>You can already create a <code>DateTime</code> object from a <code>DateTimeImmutable</code> object using <code>DateTime::createFromImmutable($immutableDateTime)</code>, but the other way around was tricky. By adding <code>DateTime::createFromInterface()</code> and <code>DatetimeImmutable::createFromInterface()</code> there's now a generalised way to convert <code>DateTime</code> and <code>DateTimeImmutable</code> objects to each other.</p>
<pre><span class="hl-type">DateTime</span>::<span class="hl-property">createFromInterface</span>(DateTimeInterface <span class="hl-variable">$other</span>);

<span class="hl-type">DateTimeImmutable</span>::<span class="hl-property">createFromInterface</span>(DateTimeInterface <span class="hl-variable">$other</span>);
</pre>
<hr />
<h3 id="new-stringable-interface-rfc"><a href="#new-stringable-interface-rfc" class="heading-anchor">#</a> New <code>Stringable</code> interface <small><a target="_blank" href="https://wiki.php.net/rfc/stringable">RFC</a></small></h3>
<p>The <code>Stringable</code> interface can be used to type hint anything that implements <code>__toString()</code>. Whenever a class implements <code>__toString()</code>, it automatically implements the interface behind the scenes and there's no need to manually implement it.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__toString</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> '<span class="hl-value">foo</span>';
    }
}

<span class="hl-keyword">function</span> <span class="hl-property">bar</span>(<span class="hl-injection"><span class="hl-type">string|Stringable</span> $stringable</span>) { <span class="hl-comment">/* … */</span> }

<span class="hl-property">bar</span>(<span class="hl-keyword">new</span> <span class="hl-type">Foo</span>());
<span class="hl-property">bar</span>('<span class="hl-value">abc</span>');
</pre>
<hr />
<h3 id="new-str_contains()-function-rfc"><a href="#new-str_contains()-function-rfc" class="heading-anchor">#</a> New <code>str_contains()</code> function <small><a target="_blank" href="https://wiki.php.net/rfc/str_contains">RFC</a></small></h3>
<p>Some might say it's long overdue, but we finally don't have to rely on <code>strpos()</code> anymore to know whether a string contains another string.</p>
<p>Instead of doing this:</p>
<pre><span class="hl-keyword">if</span> (<span class="hl-property">strpos</span>('<span class="hl-value">string with lots of words</span>', '<span class="hl-value">words</span>') !== <span class="hl-keyword">false</span>) { <span class="hl-comment">/* … */</span> }
</pre>
<p>You can now do this</p>
<pre><span class="hl-keyword">if</span> (<span class="hl-property">str_contains</span>('<span class="hl-value">string with lots of words</span>', '<span class="hl-value">words</span>')) { <span class="hl-comment">/* … */</span> }
</pre>
<hr />
<h3 id="new-str_starts_with()-and-str_ends_with()-functions-rfc"><a href="#new-str_starts_with()-and-str_ends_with()-functions-rfc" class="heading-anchor">#</a> New <code>str_starts_with()</code> and <code>str_ends_with()</code> functions <small><a target="_blank" href="https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions">RFC</a></small></h3>
<p>Two other ones long overdue, these two functions are now added in the core.</p>
<pre><span class="hl-property">str_starts_with</span>('<span class="hl-value">haystack</span>', '<span class="hl-value">hay</span>'); <span class="hl-comment">// true</span>
<span class="hl-property">str_ends_with</span>('<span class="hl-value">haystack</span>', '<span class="hl-value">stack</span>'); <span class="hl-comment">// true</span>
</pre>
<hr />
<h3 id="new-fdiv()-function-pr"><a href="#new-fdiv()-function-pr" class="heading-anchor">#</a> New <code>fdiv()</code> function <small><a target="_blank" href="https://github.com/php/php-src/pull/4769">PR</a></small></h3>
<p>The new <code>fdiv()</code> function does something similar as the <code>fmod()</code> and <code>intdiv()</code> functions, which allows for division by 0. Instead of errors you'll get <code>INF</code>, <code>-INF</code> or <code>NAN</code>, depending on the case.</p>
<hr />
<h3 id="new-get_debug_type()-function-rfc"><a href="#new-get_debug_type()-function-rfc" class="heading-anchor">#</a> New <code>get_debug_type()</code> function <small><a target="_blank" href="https://wiki.php.net/rfc/get_debug_type">RFC</a></small></h3>
<p><code>get_debug_type()</code> returns the type of a variable. Sounds like something <code>gettype()</code> would do? <code>get_debug_type()</code> returns more useful output for arrays, strings, anonymous classes and objects.</p>
<p>For example, calling <code>gettype()</code> on a class <code>\Foo\Bar</code> would return <code>object</code>. Using <code>get_debug_type()</code> will return the class name.</p>
<p>A full list of differences between <code>get_debug_type()</code> and <code>gettype()</code> can be found in the RFC.</p>
<hr />
<h3 id="new-get_resource_id()-function-pr"><a href="#new-get_resource_id()-function-pr" class="heading-anchor">#</a> New <code>get_resource_id()</code> function <small><a target="_blank" href="https://github.com/php/php-src/pull/5427">PR</a></small></h3>
<p>Resources are special variables in PHP, referring to external resources. One example is a MySQL connection, another one a file handle.</p>
<p>Each one of those resources gets assigned an ID, though previously the only way to know that id was to cast the resource to <code>int</code>:</p>
<pre><span class="hl-variable">$resourceId</span> = (int) <span class="hl-variable">$resource</span>;
</pre>
<p>PHP 8 adds the <code>get_resource_id()</code> functions, making this operation more obvious and type-safe:</p>
<pre><span class="hl-variable">$resourceId</span> = <span class="hl-property">get_resource_id</span>(<span class="hl-variable">$resource</span>);
</pre>
<hr />
<h3 id="abstract-methods-in-traits-improvements-rfc"><a href="#abstract-methods-in-traits-improvements-rfc" class="heading-anchor">#</a> Abstract methods in traits improvements <small><a target="_blank" href="https://wiki.php.net/rfc/abstract_trait_method_validation">RFC</a></small></h3>
<p>Traits can specify abstract methods which must be implemented by the classes using them. There's a caveat though: before PHP 8 the signature of these method implementations weren't validated. The following was valid:</p>
<pre><span class="hl-keyword">trait</span> <span class="hl-type">Test</span> {
    <span class="hl-keyword">abstract</span> <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">test</span>(<span class="hl-injection"><span class="hl-type">int</span> $input</span>): <span class="hl-type">int</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">UsesTrait</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">Test</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">test</span>(<span class="hl-injection">$input</span>)
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$input</span>;
    }
}
</pre>
<p>PHP 8 will perform proper method signature validation when using a trait and implementing its abstract methods. This means you'll need to write this instead:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">UsesTrait</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">Test</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">test</span>(<span class="hl-injection"><span class="hl-type">int</span> $input</span>): <span class="hl-type">int</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$input</span>;
    }
}
</pre>
<hr />
<h3 id="object-implementation-of-token_get_all()-rfc"><a href="#object-implementation-of-token_get_all()-rfc" class="heading-anchor">#</a> Object implementation of <code>token_get_all()</code> <small><a target="_blank" href="https://wiki.php.net/rfc/token_as_object">RFC</a></small></h3>
<p>The <code>token_get_all()</code> function returns an array of values. This RFC adds a <code>PhpToken</code> class with a <code>PhpToken::tokenize()</code> method. This implementation works with objects instead of plain values. It consumes less memory and is easier to read.</p>
<hr />
<h3 id="variable-syntax-tweaks-rfc"><a href="#variable-syntax-tweaks-rfc" class="heading-anchor">#</a> Variable syntax tweaks <small><a target="_blank" href="https://wiki.php.net/rfc/variable_syntax_tweaks">RFC</a></small></h3>
<p>From the RFC: "the Uniform Variable Syntax RFC resolved a number of inconsistencies in PHP's variable syntax. This RFC intends to address a small handful of cases that were overlooked."</p>
<hr />
<h3 id="type-annotations-for-internal-functions-externals"><a href="#type-annotations-for-internal-functions-externals" class="heading-anchor">#</a> Type annotations for internal functions <small><a target="_blank" href="https://externals.io/message/106522">EXTERNALS</a></small></h3>
<p>Lots of people <a target="_blank" href="https://github.com/php/php-src/pulls?q=is%3Apr+label%3AStubs+is%3Aclosed">pitched in</a> to add proper type annotations to all internal functions. This was a long standing issue, and finally solvable with all the changes made to PHP in previous versions. This means that internal functions and methods will have complete type information in reflection.</p>
<hr />
<h3 id="ext-json-always-available-rfc"><a href="#ext-json-always-available-rfc" class="heading-anchor">#</a> <code>ext-json</code> always available <small><a target="_blank" href="https://wiki.php.net/rfc/always_enable_json">RFC</a></small></h3>
<p>Previously it was possible to compile PHP without the JSON extension enabled, this is not possible anymore. Since JSON is so widely used, it's best developers can always rely on it being there, instead of having to ensure the extension exist first.</p>
<h2 id="breaking-changes"><a href="#breaking-changes" class="heading-anchor">#</a> Breaking changes</h2>
<p>As mentioned before: this is a major update and thus there will be breaking changes. The best thing to do is take a look at the full list of breaking changes over at the <a target="_blank" href="https://github.com/php/php-src/blob/PHP-8.0/UPGRADING#L20">UPGRADING</a> document.</p>
<p>Many of these breaking changes have been deprecated in previous 7.* versions though, so if you've been staying up-to-date over the years, it shouldn't be all that hard to upgrade to PHP 8.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h3 id="consistent-type-errors-rfc"><a href="#consistent-type-errors-rfc" class="heading-anchor">#</a> Consistent type errors <small><a target="_blank" href="https://wiki.php.net/rfc/consistent_type_errors">RFC</a></small></h3>
<p>User-defined functions in PHP will already throw <code>TypeError</code>, but internal functions did not, they rather emitted warnings and returned <code>null</code>. As of PHP 8 the behaviour of internal functions have been made consistent.</p>
<hr />
<h3 id="reclassified-engine-warnings-rfc"><a href="#reclassified-engine-warnings-rfc" class="heading-anchor">#</a> Reclassified engine warnings <small><a target="_blank" href="https://wiki.php.net/rfc/engine_warnings">RFC</a></small></h3>
<p>Lots of errors that previously only triggered warnings or notices, have been converted to proper errors. The following warnings were changed.</p>
<ul>
<li>Undefined variable: warning instead of notice</li>
<li>Undefined array index: warning instead of notice</li>
<li>Division by zero: <code>DivisionByZeroError</code> exception instead of warning</li>
<li>Attempt to increment/decrement property '%s' of non-object: <code>Error</code> exception instead of warning</li>
<li>Attempt to modify property '%s' of non-object: <code>Error</code> exception instead of warning</li>
<li>Attempt to assign property '%s' of non-object: <code>Error</code> exception instead of warning</li>
<li>Creating default object from empty value: <code>Error</code> exception instead of warning</li>
<li>Trying to get property '%s' of non-object: warning instead of notice</li>
<li>Undefined property: %s::$%s: warning instead of notice</li>
<li>Cannot add element to the array as the next element is already occupied: <code>Error</code> exception instead of warning</li>
<li>Cannot unset offset in a non-array variable: <code>Error</code> exception instead of warning</li>
<li>Cannot use a scalar value as an array: <code>Error</code> exception instead of warning</li>
<li>Only arrays and <code>Traversables</code> can be unpacked: <code>TypeError</code> exception instead of warning</li>
<li>Invalid argument supplied for foreach(): <code>TypeError</code> exception instead of warning</li>
<li>Illegal offset type: <code>TypeError</code> exception instead of warning</li>
<li>Illegal offset type in isset or empty: <code>TypeError</code> exception instead of warning</li>
<li>Illegal offset type in unset: <code>TypeError</code> exception instead of warning</li>
<li>Array to string conversion: warning instead of notice</li>
<li>Resource ID#%d used as offset, casting to integer (%d): warning instead of notice</li>
<li>String offset cast occurred: warning instead of notice</li>
<li>Uninitialized string offset: %d: warning instead of notice</li>
<li>Cannot assign an empty string to a string offset: <code>Error</code> exception instead of warning</li>
<li>Supplied resource is not a valid stream resource: <code>TypeError</code> exception instead of warning</li>
</ul>
<hr />
<h3 id="the-@-operator-no-longer-silences-fatal-errors"><a href="#the-@-operator-no-longer-silences-fatal-errors" class="heading-anchor">#</a> The @ operator no longer silences fatal errors</h3>
<p>It's possible that this change might reveal errors that again were hidden before PHP 8. Make sure to set <code>display_errors=Off</code> on your production servers!</p>
<hr />
<h3 id="default-error-reporting-level"><a href="#default-error-reporting-level" class="heading-anchor">#</a> Default error reporting level</h3>
<p>It's now <code>E_ALL</code> instead of everything but <code>E_NOTICE</code> and <code>E_DEPRECATED</code>. This means that many errors might pop up which were previously silently ignored, though probably already existent before PHP 8.</p>
<hr />
<h3 id="default-pdo-error-mode-rfc"><a href="#default-pdo-error-mode-rfc" class="heading-anchor">#</a> Default PDO error mode <small><a target="_blank" href="https://wiki.php.net/rfc/pdo_default_errmode">RFC</a></small></h3>
<p>From the RFC: <em>The current default error mode for PDO is silent. This means that when an SQL error occurs, no errors or warnings may be emitted and no exceptions thrown unless the developer implements their own explicit error handling.</em></p>
<p>This RFC changes the default error will change to <code>PDO::ERRMODE_EXCEPTION</code> in PHP 8.</p>
<hr />
<h3 id="concatenation-precedence-rfc"><a href="#concatenation-precedence-rfc" class="heading-anchor">#</a> Concatenation precedence <small><a target="_blank" href="https://wiki.php.net/rfc/concatenation_precedence">RFC</a></small></h3>
<p>While already deprecated in PHP 7.4, this change is now taken into effect. If you'd write something like this:</p>
<pre><span class="hl-keyword">echo</span> &quot;<span class="hl-value">sum: </span>&quot; . <span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>;
</pre>
<p>PHP would previously interpret it like this:</p>
<pre><span class="hl-keyword">echo</span> (&quot;<span class="hl-value">sum: </span>&quot; . <span class="hl-variable">$a</span>) + <span class="hl-variable">$b</span>;
</pre>
<p>PHP 8 will make it so that it's interpreted like this:</p>
<pre><span class="hl-keyword">echo</span> &quot;<span class="hl-value">sum: </span>&quot; . (<span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>);
</pre>
<hr />
<h3 id="stricter-type-checks-for-arithmetic-and-bitwise-operators-rfc"><a href="#stricter-type-checks-for-arithmetic-and-bitwise-operators-rfc" class="heading-anchor">#</a> Stricter type checks for arithmetic and bitwise operators <small><a target="_blank" href="https://wiki.php.net/rfc/arithmetic_operator_type_checks">RFC</a></small></h3>
<p><hljs type>Before PHP 8, it was possible to apply arithmetic or bitwise operators on arrays, resources or objects. This isn't possible anymore, and will throw a <code>TypeError</code>:</hljs></p>
<pre>[] % [42];
<span class="hl-variable">$object</span> + 4;
</pre>
<hr />
<h3 id="namespaced-names-being-a-single-token-rfc"><a href="#namespaced-names-being-a-single-token-rfc" class="heading-anchor">#</a> Namespaced names being a single token <small><a target="_blank" href="https://wiki.php.net/rfc/namespaced_names_as_token">RFC</a></small></h3>
<p>PHP used to interpret each part of a namespace (separated by a backslash <code>\</code>) as a sequence of tokens. This RFC changed that behaviour, meaning reserved names can now be used in namespaces.</p>
<hr />
<h3 id="saner-numeric-strings-rfc"><a href="#saner-numeric-strings-rfc" class="heading-anchor">#</a> Saner numeric strings <small><a target="_blank" href="https://wiki.php.net/rfc/saner-numeric-strings">RFC</a></small></h3>
<p>PHP's type system tries to do a lot of smart things when it encounters numbers in strings. This RFC makes that behaviour more consistent and clear.</p>
<hr />
<h3 id="saner-string-to-number-comparisons-rfc"><a href="#saner-string-to-number-comparisons-rfc" class="heading-anchor">#</a> Saner string to number comparisons <small><a target="_blank" href="https://wiki.php.net/rfc/string_to_number_comparison">RFC</a></small></h3>
<p>This RFC fixes the very strange case in PHP where <code>0 == &quot;foo&quot;</code> results in <code>true</code>. There are some other edge cases like that one, and this RFC fixes them.</p>
<hr />
<h3 id="reflection-changes"><a href="#reflection-changes" class="heading-anchor">#</a> Reflection changes</h3>
<p>A few reflection methods have been deprecated:</p>
<ul>
<li>
<code>ReflectionFunction::isDisabled()</code>
</li>
<li>
<code>ReflectionParameter::getClass()</code>
</li>
<li>
<code>ReflectionParameter::isCallable()</code>
</li>
</ul>
<p>You should now use <code>ReflectionType</code> to get information about a parameter's type:</p>
<pre><span class="hl-variable">$reflectionParameter</span>-&gt;<span class="hl-property">getType</span>()-&gt;<span class="hl-property">allowsNull</span>();
</pre>
<p>If the type is a single type, <code>ReflectionParameter::getType()</code> returns an instance of <code>ReflectionNamedType</code>, which you can get its name from and whether it's built-in:</p>
<pre><span class="hl-variable">$reflectionParameter</span>-&gt;<span class="hl-property">getType</span>()-&gt;<span class="hl-property">getName</span>();
<span class="hl-variable">$reflectionParameter</span>-&gt;<span class="hl-property">getType</span>()-&gt;<span class="hl-property">isBuiltin</span>();
</pre>
<p>If the type is a union type however, you'll get an instance of <code>ReflectionUnionType</code>, which can give you an array of <code>ReflectionNamedType</code> like so:</p>
<pre><span class="hl-variable">$reflectionParameter</span>-&gt;<span class="hl-property">getType</span>()-&gt;<span class="hl-property">getTypes</span>();
</pre>
<p>Checking whether a type is a union or not can be done with an <code>instanceof</code> check:</p>
<pre><span class="hl-keyword">if</span> (<span class="hl-variable">$reflectionParameter</span>-&gt;<span class="hl-property">getType</span>() <span class="hl-keyword">instanceof</span> <span class="hl-type">ReflectionNamedType</span>) { 
    <span class="hl-comment">// It's a single type</span>
}

<span class="hl-keyword">if</span> (<span class="hl-variable">$reflectionParameter</span>-&gt;<span class="hl-property">getType</span>() <span class="hl-keyword">instanceof</span> <span class="hl-type">ReflectionUnionType</span>) {
    <span class="hl-comment">// It's a union type</span>
}
</pre>
<p>Next up, three method signatures of reflection classes have been changed:</p>
<pre><span class="hl-type">ReflectionClass</span>::<span class="hl-property">newInstance</span>(<span class="hl-variable">$args</span>);
<span class="hl-type">ReflectionFunction</span>::<span class="hl-property">invoke</span>(<span class="hl-variable">$args</span>);
<span class="hl-type">ReflectionMethod</span>::<span class="hl-property">invoke</span>(<span class="hl-variable">$object</span>, <span class="hl-variable">$args</span>);
</pre>
<p>Have now become:</p>
<pre><span class="hl-type">ReflectionClass</span>::<span class="hl-property">newInstance</span>(...<span class="hl-variable">$args</span>);
<span class="hl-type">ReflectionFunction</span>::<span class="hl-property">invoke</span>(...<span class="hl-variable">$args</span>);
<span class="hl-type">ReflectionMethod</span>::<span class="hl-property">invoke</span>(<span class="hl-variable">$object</span>, ...<span class="hl-variable">$args</span>);
</pre>
<p>The upgrading guide specifies that if you extend these classes, and still want to support both PHP 7 and PHP 8, the following signatures are allowed:</p>
<pre><span class="hl-type">ReflectionClass</span>::<span class="hl-property">newInstance</span>(<span class="hl-variable">$arg</span> = <span class="hl-keyword">null</span>, ...<span class="hl-variable">$args</span>);
<span class="hl-type">ReflectionFunction</span>::<span class="hl-property">invoke</span>(<span class="hl-variable">$arg</span> = <span class="hl-keyword">null</span>, ...<span class="hl-variable">$args</span>);
<span class="hl-type">ReflectionMethod</span>::<span class="hl-property">invoke</span>(<span class="hl-variable">$object</span>, <span class="hl-variable">$arg</span> = <span class="hl-keyword">null</span>, ...<span class="hl-variable">$args</span>);
</pre>
<hr />
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<hr />
<h3 id="stable-sorting-rfc"><a href="#stable-sorting-rfc" class="heading-anchor">#</a> Stable sorting <small><a target="_blank" href="https://wiki.php.net/rfc/stable_sorting">RFC</a></small></h3>
<p>Before PHP 8, sorting algorithms were unstable. This means that the order of equal elements wasn't guaranteed. PHP 8 changes the behaviour of all sorting functions to stable sorting.</p>
<hr />
<h3 id="fatal-error-for-incompatible-method-signatures-rfc"><a href="#fatal-error-for-incompatible-method-signatures-rfc" class="heading-anchor">#</a> Fatal error for incompatible method signatures <small><a target="_blank" href="https://wiki.php.net/rfc/lsp_errors">RFC</a></small></h3>
<p>From the RFC: <em>Inheritance errors due to incompatible method signatures currently either throw a fatal error or a warning depending on the cause of the error and the inheritance hierarchy.</em></p>
<hr />
<h3 id="other-deprecations-and-changes"><a href="#other-deprecations-and-changes" class="heading-anchor">#</a> Other deprecations and changes</h3>
<p>During the PHP 7.* development, several deprecations were added that are now finalised in PHP 8.</p>
<ul>
<li>Deprecations in <a target="_blank" href="https://wiki.php.net/rfc/deprecations_php_7_2">PHP 7.2</a>
</li>
<li>Deprecations in <a target="_blank" href="https://wiki.php.net/rfc/deprecations_php_7_3">PHP 7.3</a>
</li>
<li>Deprecations in <a target="_blank" href="https://wiki.php.net/rfc/deprecations_php_7_4">PHP 7.4</a>
</li>
<li>Locale-independent <a target="_blank" href="https://wiki.php.net/rfc/locale_independent_float_to_string">float to string cast</a>
</li>
</ul>
<hr />
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-11-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: the null safe operator ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-8-nullsafe-operator"/>

                <id>https://www.stitcher.io/blog/php-8-nullsafe-operator</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>If you've used the <a href="/blog/shorthand-comparisons-in-php#null-coalescing-operator">null coalescing operator</a> in the past, you probably also noticed its shortcomings: null coalescing doesn't work on method calls. Instead you need intermediate checks, or rely on <code>optional</code> helpers provided by some frameworks:</p>
<pre><span class="hl-variable">$startDate</span> = <span class="hl-variable">$booking</span>-&gt;<span class="hl-property">getStartDate</span>();

<span class="hl-variable">$dateAsString</span> = <span class="hl-variable">$startDate</span> <span class="hl-operator">?</span> <span class="hl-variable">$startDate</span>-&gt;<span class="hl-property">asDateTimeString</span>() : <span class="hl-keyword">null</span>;
</pre>
<p>The nullsafe operator provides functionality similar to null coalescing, but also supports method calls. Instead of writing this:</p>
<pre><span class="hl-variable">$country</span> =  <span class="hl-keyword">null</span>;
 
<span class="hl-keyword">if</span> (<span class="hl-variable">$session</span> !== <span class="hl-keyword">null</span>) {
    <span class="hl-variable">$user</span> = <span class="hl-variable">$session</span>-&gt;<span class="hl-property">user</span>;
 
    <span class="hl-keyword">if</span> (<span class="hl-variable">$user</span> !== <span class="hl-keyword">null</span>) {
        <span class="hl-variable">$address</span> = <span class="hl-variable">$user</span>-&gt;<span class="hl-property">getAddress</span>();
 
        <span class="hl-keyword">if</span> (<span class="hl-variable">$address</span> !== <span class="hl-keyword">null</span>) {
            <span class="hl-variable">$country</span> = <span class="hl-variable">$address</span>-&gt;<span class="hl-property">country</span>;
        }
    }
}
</pre>
<p>PHP 8 allows you to write this:</p>
<pre><span class="hl-variable">$country</span> = <span class="hl-variable">$session</span>?-&gt;<span class="hl-property">user</span>?-&gt;<span class="hl-property">getAddress</span>()?-&gt;<span class="hl-property">country</span>;
</pre>
<p>Let's take a look at what this new operator can and cannot do!</p>
<h2 id="nullsafe-operator-in-depth"><a href="#nullsafe-operator-in-depth" class="heading-anchor">#</a> Nullsafe operator in depth</h2>
<p>Let's start by addressing the most important question: what exactly is the difference between the null coalescing operator and the nullsafe operator?</p>
<p>Let's take a look at this example:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Order</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">?Invoice</span> <span class="hl-property">$invoice</span> = <span class="hl-keyword">null</span>;
}

<span class="hl-variable">$order</span> = <span class="hl-keyword">new</span> <span class="hl-type">Order</span>();
</pre>
<p>Here we have an <code>Order</code> object which has an optional relation to an <code>Invoice</code> object. Now imagine we'd want to get the invoice's number (if the invoice isn't null). You could do this both with the null coalescing operator and the nullsafe operator:</p>
<pre><span class="hl-property">var_dump</span>(<span class="hl-variable">$order</span>-&gt;<span class="hl-property">invoice</span>?-&gt;<span class="hl-property">number</span>);
<span class="hl-property">var_dump</span>(<span class="hl-variable">$order</span>-&gt;<span class="hl-property">invoice</span>-&gt;<span class="hl-property">number</span> ?? <span class="hl-keyword">null</span>);
</pre>
<p>So what's the difference? While you could use both operators to achieve the same result in this example, they also have specific edge cases only one of them can handle. For example, you can use the null coalescing operator in combination with array keys, while the nullsafe operator can't handle them:</p>
<pre><span class="hl-variable">$array</span> = [];

<span class="hl-property">var_dump</span>(<span class="hl-variable">$array</span>['<span class="hl-value">key</span>']-&gt;<span class="hl-property">foo</span> ?? <span class="hl-keyword">null</span>);
</pre>
<pre>var_dump($array['key']?-&gt;foo);

Warning: Undefined array key &quot;key&quot;
</pre>
<p>The nullsafe operator, on the other hand, can work with method calls, while the null coalescing operator can't. Imagine an <code>Invoice</code> object like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Invoice</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getDate</span>(): <span class="hl-type">?DateTime</span> { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-comment">// …</span>
}

<span class="hl-variable">$invoice</span> = <span class="hl-keyword">new</span> <span class="hl-type">Invoice</span>();
</pre>
<p>You could use the nullsafe operator to call <code>format</code> on the invoice's date, even when it's <code>null</code>:</p>
<pre><span class="hl-property">var_dump</span>(<span class="hl-variable">$invoice</span>-&gt;<span class="hl-property">getDate</span>()?-&gt;<span class="hl-property">format</span>('<span class="hl-value">Y-m-d</span>'));

<span class="hl-comment">// null</span>
</pre>
<p>While the null coalescing operator would crash:</p>
<pre><span class="hl-property">var_dump</span>(<span class="hl-variable">$invoice</span>-&gt;<span class="hl-property">getDate</span>()-&gt;<span class="hl-property">format</span>('<span class="hl-value">Y-m-d</span>') ?? <span class="hl-keyword">null</span>);

<span class="hl-type">Fatal</span> <span class="hl-property">error</span>: Uncaught <span class="hl-property">Error</span>: Call to a member <span class="hl-keyword">function</span> <span class="hl-property">format</span>() on <span class="hl-keyword">null</span>
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h3 id="short-circuiting"><a href="#short-circuiting" class="heading-anchor">#</a> Short circuiting</h3>
<p>Sometimes you could use either the null coalescing or nullsafe operator, and other times you'd need to use a specific one. The difference is that the nullsafe operator uses a form of "short circuiting": writing <code>?-&gt;</code> will cause PHP to look at whats on the lefthand side of this operator, if it's <code>null</code> then the righthand side will simply be discarded. The null coalescing operator is actually an <code>isset</code> call in disguise on its lefthand operand, which doesn't support short circuiting.</p>
<p>Short circuiting also means that when writing something like this:</p>
<pre><span class="hl-variable">$foo</span>?-&gt;<span class="hl-property">bar</span>(<span class="hl-property">expensive_function</span>(<span class="hl-injection">)</span><span class="hl-injection">)</span>;
</pre>
<p><code>expensive_function</code> would only be executed if <code>$foo</code> is actually not <code>null</code>.</p>
<h3 id="nested-nullsafe-operators"><a href="#nested-nullsafe-operators" class="heading-anchor">#</a> Nested nullsafe operators</h3>
<p>It's possible to nest several nullsafe operator calls like so:</p>
<pre><span class="hl-variable">$foo</span>?-&gt;<span class="hl-property">bar</span>?-&gt;<span class="hl-property">baz</span>()?-&gt;<span class="hl-property">boo</span>?-&gt;<span class="hl-property">baa</span>();
</pre>
<h3 id="only-for-reading-data"><a href="#only-for-reading-data" class="heading-anchor">#</a> Only for reading data</h3>
<p>You cannot use the nullsafe operator to write data to objects:</p>
<pre><span class="hl-variable">$offer</span>?-&gt;<span class="hl-property">invoice</span>?-&gt;<span class="hl-property">date</span> = <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>(); 
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>The nullsafe operator is definitely a missing piece of the puzzle finally added in PHP. Given its dynamic nature, it feels good to have a smooth way of dealing with <code>null</code>. The difference and overlap between the nullsafe operator and null coalescing operator feels a bit confusing at first, but I'm sure we'll get used to it.</p>
 ]]></summary>

                <updated>2020-11-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: How to setup the JIT ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-8-jit-setup"/>

                <id>https://www.stitcher.io/blog/php-8-jit-setup</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><a href="/blog/new-in-php-8">PHP 8</a> adds a <a href="/blog/php-jit">JIT</a> compiler to PHP's core which has the potential to speed up performance dramatically. There are some sidenotes to be made about the actual impact on real-life web applications, which is why I ran <a href="/blog/jit-in-real-life-web-applications">some benchmarks</a> on how the JIT performs (I've listed all relevant references in the footnotes as well).</p>
<p>I wanted to dedicate a blog post on how to setup the JIT as well, since there's a few things to talk about.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Honestly, setting up the JIT is one of the most confusing ways of configuring a PHP extension I've ever seen. Luckily there are some configuration shorthands available so that it's more easy to set up. Still it's good to know about the JIT config in depth, so here goes.</p>
<p>First of all, the JIT will only work if opcache is enabled, this is the default for most PHP installations, but you should make sure that <code>opcache.enable</code> is set to 1 in your<code>php.ini</code> file. Enabling the JIT itself is done by specifying <code>opcache.jit_buffer_size</code> in <code>php.ini</code>.</p>
<p>Note that if you're running PHP via the commandline, you can also pass these options via the <code>-d</code> flag, instead of adding them to <code>php.ini</code>:</p>
<pre>php -dopcache.enable=1 -dopcache.jit_buffer_size=100M
</pre>
<p>If this directive is excluded, the default value is set to 0, and the JIT won't run. If you're testing the JIT in a CLI script, you'll need to use <code>opcache.enable_cli</code> instead to enable opcache:</p>
<pre>php -dopcache.enable_cli=1 -dopcache.jit_buffer_size=100M
</pre>
<p>The difference between <code>opcache.enable</code> and <code>opcache.enable_cli</code> is that the first one should be used if you're running, for example, the built-in PHP server. If you're actually running a CLI script, you'll need <code>opcache.enable_cli</code>.</p>
<p>Before continuing, let's ensure the JIT actually works, create a PHP script that's accessible via the browser or the CLI (depending on where you're testing the JIT), and look at the output of <code>opcache_get_status()</code>:</p>
<pre><span class="hl-property">var_dump</span>(<span class="hl-property">opcache_get_status</span>()['<span class="hl-value">jit</span>']);
</pre>
<p>The output should be something like this:</p>
<pre>array:7 [
  &quot;<span class="hl-value">enabled</span>&quot; =&gt; <span class="hl-keyword">true</span>
  &quot;<span class="hl-value">on</span>&quot; =&gt; <span class="hl-keyword">true</span>
  &quot;<span class="hl-value">kind</span>&quot; =&gt; 5
  &quot;<span class="hl-value">opt_level</span>&quot; =&gt; 4
  &quot;<span class="hl-value">opt_flags</span>&quot; =&gt; 6
  &quot;<span class="hl-value">buffer_size</span>&quot; =&gt; 4080
  &quot;<span class="hl-value">buffer_free</span>&quot; =&gt; 0
]
</pre>
<p>If <code>enabled</code> and <code>on</code> are true, you're good to go!</p>
<p>Next, there's several ways to configure the JIT (and this is where we'll get into the configuration mess). You can configure when the JIT should run, how much it should try to optimise, etc. All of these options are configured using a single (!) config entry: <code>opcache.jit</code>. It could look something like this:</p>
<pre>opcache.enable=1 
opcache.jit=1255
</pre>
<p>Now, what does that number mean? The <a target="_blank" href="https://wiki.php.net/rfc/jit">RFC</a> lists the meaning of each of them. Mind you: this is not a bit mask, each number simply represents another configuration option. The RFC lists the following options:</p>
<h4 id="o-—-optimization-level"><a href="#o-—-optimization-level" class="heading-anchor">#</a> O — Optimization level</h4>
<table>
    <tr><td>0</td> <td>don't JIT</td></tr>
    <tr><td>1</td> <td>minimal JIT (call standard VM handlers)</td></tr>
    <tr><td>2</td> <td>selective VM handler inlining</td></tr>
    <tr><td>3</td> <td>optimized JIT based on static type inference of individual function</td></tr>
    <tr><td>4</td> <td>optimized JIT based on static type inference and call tree</td></tr>
    <tr><td>5</td> <td>optimized JIT based on static type inference and inner procedure analyses</td></tr>
</table>
<h4 id="t-—-jit-trigger"><a href="#t-—-jit-trigger" class="heading-anchor">#</a> T — JIT trigger</h4>
<table>
    <tr><td>0</td> <td>JIT all functions on first script load</td></tr>
    <tr><td>1</td> <td>JIT function on first execution</td></tr>
    <tr><td>2</td> <td>Profile on first request and compile hot functions on second request</td></tr>
    <tr><td>3</td> <td>Profile on the fly and compile hot functions</td></tr>
    <tr><td>4</td> <td>Compile functions with @jit tag in doc-comments</td></tr>
    <tr><td>5</td> <td>Tracing JIT</td></tr>
</table>
<h4 id="r-—-register-allocation"><a href="#r-—-register-allocation" class="heading-anchor">#</a> R — register allocation</h4>
<table>
    <tr><td>0</td> <td>don't perform register allocation</td></tr>
    <tr><td>1</td> <td>use local liner-scan register allocator</td></tr>
    <tr><td>2</td> <td>use global liner-scan register allocator</td></tr>
</table>
<h4 id="c-—-cpu-specific-optimization-flags"><a href="#c-—-cpu-specific-optimization-flags" class="heading-anchor">#</a> C — CPU specific optimization flags</h4>
<table>
    <tr><td>0</td> <td>none</td></tr>
    <tr><td>1</td> <td>enable AVX instruction generation</td></tr>
</table>
<p>One <em>small</em> gotcha: the RFC lists these options in reverse order, so the first digit represents the <code>C</code> value, the second the <code>R</code>, and so on. Why there simply weren't four configuration entries added is beyond my comprehension, probably to make configuring the JIT faster… right?</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>Anyways, internals propose <code>1255</code> as the best default, it will do maximum jitting, use the tracing JIT, use a global liner-scan register allocator — whatever that might be — and enables AVX instruction generation.</p>
<p>So your ini settings (or <code>-d</code> flags) should have these values:</p>
<pre>opcache.enable=1 
opcache.jit_buffer_size=100M
opcache.jit=1255
</pre>
<p>Keep in mind that <code>opcache.jit</code> is optional by the way. The JIT will use a default value if that property is omitted.</p>
<p>Which default, you ask? That would be <code>opcache.jit=tracing</code>.</p>
<p>Hang on, that's not the strange bitmask-like structure we saw earlier? That's right: after the original RFC passed, internals recognised that the bitmask-like options weren't all that user-friendly, so they added two aliases which are translated to the bitmask under the hood. There's <code>opcache.jit=tracing</code> and <code>opcache.jit=function</code>.</p>
<p>The difference between the two is that the function JIT will only try to optimise code within the scope of a single function, while the tracing JIT can look at the whole stack trace to identify and optimise hot code. Internals recommends to use the tracing JIT, because it'll probably almost always give the best results. You can read about those results in the <a href="/blog/jit-in-real-life-web-applications">benchmarks</a> I've done.</p>
<p>So the only option you actually need to set to enable the JIT with its optimal configuration is <code>opcache.jit_buffer_size</code>, but if you want to be explicit, listing <code>opcache.jit</code> wouldn't be such a bad idea:</p>
<pre>opcache.enable=1 
opcache.jit_buffer_size=100M
opcache.jit=tracing
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
 ]]></summary>

                <updated>2020-10-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Front Line PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/front-line-php"/>

                <id>https://www.stitcher.io/blog/front-line-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been blogging for three years and a half: I've written about PHP, the web, programming in general, and here and there something completely off topic. When I started this project I never imagined it would be received so well by so many. But here we are: thousands of people visit my blog every month, with a total of over 2 million pageviews in the span of three years. I realise those numbers are dwarfed by many other websites, still to me it feels like a great achievement.</p>
<p>The last year and a half I've been focussing on more specific topics: the "<a href="/blog/new-in-php-8">What's new in PHP</a>" series has been really popular, and the <a href="/blog/attributes-in-php-8">in</a>-<a href="/blog/jit-in-real-life-web-applications">depth</a> <a href="/blog/constructor-promotion-in-php-8">PHP</a> <a href="/blog/php-8-named-arguments">feature</a> <a href="/blog/php-8-match-or-switch">posts</a> have sparked many great discussions and conversations. With those PHP-related topics, I always envisioned them to be part of a greater whole and not separate posts. I've been trying to tell the story of modern PHP for a while now, and I'm trying to make it as focussed and of the highest quality as possible.</p>
<p>So that's why I'm introducing the next chapter, or better said: a bundle of chapters. I'm working on a book that teaches you modern PHP, its best practices and the community surrounding it — it's called "<a target="_blank" href="https://front-line-php.com/">Front Line PHP</a>". Some parts of it will be based on what I've written throughout the years on this blog, but large parts will be brand new. I'll cover the language itself, patterns and principles, frameworks, and most importantly: the mindset of a professional web developer. I'm really looking forward being able to share everything I want as a unified whole.</p>
<p>Like my <a target="_blank" href="https://laravel-beyond-crud.com/">previous book</a>, I'm working together with <a target="_blank" href="https://spatie.be/">Spatie</a> — the company I work at — to ensure it'll be the greatest product possible. You can expect Front Line PHP to launch in December 2020, right around the time PHP 8 arrives. It'll be accompanied by a <em>free</em> video series, teaching you all about PHP 8 in practice.</p>
<p>I'm really looking forward to sharing all of this with you, so make sure you <a target="_blank" href="https://front-line-php.com/">subscribe to the dedicated newsletter</a> to receive all relevant updates. If you want to know a little more, head over to the <a target="_blank" href="https://front-line-php.com/">Front Line PHP website</a>, which will receive regular updates over the coming weeks. I hope you're as excited as I am. If you have any questions or remarks, you're of course free to reach out to me via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
<p>Thanks!</p>
 ]]></summary>

                <updated>2020-10-05T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What a good PR looks like ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/what-a-good-pr-looks-like"/>

                <id>https://www.stitcher.io/blog/what-a-good-pr-looks-like</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's <a target="_blank" href="https://hacktoberfest.digitalocean.com/">Hacktoberfest</a>, your chance to contribute to open source and win a t-shirt while at it! Being an open source maintainer <a target="_blank" href="https://github.com/brendt">myself</a>, I find it a great initiative, but it comes with responsibility as well. Many people try to be smart and send low-effort, borderline-spam PRs, essentially <a target="_blank" href="https://joel.net/how-one-guy-ruined-hacktoberfest2020-drama">ruining</a> a maintainer's day.</p>
<p>So to help maintainers <em>and</em> contributors in creating quality open source, here are a few tips!</p>
<h2 id="start-by-looking-at-existing-issues-and-prs"><a href="#start-by-looking-at-existing-issues-and-prs" class="heading-anchor">#</a> Start by looking at existing issues and PRs</h2>
<p>Even though most PRs are well meant, it's important to first look around the repo for existing issues or PRs addressing the same problem. Someone else might already be working on a similar PR or there might be issues preventing the PR from being made. If you want to help out, start by participating in the discussions already happening, instead of working on your own.</p>
<h2 id="discuss-first"><a href="#discuss-first" class="heading-anchor">#</a> Discuss first</h2>
<p>If nothing has been said about your feature, it might be a good idea to discuss it first, instead of going ahead and potentially changing hundreds of lines of code. I'll be the one who has to maintain your PR for the foreseeable future, so it's best to first discuss it with me! I can probably give you some tips about the code base, as well as tell you about our expectations regarding implementation.</p>
<p>You can choose to open an issue first, or submit a draft PR with a minimal implementation, a proof of concept. I actually really like those draft PRs: it visualises what you want to change, but also indicates that you realise there's more work to do.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="follow-the-style-guide"><a href="#follow-the-style-guide" class="heading-anchor">#</a> Follow the style guide</h2>
<p>Speaking of expectations, check whether the repository you're committing to has any code style guide or linter set up. <strong>Follow those rules</strong>. Don't submit a PR that deliberately uses other styling rules. You're submitting code to another codebase, and that style guide has to be followed.</p>
<p>A note to maintainers: you can help out here by using GitHub actions to automatically run your linters on PRs.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="document-your-pr"><a href="#document-your-pr" class="heading-anchor">#</a> Document your PR</h2>
<p>I'm going to review your code, so I'd like it to be as clear as possible. This starts by writing <a href="/blog/a-programmers-cognitive-load">clean code</a>: using proper variable names, maybe even add a doc block here and there; but it's equally important to explain your thought process as well. You could use review comments to clarify specific parts of the code, or you could add some general comments in the PR.</p>
<h2 id="clean-commits"><a href="#clean-commits" class="heading-anchor">#</a> Clean commits</h2>
<p>Please try to avoid <code>&quot;wip&quot;</code> commit messages, please? You don't have to write a book for every commit, and I realise that you might not want to think about them while in the zone; but something like <code>&quot;Refactor XX to YY&quot;</code> is already infinitely better than <code>&quot;wip&quot;</code>. If you really want a good commit message, try to have your commits only do one thing, and try to explain <em>why</em> this commit is necessary.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="only-relevant-changes"><a href="#only-relevant-changes" class="heading-anchor">#</a> Only relevant changes</h2>
<p>Only submit changes that are relevant within the scope of the PR. You might be tempted to fix another thing or two while at it — and you're allowed to — but keep those changes in a separate PR.</p>
<p>You can always base a new branch on your PR branch if necessary, and mention in the second PR that it depends on the first one to be merged. I'm happy to merge them for you, in the right order.</p>
<h2 id="be-patient"><a href="#be-patient" class="heading-anchor">#</a> Be patient</h2>
<p>It might take a while for maintainers to merge your PR. I even confess to have lost track of a few PRs over the past years. A friendly "bump" after a few days is always appreciated, but it still might take some time. Remember that most OSS maintainers are doing this on a voluntary basis, so don't be mad when a PR takes a little longer to merge.</p>
<h2 id="be-friendly"><a href="#be-friendly" class="heading-anchor">#</a> Be friendly</h2>
<p>This goes for both maintainers and contributors: don't be a jerk. Sometimes a PR gets declined, sometimes a maintainers looses their patience. Stop and breath, realise it's not the end of the world and move on. Be friendly and respectful.</p>
<h2 id="don't-wait-too-long-to-tag"><a href="#don't-wait-too-long-to-tag" class="heading-anchor">#</a> Don't wait too long to tag</h2>
<p>This one is for the maintainers: one of the most frustrating things is a PR getting accepted, and than having to wait another month for a release to be tagged. You shouldn't be afraid of high version numbers, that's what semver is for. Tag the release as soon as possible, and please don't wait another week!</p>
<hr />
<p>Do you have any more tips? Let them know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">email</a>. Here's already another good read by my Colleague Sebastian, on how to write <a target="_blank" href="https://sebastiandedeyne.com/a-good-issue/">a good issue</a>.</p>
 ]]></summary>

                <updated>2020-10-02T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Which colour scheme is better? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/why-light-themes-are-better-according-to-science"/>

                <id>https://www.stitcher.io/blog/why-light-themes-are-better-according-to-science</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>As a programmer I think I should always critically look at my own toolset and try to optimise it, regardless of my own subjective preference. It's by doing so that I've come to the conclusion that light colour schemes are better than dark ones, and today I want to share those thoughts with you.</p>
<p>Before looking at theory, grab a pair of sunglasses if you have any laying around. With both eyes open, cover only <em>one</em> eye with one of the sunglass glasses. Make it so you're looking through your sunglasses with one eye, and use the other one like you're used to.</p>
<p>With that setup in place, have fun watching this video in 3D!</p>
<iframe width="560" height="400" src="https://www.youtube.com/embed/IZdWlXjhMo4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>Did you see the 3D effect? It might not work as well for parts of the video and some of you might not notice the 3D effect at all. That's fine, this post isn't about 3D, but it <em>is</em> about the reason why you can watch that video in 3D with only a pair of sunglasses: the Pulfrich effect.</p>
<div class="sidenote">    
<h2>The Pulfrich effect</h2>
<p>The Pulfrich effect is a psychophysical percept wherein lateral motion of an object in the field of view is interpreted by the visual cortex as having a depth component, due to a relative difference in signal timings between the two eyes.</p>
</div>
<p>All sources are listed in the footnotes by the way, you'll find them at the end of this post.</p>
<p>To clarify, the 3D effect in the video is indeed your brain tricking you; it thinks there's depth in a moving flat image because there's a slight difference in timing between your left and right eye.
What's interesting though is what causes that timing difference. Can you guess? It's because you covered one eye with sunglasses, making the image darker. It turns out that dark images take longer to process than light ones.</p>
<div class="sidenote">  
<p>The Pulfrich effect […] yields about a 15 ms delay for a factor of ten difference in average retinal illuminance</p>
</div>
<p>By only covering one eye with sunglasses, you add a few milliseconds of delay to that one. The exact delay will depend on the brightness of the screen and the darkness of the sunglasses, which might explain why some people see the 3D effect better than others. The timing difference between your eyes causes your brain to interpret that image as having depth, hence 3D.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Now on to programming. If you're using a dark colour scheme, you're deliberately adding extra delay, so says the Pulfrich effect.
Sure the difference seems negligible, it's only a few milliseconds. Actually, it's a few milliseconds <em>every</em> time you "rescan" your screen; that's between 10 or 50 times a second, depending on what research you want to believe.
Still you probably won't notice any real-time difference, but over time this adds up, and the extra effort needed by your eyes can become to feel exhausting.</p>
<p>Besides the Pulfrich effect, there are other reasons that make light colour schemes superior. First of there's what human eyes are used to, what they are built for. Most of us are awake during the day and asleep at night. The human eye is better adapted to interpreting light scenes with dark points of focus, instead of the other way around.</p>
<p>On the other hand there's the case of astigmatism, which is caused by an imperfection of your corneas or lenses. It's estimated that between 30% and 60% of adults in Europe and Asia have it (I actually have it myself, which is why I wear glasses). For people with astigmatism, a bright display with dark text is easier to read, because the iris closes a little more given the additional light; which decreases the impact of the defect in your cornea or lens.</p>
<p>As a sidenote: if you often experience headaches after a day of programming, you might want to test for astigmatism. Glasses make a world of difference</p>
<p>Lastly, there have been extensive studies about the readability of computer screens, one example is a study by Etienne Grandjean, called "Ergonomic Aspects of Visual Display Terminals". You can't read it online; if you manage to find it in a library you should check out pages 137-142. Its conclusion, like several other studies is that it's indeed easier to read dark text on a light background, then the other way around.</p>
<p>Often when I share these arguments with someone who clings to the dark side, they tell me light colour schemes hurt their eyes because they are too bright; you might be thinking the same right now. I've got two answers for you.</p>
<p>First: you don't need to use a white <code>#fff</code> background with black <code>#000</code> text. There's lots of light colour schemes that don't go to the extreme ends. The important thing is that there's enough contrast between fore- and background, and that the background is lighter than the foreground.
Second: you can always adjust the brightness of your screen. You don't need to turn it up to a 100%! You'd only do that if the text is otherwise unreadable, and guess when that happens? If you'd use a dark scheme!</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>I don't want to end with theory though. Over the past three years, I've put light themes to the test: I've challenged myself and dozens of others to switch to a light theme for <strong>one week</strong>. I wanna do the same with you: try it for one week, and let me know whether you're switching back to a dark theme or not. Based on my past experiments I can tell you that only a few people decide to switch back. The majority stays with a light scheme because, guess what, it's actually better.</p>
<p>Now I reckon there <em>are</em> people who can't use a light colour scheme because of an eye illness. There are legitimate cases when dark colour schemes <em>are</em> better for some people's health, the exceptions to the rule.</p>
<p>So try it out, and let me know your findings via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>!</p>
<p>PS: if you're using PhpStorm or any other JetBrain IDE, you can check these two light colour schemes:</p>
<ul>
<li>
<a target="_blank" href="https://github.com/brendt/phpstorm-light-lite-theme">Light Lite</a>
</li>
<li>
<a target="_blank" href="https://github.com/brendt/phpstorm-photon-theme">Photon Light</a>
</li>
</ul>
 ]]></summary>

                <updated>2020-09-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The case for transpiled generics in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/the-case-for-transpiled-generics"/>

                <id>https://www.stitcher.io/blog/the-case-for-transpiled-generics</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="footnotes">
<p>This is a mail I sent to PHP's internals, these are my thoughts, and you can follow the internals discussion <a href="https://externals.io/message/111875">here</a>, or share your own thoughts <a href="https://www.reddit.com/r/PHP/comments/iuhtgd/ive_proposed_an_approach_to_generics_on_internals/?">on Reddit</a>.</p>
</div><br>
<p>Hello internals</p>
<p>Today I'd like to hear your thoughts on what might be a controversial topic, though I think it's worth having this discussion. I want to make the case for adding generic syntax, without actually enforcing any additional type checks at runtime. Please hear me out.</p>
<p>We've been discussing generics for years now [1][2], all without any result. Nikita's latest attempt [3] stalled because, from what I gathered and amongst other things, doing generic type checks at runtime has a significant impact on performance.</p>
<p>On the other hand, static analysers have been making their rise for a few years now. Granted: not the whole community might like this kind of type strictness, and PHP doesn't force them to; but still projects like PhpStorm acknowledge their significance — they will add built-in support for both psalm and PHPStan later this year [4]. Rasmus Lerdorf also showed interest in the idea of improving PHP's static analysis capabilities two years ago [5].</p>
<p>That all to say that there's a significant part of the PHP community who's interested in embracing the benefits of static analysis.</p>
<p>If we look outside of our PHP bubble, we can see the same thing happening in JavaScript: the core benefit that TypeScript adds is its robust static analysis. Sure those developers need an extra compilation step to transpile their code to plain old JavaScript, but it seems that they are… fine with that?</p>
<p>I'd like to discuss a similar idea for PHP. If runtime generics aren't possible because of performance issues, why not explore the other option: adding generic syntax that is ignored by the interpreter, but can be used by static analysis tools — third party of built-into PHP, that's another discussion. I realise this thought goes against the "PHP mindset" we've been programming with for more than 20 years, but we shouldn't ignore what's happening in the PHP- and wider programming community: static analysis is relevant, whether you want to use it or not, and a stricter type system is preferred by many.</p>
<p>Now I know there are alternatives we can use today. Static analysers already support generics, using doc blocks. I'm not trying to argue that it's impossible to achieve the same results with the toolset we have, but rather that there's room for improvement from the developer's point of view. History has shown that such convenience additions to PHP have been a difficult pill to swallow for some, but on the other hand those kind of changes <em>have</em> been happening more and more often anyway: property promotion, short closures, named arguments, attributes, yes even types themselves: you can write the same working PHP program without any of those features, and yet they have been proven so useful and wanted over the last years.</p>
<p>As a sidenote: the idea of transpiling is already present in PHP. Looking at constructor property promotion: a purely syntactical feature, which is transformed to simpler PHP code at runtime. Nikita called this principle "desugaring" in the constructor property promotion RFC [6].</p>
<p>So here's my case for transpiled generics summarized:</p>
<ul>
<li>There's no significant runtime performance impact</li>
<li>The PHP community is already embracing static analysis</li>
<li>Transpiling has been proved to be a viable workflow, thanks to TypeScript</li>
<li>As with all things-PHP: it's opt-in. You don't have to use the syntax if you don't want to and you won't experience any downsides</li>
</ul>
<p>So with all that being said, I'm looking forward to hearing your thoughts.</p>
<p>Kind regards<br>
Brent</p>
<ul>
<li>[1] <a href="https://wiki.php.net/rfc/generics">https://wiki.php.net/rfc/generics</a>
</li>
<li>[2] <a href="https://wiki.php.net/rfc/generic-arrays">https://wiki.php.net/rfc/generic-arrays</a>
</li>
<li>[3] <a href="https://github.com/PHPGenerics/php-generics-rfc/issues/45">https://github.com/PHPGenerics/php-generics-rfc/issues/45</a>
</li>
<li>[4] <a href="https://blog.jetbrains.com/phpstorm/2020/07/phpstan-and-psalm-support-coming-to-phpstorm/">https://blog.jetbrains.com/phpstorm/2020/07/phpstan-and-psalm-support-coming-to-phpstorm/</a>
</li>
<li>[5] <a href="https://externals.io/message/101477#101592">https://externals.io/message/101477#101592</a>
</li>
<li>[6] <a href="https://wiki.php.net/rfc/constructor_promotion#desugaring">https://wiki.php.net/rfc/constructor_promotion#desugaring</a>
</li>
</ul>
 ]]></summary>

                <updated>2020-09-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Don&#039;t get stuck ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/dont-get-stuck"/>

                <id>https://www.stitcher.io/blog/dont-get-stuck</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>Note: this post is about a previous job, not my current one.</em></p>
<p>
<iframe width="560" height="422" src="https://www.youtube.com/embed/s_Q1BmNSujk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</p>
<p>Both managers were looking at me in disbelief, they seemed to be stunned for a few seconds. I just told them I had decided to resign. One of them quickly recovered, smiled, and said he regretted my decision; though he also realised it's expected in our line of work: people usually don't spend more than a few years at the same company.</p>
<p>I didn't want to chit-chat much longer, so I nodded, apologised (I'm not sure why), and told them I'd be checking out the paperwork with the office manager later that week. I left the room, went back to my desk.</p>
<p>I received a mail from the other manager over the weekend, the one who didn't say much during our conversation. He wrote he was perplexed, didn't see this coming, and regretted the decision tremendously. He told me if there was anything he could do to change my mind, I should tell him.</p>
<p>My decision to leave was final though.</p>
<p>Mind you, it wasn't a financial one; in fact I was just about to get a significant raise and more responsibilities. It also wasn't a relational one, I really appreciated all of my colleagues back then; I'd even call some of them good friends.</p>
<p>I decided to leave because I got stuck and there wasn't any room to grow anymore. The perspective of being a developer who's 5 years behind of modern day practices made me miserable.</p>
<p>Even though I'd been advocating within the company to make significant changes, both on a technical level, as well as on the management side; it didn't seem achievable. We were still struggling to deliver the quality we promised our clients, we were using out of date technologies, I went home feeling down and depressed almost every day.</p>
<p>I wasn't the only one, by the way. During the 3 years I worked for this company, 8 out of 25 people left, and around the same amount were hired; always young developers, straight from school, just like I three years before. Every time this happened, it was described as "the normal flow" a web development company has to deal with, just like our manager told me during my resignation.</p>
<p>I've since realised that this manager was wrong: it's not normal to switch jobs every 5 years, to have a third of your company come and go, and be replaced with inexperienced developers. And mind you: there should always be room for those juniors to grow, but who will teach them if most of the experienced developers left?</p>
<p>No, these kinds of things are only "normal" when your company fails to invest in people the way it should. And that, it turns out, is very common indeed.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>I don't regret having worked for that company: I did learn valuable lessons there. It's ok to be at a place where there's little or no room for growth, as long as it's not too long. You've got to watch out, and critically assess your situation from time to time; you might get stuck without even knowing it.</p>
<p>My advice? Either try to change your position and responsibilities within the company or, if that doesn't work, change jobs. I realise that's easy to write, like I also realise it's not as easy as it sounds. Personally, I noticed being stuck after two years and it took me another whole year to find a place where I believed there was enough room to grow.</p>
<p>Whatever turns your path takes, knowing you want to go somewhere and not stand idle is the most important first step.</p>
<p><div class="sidenote">
    <p>
        Thanks for reading! This post is part of my "Dev Diaries" series where I write about my own and personal experiences as a developer. Would you like to read some more?
    </p>

    <ul>
        <li><a href="/blog/how-i-plan">How I plan</a></li>
        <li><a href="/blog/why-do-i-write">Why do I write?</a></li>
        <li><a href="/blog/opinion-driven-design">Opinion-driven design</a></li>
        <li><a href="/blog/dont-get-stuck">Don't get stuck</a></li>
        <li><a href="/blog/dont-write-your-own-framework">Don't write your own framework</a></li>
        <li><a href="/blog/honesty">Honesty</a></li>
        <li><a href="/blog/when-i-lost-a-few-hundred-leads">When I lost a few hundred leads</a></li>
        <li><a href="/blog/how-to-be-right-on-the-internet">How to be right on the internet</a></li>
    </ul>

    <p>

        If you want to stay up to date about what's happening on this blog, you can follow me
        <a href="https://mobile.twitter.com/brendt_gd" target="_blank" rel="noopener noreferrer">on Twitter</a> or subscribe to my newsletter:
    </p>

    <form action="https://mail.stitcher.io/subscribe/81fa83d0-4a0b-4eff-b897-f6ce51dfb7f0" method="post" class="newsletter-form">
        <label for="email">Email</label>
        <input type="email" name="email"/>
        <button type="submit" class="cta cta-small">Subscribe</button>
    </form>
</div>
</p>
 ]]></summary>

                <updated>2020-08-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Annotations ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/annotations"/>

                <id>https://www.stitcher.io/blog/annotations</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="image-noborder"></div>
<p><img src="/resources/img/comics/annotations.png" srcset="/resources/img/comics/annotations-1399x707.png 1399w, /resources/img/comics/annotations-1083x547.png 1083w, /resources/img/comics/annotations-884x446.png 884w, /resources/img/comics/annotations-1251x632.png 1251w, /resources/img/comics/annotations-625x315.png 625w" sizes="" alt="Show large image"><em class="small center">Show large image</em></img></p>
 ]]></summary>

                <updated>2020-08-28T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Differences ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/differences"/>

                <id>https://www.stitcher.io/blog/differences</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="image-noborder"></div>
<p><img src="/resources/img/comics/differences.png" srcset="/resources/img/comics/differences-858x309.png 858w, /resources/img/comics/differences-1487x535.png 1487w, /resources/img/comics/differences-1717x618.png 1717w, /resources/img/comics/differences-1920x692.png 1920w, /resources/img/comics/differences-1214x437.png 1214w" sizes="" alt="Show large image"><em class="small center">Show large image</em></img></p>
 ]]></summary>

                <updated>2020-08-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ My journey into event sourcing ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/my-journey-into-event-sourcing"/>

                <id>https://www.stitcher.io/blog/my-journey-into-event-sourcing</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In this post I want to share four talks that have guided me into the world of event driven development, and by extent into event sourcing.</p>
<p>I wanted to share these talks here on my blog, because I figured some of you might be interested in them, and this way I can revisit them in the future.</p>
<hr />
<p>Starting with Martin Fowler, who explains the basics of event driven development, the pros and cons, as well as the different patterns that can be applied on top of EDD, one of them event sourcing.</p>
<p>
    <iframe width="560" height="400" 
        src="https://www.youtube.com/embed/STKCRSUsyP0" 
        frameborder="0" 
        allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
        allowfullscreen>
    </iframe>
</p>
<hr />
<p>Next Greg Young, one of the founding fathers of event sourcing and CQRS. What's most interesting in this talk is the misconceptions Greg talks about. The one that stood out to me most, is that event sourcing isn't a top-level architecture, it's a pattern that should be applied in parts of your projects where relevant. A great insight, one that has guided us throughout <a href="/blog/combining-event-sourcing-and-stateful-systems">our latest project</a>.</p>
<p>
    <iframe width="560" height="400" 
        src="https://www.youtube.com/embed/LDW0QWie21s" 
        frameborder="0" 
        allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
        allowfullscreen>
    </iframe>
</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<hr />
<p>Next up an old talk be Eric Evans. I know the video and sound quality is crap, but the way he talks about splitting large systems in small pieces is awesome.</p>
<p>The greatest insight for me is how he explains the concept of micro services within the context of one large system. Eric explains concrete ways of dealing with such a split system, which directly ties in the point made by Greg Young earlier: event sourcing should only be applied in parts of your system. Eric gives us concrete strategies of doing that.</p>
<p>
    <iframe width="560" height="400" 
        src="https://www.youtube.com/embed/OTF2Y6TLTG0" 
        frameborder="0" 
        allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
        allowfullscreen>
    </iframe>
</p>
<hr />
<p>Finally, putting everything into practice with code: Freek shows a hands-on integration of event sourcing into a Laravel projects, the framework I also work with daily.</p>
<p>
    <iframe width="560" height="400" 
        src="https://www.youtube.com/embed/9tbxl_I1EGE" 
        frameborder="0" 
        allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
        allowfullscreen>
    </iframe>
</p>
<hr />
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-07-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: named arguments ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-8-named-arguments"/>

                <id>https://www.stitcher.io/blog/php-8-named-arguments</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It was a <a href="/blog/why-we-need-named-params-in-php">close call</a>, but named arguments — also called named parameters — are supported in <a href="/blog/new-in-php-8">PHP 8</a>! In this post I'll discuss their ins and outs, but let me show you first what they look like with a few examples in the wild:</p>
<pre><span class="hl-property">setcookie</span>(
    <span class="hl-property">name</span>: '<span class="hl-value">test</span>',
    <span class="hl-property">expires</span>: <span class="hl-property">time</span>() + 60 * 60 * 2,
);
</pre>
<p><em class="center small">Named arguments used on a built-in PHP function</em></p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CustomerData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$email</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$age</span>,
    </span>) {}
}

<span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(
    <span class="hl-property">name</span>: <span class="hl-variable">$input</span>['<span class="hl-value">name</span>'],
    <span class="hl-property">email</span>: <span class="hl-variable">$input</span>['<span class="hl-value">email</span>'],
    <span class="hl-property">age</span>: <span class="hl-variable">$input</span>['<span class="hl-value">age</span>'],
);
</pre>
<p><em class="center small">A DTO making use of <a href="/blog/constructor-promotion-in-php-8">promoted properties</a>, as well as named arguments</em></p>
<pre><span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(...<span class="hl-variable">$customerRequest</span>-&gt;<span class="hl-property">validated</span>());
</pre>
<p><em class="center small">Named arguments also support array spreading</em></p>
<p>You might have guessed it from the examples: named arguments allow you to pass input data into a function, based on their argument name instead of the argument order.</p>
<p>I would argue named arguments are a great feature that will have a significant impact on my day-to-day programming life.
You're probably wondering about the details though: what if you pass a wrong name, what's up with that array spreading syntax? Well, let's look at all those questions in-depth.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="why-named-arguments?"><a href="#why-named-arguments?" class="heading-anchor">#</a> Why named arguments?</h2>
<p>Let's say this feature was a highly debated one, and there were some <a href="/blog/why-we-need-named-params-in-php">counter arguments</a> to not adding them. However, I'd say their benefit far outweigh the fear of backwards compatibility problems or bloated APIs. The way I see it, they will allow us to write cleaner and more flexible code.</p>
<p>For one, named arguments allow you to skip default values. Take a look again at the cookie example:</p>
<pre><span class="hl-property">setcookie</span>(
    <span class="hl-property">name</span>: '<span class="hl-value">test</span>',
    <span class="hl-property">expires</span>: <span class="hl-property">time</span>() + 60 * 60 * 2,
);
</pre>
<p>Its method signature is actually the following:</p>
<pre>setcookie ( 
    string <span class="hl-variable">$name</span>, 
    string <span class="hl-variable">$value</span> = &quot;<span class="hl-value"></span>&quot;, 
    int <span class="hl-variable">$expires</span> = 0, 
    string <span class="hl-variable">$path</span> = &quot;<span class="hl-value"></span>&quot;, 
    string <span class="hl-variable">$domain</span> = &quot;<span class="hl-value"></span>&quot;, 
    bool <span class="hl-variable">$secure</span> = <span class="hl-keyword">false</span>, 
    bool <span class="hl-variable">$httponly</span> = <span class="hl-keyword">false</span>,
) : <span class="hl-type">bool</span>
</pre>
<p>In the example I showed, we didn't need to set the a cookie <code>$value</code>, but we did need to set an expiration time. Named arguments made this method call a little more concise:</p>
<pre><span class="hl-property">setcookie</span>(
    '<span class="hl-value">test</span>',
    '<span class="hl-value"></span>',
    <span class="hl-property">time</span>() + 60 * 60 * 2,
);
</pre>
<p><em class="center small"><code>setcookie</code> without named arguments</em></p>
<pre><span class="hl-property">setcookie</span>(
    <span class="hl-property">name</span>: '<span class="hl-value">test</span>',
    <span class="hl-property">expires</span>: <span class="hl-property">time</span>() + 60 * 60 * 2,
);
</pre>
<p><em class="center small"><code>setcookie</code> with named arguments</em></p>
<p>Besides skipping arguments with default values, there's also the benefit of having clarity about which variable does what; something that's especially useful in functions with large method signatures. Now we could say that lots of arguments are usually a code smell; we still have to deal with them no matter what, so it's better to have a sane way of doing so, than nothing at all.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="named-arguments-in-depth"><a href="#named-arguments-in-depth" class="heading-anchor">#</a> Named arguments in depth</h2>
<p>With the basics out of the way, let's look at what named arguments can and can't do.</p>
<p>First of all, named arguments can be combined with unnamed — also called ordered — arguments. In that case the ordered arguments must always come first.</p>
<p>Take our DTO example from before:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CustomerData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$email</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$age</span>,
    </span>) {}
}
</pre>
<p>You could construct it like so:</p>
<pre><span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(
    <span class="hl-variable">$input</span>['<span class="hl-value">name</span>'],
    <span class="hl-property">age</span>: <span class="hl-variable">$input</span>['<span class="hl-value">age</span>'],
    <span class="hl-property">email</span>: <span class="hl-variable">$input</span>['<span class="hl-value">email</span>'],
);
</pre>
<p>However, having an ordered argument after a named one would throw an error:</p>
<pre><span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(
    <span class="hl-property">age</span>: <span class="hl-variable">$input</span>['<span class="hl-value">age</span>'],
    <span class="hl-variable">$input</span>['<span class="hl-value">name</span>'],
    <span class="hl-property">email</span>: <span class="hl-variable">$input</span>['<span class="hl-value">email</span>'],
);
</pre>
<hr />
<p>Next, it's possible to use array spreading in combination with named arguments:</p>
<pre><span class="hl-variable">$input</span> = [
    '<span class="hl-value">age</span>' =&gt; 25,
    '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">Brent</span>',
    '<span class="hl-value">email</span>' =&gt; '<span class="hl-value">brent@stitcher.io</span>',
];

<span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(...<span class="hl-variable">$input</span>);
</pre>
<p><em>If</em>, however, there are missing required entries in the array, or if there's a key that's not listed as a named argument, an error will be thrown:</p>
<pre><span class="hl-variable">$input</span> = [
    '<span class="hl-value">age</span>' =&gt; 25,
    '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">Brent</span>',
    '<span class="hl-value">email</span>' =&gt; '<span class="hl-value">brent@stitcher.io</span>',
    '<span class="hl-value">unknownProperty</span>' =&gt; '<span class="hl-value">This is not allowed</span>',
];

<span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(...<span class="hl-variable">$input</span>);
</pre>
<p>It <em>is</em> possible to combine named and ordered arguments in an input array, but only if the ordered arguments follow the same rule as before: they must come first!</p>
<pre><span class="hl-variable">$input</span> = [
    '<span class="hl-value">Brent</span>',
    '<span class="hl-value">age</span>' =&gt; 25,
    '<span class="hl-value">email</span>' =&gt; '<span class="hl-value">brent@stitcher.io</span>',
];

<span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(...<span class="hl-variable">$input</span>);
</pre>
<hr />
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<hr />
<p>If you're using variadic functions, named arguments will be passed with their key name into the variadic arguments array. Take the following example:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CustomerData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-keyword">new</span>(<span class="hl-injection">...$args</span>): <span class="hl-type">self</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">self</span>(...<span class="hl-variable">$args</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$email</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$age</span>,
    </span>) {}
}

<span class="hl-variable">$data</span> = <span class="hl-type">CustomerData</span>::<span class="hl-keyword">new</span>(
    <span class="hl-property">email</span>: '<span class="hl-value">brent@stitcher.io</span>',
    <span class="hl-property">age</span>: 25,
    <span class="hl-property">name</span>: '<span class="hl-value">Brent</span>',
);
</pre>
<p>In this case, <code>$args</code> in <code>CustomerData::new</code> will contain the following data:</p>
<pre>[
    '<span class="hl-value">age</span>' =&gt; 25,
    '<span class="hl-value">email</span>' =&gt; '<span class="hl-value">brent@stitcher.io</span>',
    '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">Brent</span>',
]
</pre>
<hr />
<p><a href="/blog/attributes-in-php-8">Attributes</a> — also known as annotations — also support named arguments:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ProductSubscriber</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ListensTo</span>(<span class="hl-property">event</span>: <span class="hl-type">ProductCreated</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onProductCreated</span>(<span class="hl-injection"><span class="hl-type">ProductCreated</span> $event</span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<hr />
<p>It's not possible to have a variable as the argument name:</p>
<pre><span class="hl-variable">$field</span> = '<span class="hl-value">age</span>';

<span class="hl-variable">$data</span> = <span class="hl-type">CustomerData</span>::<span class="hl-keyword">new</span>(
    <span class="hl-variable">$field</span>: 25,
);
</pre>
<hr />
<p>And finally, named arguments will deal in a pragmatic way with name changes during inheritance. Take this example:</p>
<pre><span class="hl-keyword">interface</span> <span class="hl-type">EventListener</span> {
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">on</span>(<span class="hl-injection">$event, $handler</span>);
}

<span class="hl-keyword">class</span> <span class="hl-type">MyListener</span> <span class="hl-keyword">implements</span><span class="hl-type"> EventListener
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">on</span>(<span class="hl-injection">$myEvent, $myHandler</span>)
    {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>PHP will silently allow changing the name of <code>$event</code> to <code>$myEvent</code>, and <code>$handler</code> to <code>$myHandler</code>; <em>but</em> if you decide to use named arguments using the parent's name, it will result in a runtime error:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">register</span>(<span class="hl-injection"><span class="hl-type">EventListener</span> $listener</span>)
{
    <span class="hl-variable">$listener</span>-&gt;<span class="hl-property">on</span>(
        <span class="hl-property">event</span>: <span class="hl-variable">$this</span>-&gt;<span class="hl-property">event</span>,
        <span class="hl-property">handler</span>: <span class="hl-variable">$this</span>-&gt;<span class="hl-property">handler</span>, 
    );
}
</pre>
<p><em class="small center">Runtime error in case <code>$listener</code> is an instance of <code>MyListener</code></em></p>
<p>This pragmatic approach was chosen to prevent a major breaking change when all inherited arguments would have to keep the same name. Seems like a good solution to me.</p>
<hr />
<p>That's most there is to tell about named arguments. If you want to know a little more backstory behind some design decisions, I'd encourage you to read <a href="https://wiki.php.net/rfc/named_params">the RFC</a>.</p>
<p>Are you looking forward to using named arguments? Let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>!</p>
 ]]></summary>

                <updated>2020-07-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: before and after ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-8-before-and-after"/>

                <id>https://www.stitcher.io/blog/php-8-before-and-after</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's only a few months before <a href="/blog/new-in-php-8">PHP 8</a> will be released, and honestly there are so many good features. In this post I want to share the real-life impact that PHP 8 will have on my own code.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="events-subscribers-with-attributes"><a href="#events-subscribers-with-attributes" class="heading-anchor">#</a> Events subscribers with attributes</h2>
<p>I'm going to try not to abuse <a href="/blog/attributes-in-php-8">attributes</a>, but I think configuring event listeners is an example of an annotation I'll be using extensively.</p>
<p>You might know that I've been working on <a href="/blog/combining-event-sourcing-and-stateful-systems">event sourced systems</a> lately, and I can tell you: there's lots of event configuration to do. Take this simple projector, for example:</p>
<pre><span class="hl-comment">// Before</span>

<span class="hl-keyword">class</span> <span class="hl-type">CartsProjector</span> <span class="hl-keyword">implements</span><span class="hl-type"> Projector
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">ProjectsEvents</span>;

    <span class="hl-keyword">protected</span> <span class="hl-type">array</span> <span class="hl-property">$handlesEvents</span> = [
        <span class="hl-type">CartStartedEvent</span>::<span class="hl-keyword">class</span> =&gt; '<span class="hl-value">onCartStarted</span>',
        <span class="hl-type">CartItemAddedEvent</span>::<span class="hl-keyword">class</span> =&gt; '<span class="hl-value">onCartItemAdded</span>',
        <span class="hl-type">CartItemRemovedEvent</span>::<span class="hl-keyword">class</span> =&gt; '<span class="hl-value">onCartItemRemoved</span>',
        <span class="hl-type">CartExpiredEvent</span>::<span class="hl-keyword">class</span> =&gt; '<span class="hl-value">onCartExpired</span>',
        <span class="hl-type">CartCheckedOutEvent</span>::<span class="hl-keyword">class</span> =&gt; '<span class="hl-value">onCartCheckedOut</span>',
        <span class="hl-type">CouponAddedToCartItemEvent</span>::<span class="hl-keyword">class</span> =&gt; '<span class="hl-value">onCouponAddedToCartItem</span>',
    ];

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartStarted</span>(<span class="hl-injection"><span class="hl-type">CartStartedEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartItemAdded</span>(<span class="hl-injection"><span class="hl-type">CartItemAddedEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartItemRemoved</span>(<span class="hl-injection"><span class="hl-type">CartItemRemovedEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartCheckedOut</span>(<span class="hl-injection"><span class="hl-type">CartCheckedOutEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartExpired</span>(<span class="hl-injection"><span class="hl-type">CartExpiredEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCouponAddedToCartItem</span>(<span class="hl-injection"><span class="hl-type">CouponAddedToCartItemEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p><em class="center small">PHP 7.4</em></p>
<p>There are two benefits attributes will give me:</p>
<ul>
<li>Event listener configuration and handlers are put together, I don't have to scroll to the top of the file to know whether a listener is configured correctly.</li>
<li>I don't have to bother anymore writing and managing method names as strings: your IDE can't autocomplete them, there's no static analysis on typos and method renaming doesn't work.</li>
</ul>
<p>Luckily, PHP 8 solves these problems:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CartsProjector</span> <span class="hl-keyword">implements</span><span class="hl-type"> Projector
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">ProjectsEvents</span>;

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">SubscribesTo</span>(<span class="hl-type">CartStartedEvent</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartStarted</span>(<span class="hl-injection"><span class="hl-type">CartStartedEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">SubscribesTo</span>(<span class="hl-type">CartItemAddedEvent</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartItemAdded</span>(<span class="hl-injection"><span class="hl-type">CartItemAddedEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">SubscribesTo</span>(<span class="hl-type">CartItemRemovedEvent</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartItemRemoved</span>(<span class="hl-injection"><span class="hl-type">CartItemRemovedEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">SubscribesTo</span>(<span class="hl-type">CartCheckedOutEvent</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartCheckedOut</span>(<span class="hl-injection"><span class="hl-type">CartCheckedOutEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">SubscribesTo</span>(<span class="hl-type">CartExpiredEvent</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCartExpired</span>(<span class="hl-injection"><span class="hl-type">CartExpiredEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">SubscribesTo</span>(<span class="hl-type">CouponAddedToCartItemEvent</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onCouponAddedToCartItem</span>(<span class="hl-injection"><span class="hl-type">CouponAddedToCartItemEvent</span> $event</span>): <span class="hl-type">void</span>
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p><em class="center small">PHP 8</em></p>
<h2 id="static-instead-of-doc-blocks"><a href="#static-instead-of-doc-blocks" class="heading-anchor">#</a> Static instead of doc blocks</h2>
<p>A smaller one, but this one will have a day-by-day impact. I often find myself still needing doc blocks because of two things: static return types and generics. The latter one can't be solved yet, but luckily the first one will in PHP 8!</p>
<p>When I'd write this in PHP 7.4:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@return</span> <span class="hl-type">static</span>
 */</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-keyword">new</span>()
{
    <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">static</span>();
}
</pre>
<p><em class="center small">PHP 7.4</em></p>
<p>I'll now be able to write:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-keyword">new</span>(): <span class="hl-keyword">static</span>
{
    <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">static</span>();
}
</pre>
<p><em class="center small">PHP 8</em></p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="dto's,-property-promotion-and-named-arguments"><a href="#dto's,-property-promotion-and-named-arguments" class="heading-anchor">#</a> DTO's, property promotion and named arguments</h2>
<p>If you read my blog, you know I wrote quite a bit about the use of PHP's type system combined with <a href="/blog/laravel-beyond-crud-02-working-with-data">data transfer objects</a>. Naturally, I use lots of DTOs in my own code, so you can imagine how happy I am, being able to rewrite this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CustomerData</span> <span class="hl-keyword">extends</span> <span class="hl-type">DataTransferObject</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>;

    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$email</span>;

    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$age</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">fromRequest</span>(<span class="hl-injection">
        <span class="hl-type">CustomerRequest</span> $request
    </span>): <span class="hl-type">self</span> {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">self</span>([
            '<span class="hl-value">name</span>' =&gt; <span class="hl-variable">$request</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">name</span>'),
            '<span class="hl-value">email</span>' =&gt; <span class="hl-variable">$request</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">email</span>'),
            '<span class="hl-value">age</span>' =&gt; <span class="hl-variable">$request</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">age</span>'),
        ]);
    }
}

<span class="hl-variable">$data</span> = <span class="hl-type">CustomerData</span>::<span class="hl-property">fromRequest</span>(<span class="hl-variable">$customerRequest</span>);
</pre>
<p><em class="center small">PHP 7.4</em></p>
<p>As this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CustomerData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$email</span>,
        <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$age</span>,
    </span>) {}
}

<span class="hl-variable">$data</span> = <span class="hl-keyword">new</span> <span class="hl-type">CustomerData</span>(...<span class="hl-variable">$customerRequest</span>-&gt;<span class="hl-property">validated</span>());
</pre>
<p><em class="center small">PHP 8</em></p>
<p>Note the use of both <a href="/blog/constructor-promotion-in-php-8">constructor property promotion</a>, as well as named arguments. Yes, they can be passed using named arrays and the spread operator!</p>
<h2 id="enums-and-the-match-expression"><a href="#enums-and-the-match-expression" class="heading-anchor">#</a> Enums and the match expression</h2>
<p>Do you sometimes find yourself using an enum with some methods on it, that will give a different result based on the enum value?</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@method</span> static self PENDING()
 * <span class="hl-value">@method</span> static self PAID()
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">InvoiceState</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PENDING</span> = '<span class="hl-value">pending</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PAID</span> = '<span class="hl-value">paid</span>';

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getColour</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> [
            <span class="hl-type">self</span>::<span class="hl-property">PENDING</span> =&gt; '<span class="hl-value">orange</span>',
            <span class="hl-type">self</span>::<span class="hl-property">PAID</span> =&gt; '<span class="hl-value">green</span>',
        ][<span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span>] ?? '<span class="hl-value">gray</span>';   
    }
}
</pre>
<p><em class="center small">PHP 7.4</em></p>
<p>I would argue that for more complex conditions, you're better off using <a href="/blog/laravel-beyond-crud-05-states">the state pattern</a>, yet there are cases where an enum does suffice. This weird array syntax already is a shorthand for a more verbose conditional:</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@method</span> static self PENDING()
 * <span class="hl-value">@method</span> static self PAID()
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">InvoiceState</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PENDING</span> = '<span class="hl-value">pending</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PAID</span> = '<span class="hl-value">paid</span>';

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getColour</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">if</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> === <span class="hl-type">self</span>::<span class="hl-property">PENDING</span>) {
            <span class="hl-keyword">return</span> '<span class="hl-value">orange</span>';
        }
    
        <span class="hl-keyword">if</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> === <span class="hl-type">self</span>::<span class="hl-property">PAID</span>) {
            <span class="hl-keyword">return</span> '<span class="hl-value">green</span>'
        }

        <span class="hl-keyword">return</span> '<span class="hl-value">gray</span>';
    }
}
</pre>
<p><em class="center small">PHP 7.4 — alternative</em></p>
<p>But with PHP 8, we can use the <a href="/blog/php-8-match-or-switch"><code>match</code> expression</a> instead!</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@method</span> static self PENDING()
 * <span class="hl-value">@method</span> static self PAID()
 */</span>
<span class="hl-keyword">class</span> <span class="hl-type">InvoiceState</span> <span class="hl-keyword">extends</span> <span class="hl-type">Enum</span>
{
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PENDING</span> = '<span class="hl-value">pending</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">PAID</span> = '<span class="hl-value">paid</span>';

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getColour</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">match</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span>) {
            <span class="hl-type">self</span>::<span class="hl-property">PENDING</span> =&gt; '<span class="hl-value">orange</span>',
            <span class="hl-type">self</span>::<span class="hl-property">PAID</span> =&gt; '<span class="hl-value">green</span>',
            <span class="hl-keyword">default</span> =&gt; '<span class="hl-value">gray</span>',
        };
    }
}
</pre>
<p><em class="center small">PHP 8</em></p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="union-types-instead-of-doc-blocks"><a href="#union-types-instead-of-doc-blocks" class="heading-anchor">#</a> Union types instead of doc blocks</h2>
<p>When I mentioned the <code>static</code> return type before, I forgot another use case where docblock type hints were required: union types. At least, they were required before, because PHP 8 supports them natively!</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@param</span> <span class="hl-type">string|int</span> <span class="hl-variable">$input</span>
 *
 * <span class="hl-value">@return</span> <span class="hl-type">string </span>
 */</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">sanitize</span>(<span class="hl-injection">$input</span>): <span class="hl-type">string</span>;
</pre>
<p><em class="center small">PHP 7.4</em></p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">sanitize</span>(<span class="hl-injection"><span class="hl-type">string|int</span> $input</span>): <span class="hl-type">string</span>;
</pre>
<p><em class="center small">PHP 8</em></p>
<h2 id="throw-expressions"><a href="#throw-expressions" class="heading-anchor">#</a> Throw expressions</h2>
<p>Before PHP 8, you couldn't use <code>throw</code> in an expression, meaning you'd have to do explicit checks like so:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">array</span> $input</span>): <span class="hl-type">void</span>
{
    <span class="hl-keyword">if</span> (! <span class="hl-keyword">isset</span>(<span class="hl-variable">$input</span>['<span class="hl-value">bar</span>'])) {
        <span class="hl-keyword">throw</span> <span class="hl-type">BarIsMissing</span>::<span class="hl-keyword">new</span>();
    }
    
    <span class="hl-variable">$bar</span> = <span class="hl-variable">$input</span>['<span class="hl-value">bar</span>'];

    <span class="hl-comment">// …</span>
}
</pre>
<p><em class="center small">PHP 7.4</em></p>
<p>In PHP 8, <code>throw</code> has become an expression, meaning you can use it like so:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">array</span> $input</span>): <span class="hl-type">void</span>
{
    <span class="hl-variable">$bar</span> = <span class="hl-variable">$input</span>['<span class="hl-value">bar</span>'] ?? <span class="hl-keyword">throw</span> <span class="hl-type">BarIsMissing</span>::<span class="hl-keyword">new</span>();

    <span class="hl-comment">// …</span>
}
</pre>
<p><em class="center small">PHP 8</em></p>
<h2 id="the-nullsafe-operator"><a href="#the-nullsafe-operator" class="heading-anchor">#</a> The nullsafe operator</h2>
<p>If you're familiar with the <a href="/blog/shorthand-comparisons-in-php#null-coalescing-operator">null coalescing operator</a> you're already familiar with its shortcomings: it doesn't work on method calls. Instead you need intermediate checks, or rely on <code>optional</code> helpers provided by some frameworks:</p>
<pre><span class="hl-variable">$startDate</span> = <span class="hl-variable">$booking</span>-&gt;<span class="hl-property">getStartDate</span>();

<span class="hl-variable">$dateAsString</span> = <span class="hl-variable">$startDate</span> <span class="hl-operator">?</span> <span class="hl-variable">$startDate</span>-&gt;<span class="hl-property">asDateTimeString</span>() : <span class="hl-keyword">null</span>;
</pre>
<p><em class="center small">PHP 7.4</em></p>
<p>With the addition of the nullsafe operator, we can now have null coalescing-like behaviour on methods!</p>
<pre><span class="hl-variable">$dateAsString</span> = <span class="hl-variable">$booking</span>-&gt;<span class="hl-property">getStartDate</span>()?-&gt;<span class="hl-property">asDateTimeString</span>();
</pre>
<p><em class="center small">PHP 8</em></p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>What's your favourite <a href="/blog/new-in-php-8">PHP 8 feature</a>? Let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>!</p>
 ]]></summary>

                <updated>2020-07-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Shorthand comparisons in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/shorthand-comparisons-in-php"/>

                <id>https://www.stitcher.io/blog/shorthand-comparisons-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>You probably already know some comparison operators in PHP.
Things like the ternary <code>?:</code>, the null coalescing <code>??</code> and the spaceship <code>&lt;=&gt;</code> operators.
But do you really know how they work?
Understanding these operators makes you use them more, resulting in a cleaner codebase.</p>
<p>Before looking at each operator in depth, here's a summary of what each of them does:</p>
<ul>
<li>The <a href="#ternary-operator">ternary operator</a> is used to shorten if/else structures</li>
<li>The <a href="#null-coalescing-operator">null coalescing operator</a> is used to provide default values instead of null</li>
<li>The <a href="#spaceship-operator">spaceship operator</a> is used to compare two values</li>
</ul>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="ternary-operator"><a href="#ternary-operator" class="heading-anchor">#</a> Ternary operator</h2>
<p>The ternary operator is a shorthand for the <code>if {} else {}</code> structure. Instead of writing this:</p>
<pre><span class="hl-keyword">if</span> (<span class="hl-variable">$condition</span>) {
    <span class="hl-variable">$result</span> = '<span class="hl-value">foo</span>' 
} <span class="hl-keyword">else</span> {
    <span class="hl-variable">$result</span> = '<span class="hl-value">bar</span>'
}
</pre>
<p>You can write this:</p>
<pre><span class="hl-variable">$result</span> = <span class="hl-variable">$condition</span> <span class="hl-operator">?</span> '<span class="hl-value">foo</span>' : '<span class="hl-value">bar</span>';
</pre>
<p>If this <code>$condition</code> evaluates to <code>true</code>, the lefthand operand will be assigned to <code>$result</code>.
If the condition evaluates to <code>false</code>, the righthand will be used.</p>
<p>Interesting fact: the name <em>ternary operator</em> actually means "an operator which acts on three operands".
An <em>operand</em> is the term used to denote the parts needed by an expression.
The ternary operator is the only operator in PHP which requires three operands:
the condition, the <code>true</code> and the <code>false</code> result. Similarly, there are also binary and unary operators.
You can read more about it <a target="_blank" href="http://php.net/manual/en/language.operators.php">here</a>.</p>
<p>Back to ternary operators: do you know which expressions evaluate to <code>true</code>, and which don't?
Take a look at the <code>boolean</code> column of <a target="_blank" href="http://php.net/manual/en/types.comparisons.php">this table</a>.</p>
<p>The ternary operator will use its lefthand operand when the condition evaluates to <code>true</code>.
This could be a string, an integer, a boolean etc.
The righthand operand will be used for so called "falsy values".</p>
<p>Examples would be <code>0</code> or <code>'0'</code>, an empty array or string, <code>null</code>, an undefined or unassigned variable, and of course <code>false</code> itself.
All these values will make the ternary operator use its righthand operand.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h3 id="shorthand-ternary-operator"><a href="#shorthand-ternary-operator" class="heading-anchor">#</a> Shorthand ternary operator</h3>
<p>Since PHP 5.3, it's possible to leave out the lefthand operand, allowing for even shorter expressions:</p>
<pre><span class="hl-variable">$result</span> = <span class="hl-variable">$initial</span> ?: '<span class="hl-value">default</span>';
</pre>
<p>In this case, the value of <code>$result</code> will be the value of <code>$initial</code>, unless <code>$initial</code> evaluates to <code>false</code>,
in which case the string <code>'default'</code> is used.</p>
<p>You could write this expression the same way using the normal ternary operator:</p>
<pre><span class="hl-variable">$result</span> = <span class="hl-variable">$condition</span> <span class="hl-operator">?</span> <span class="hl-variable">$condition</span> : '<span class="hl-value">default</span>';
</pre>
<p>Ironically, by leaving out the second operand of the ternary operator, it actually becomes a <strong>binary operator</strong>.</p>
<h3 id="chaining-ternary-operators"><a href="#chaining-ternary-operators" class="heading-anchor">#</a> Chaining ternary operators</h3>
<p>The following, even though it seems logical; doesn't work in PHP:</p>
<pre><span class="hl-variable">$result</span> = <span class="hl-variable">$firstCondition</span>
    <span class="hl-operator">?</span> '<span class="hl-value">truth</span>'
    : <span class="hl-variable">$elseCondition</span>
        <span class="hl-operator">?</span> '<span class="hl-value">elseTrue</span>'
        : '<span class="hl-value">elseFalse</span>';
</pre>
<p>The reason because is that the ternary operator in PHP is left-associative, and thus parsed in a very strange way.
The above example would always evaluate the <code>$elseCondition</code> part first, so even when <code>$firstCondition</code> would be <code>true</code>, you'd never see its output.</p>
<p>I believe the right thing to do is to avoid nested ternary operators altogether.
You can read more about this strange behaviour
in this <a target="_blank" href="https://stackoverflow.com/questions/20559150/ternary-operator-left-associativity/38231137#38231137">Stack Overflow answer</a>.</p>
<p>Furthermore, as PHP 7.4, the use of chained ternaries without brackets is <a href="/blog/new-in-php-74#left-associative-ternary-operator-deprecation-rfc">deprecated</a>.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="null-coalescing-operator"><a href="#null-coalescing-operator" class="heading-anchor">#</a> Null coalescing operator</h2>
<p>Did you take a look at <a target="_blank" href="http://php.net/manual/en/types.comparisons.php">the types comparison table</a> earlier?
The null coalescing operator is available since PHP 7.0.
It similar to the ternary operator, but will behave like <code>isset</code> on the lefthand operand instead of just using its boolean value.
This makes this operator especially useful for arrays and assigning defaults when a variable is not set.</p>
<pre><span class="hl-variable">$undefined</span> ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'fallback'</span>

<span class="hl-variable">$unassigned</span>;
<span class="hl-variable">$unassigned</span> ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'fallback'</span>

<span class="hl-variable">$assigned</span> = '<span class="hl-value">foo</span>';
<span class="hl-variable">$assigned</span> ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'foo'</span>

'<span class="hl-value"></span>' ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// ''</span>
'<span class="hl-value">foo</span>' ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'foo'</span>
'<span class="hl-value">0</span>' ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// '0'</span>
0 ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 0</span>
<span class="hl-keyword">false</span> ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// false</span>
</pre>
<p>The null coalescing operator takes two operands, making it a <em>binary</em> operator.
"Coalescing" by the way, means "coming together to form one mass or whole".
It will take two operands, and decide which of those to use based on the value of the lefthand operand.</p>
<h3 id="null-coalescing-on-arrays"><a href="#null-coalescing-on-arrays" class="heading-anchor">#</a> Null coalescing on arrays</h3>
<p>This operator is especially useful in combination with arrays, because of its acts like <code>isset</code>.
This means you can quickly check for the existence of keys, even nested keys, without writing verbose expressions.</p>
<pre><span class="hl-variable">$input</span> = [
    '<span class="hl-value">key</span>' =&gt; '<span class="hl-value">key</span>',
    '<span class="hl-value">nested</span>' =&gt; [
        '<span class="hl-value">key</span>' =&gt; <span class="hl-keyword">true</span>
    ]
];

<span class="hl-variable">$input</span>['<span class="hl-value">key</span>'] ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'key'</span>
<span class="hl-variable">$input</span>['<span class="hl-value">nested</span>']['<span class="hl-value">key</span>'] ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// true</span>
<span class="hl-variable">$input</span>['<span class="hl-value">undefined</span>'] ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'fallback'</span>
<span class="hl-variable">$input</span>['<span class="hl-value">nested</span>']['<span class="hl-value">undefined</span>'] ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'fallback'</span>

<span class="hl-keyword">null</span> ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'fallback'</span>
</pre>
<p>The first example could also be written using a ternary operator:</p>
<pre><span class="hl-variable">$output</span> = <span class="hl-keyword">isset</span>(<span class="hl-variable">$input</span>['<span class="hl-value">key</span>']) <span class="hl-operator">?</span> <span class="hl-variable">$input</span>['<span class="hl-value">key</span>'] : '<span class="hl-value">fallback</span>';
</pre>
<p>Note that it's impossible to use the shorthand ternary operator when checking the existence of array keys.
It will either trigger an error or return a boolean, instead of the real lefthand operand's value.</p>
<pre><span class="hl-comment">// Returns `true` instead of the value of `$input['key']`</span>
<span class="hl-variable">$output</span> = <span class="hl-keyword">isset</span>(<span class="hl-variable">$input</span>['<span class="hl-value">key</span>']) ?: '<span class="hl-value">fallback</span>' 

<span class="hl-comment">// The following will trigger an 'undefined index' notice </span>
<span class="hl-comment">// when $input is no array or has no 'key'.</span>
<span class="hl-comment">//</span>
<span class="hl-comment">// It will trigger an 'undefined variable' notice </span>
<span class="hl-comment">// when $input doesn't exist.</span>
<span class="hl-variable">$output</span> = <span class="hl-variable">$input</span>['<span class="hl-value">key</span>'] ?: '<span class="hl-value">fallback</span>';
</pre>
<h3 id="null-coalesce-chaining"><a href="#null-coalesce-chaining" class="heading-anchor">#</a> Null coalesce chaining</h3>
<p>The null coalescing operator can easily be chained:</p>
<pre><span class="hl-variable">$input</span> = [
    '<span class="hl-value">key</span>' =&gt; '<span class="hl-value">key</span>',
];

<span class="hl-variable">$input</span>['<span class="hl-value">undefined</span>'] ?? <span class="hl-variable">$input</span>['<span class="hl-value">key</span>'] ?? '<span class="hl-value">fallback</span>'; <span class="hl-comment">// 'key'</span>
</pre>
<h3 id="nested-coalescing"><a href="#nested-coalescing" class="heading-anchor">#</a> Nested coalescing</h3>
<p>It's possible to use the null coalescing operator on nested object properties, even when a property in the chain is <code>null</code>.</p>
<pre><span class="hl-variable">$a</span> = (object) [
    '<span class="hl-value">prop</span>' =&gt; <span class="hl-keyword">null</span>,
];

<span class="hl-property">var_dump</span>(<span class="hl-variable">$a</span>-&gt;<span class="hl-property">prop</span>-&gt;<span class="hl-property">b</span> ?? '<span class="hl-value">empty</span>');

<span class="hl-comment">// 'empty'</span>
</pre>
<h3 id="null-coalescing-assignment-operator"><a href="#null-coalescing-assignment-operator" class="heading-anchor">#</a> Null coalescing assignment operator</h3>
<p>In PHP 7,4, we can expect an even shorter syntax called the <a href="https://wiki.php.net/rfc/null_coalesce_equal_operator">"null coalescing assignment operator"</a>.</p>
<pre><span class="hl-comment">// This operator will be available in PHP 7.4</span>

<span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">array</span> $parameters = []</span>) {
    <span class="hl-variable">$parameters</span>['<span class="hl-value">property</span>'] ??= '<span class="hl-value">default</span>';
}
</pre>
<p>In this example, <code>$parameters['property']</code> will be set to <code>'default'</code>, unless it is set in the array passed to the function.
This would be equivalent to the following, using the current null coalescing operator:</p>
<pre><span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">array</span> $parameters = []</span>) {
    <span class="hl-variable">$parameters</span>['<span class="hl-value">property</span>'] = <span class="hl-variable">$parameters</span>['<span class="hl-value">property</span>'] ?? '<span class="hl-value">default</span>';
}
</pre>
<h2 id="spaceship-operator"><a href="#spaceship-operator" class="heading-anchor">#</a> Spaceship operator</h2>
<p>The spaceship operator, while having quite a peculiar name, can be very useful.
It's an operator used for comparison.
It will always return one of three values: <code>0</code>, <code>-1</code> or <code>1</code>.</p>
<p><code>0</code> will be returned when both operands are equals,
<code>1</code> when the left operand is larger, and <code>-1</code> when the right operand is larger.
Let's take a look at a simple example:</p>
<pre>1 <span class="hl-operator">&lt;=&gt;</span> 2; <span class="hl-comment">// Will return -1, as 2 is larger than 1.</span>
</pre>
<p>This simple example isn't all that exiting, right?
However, the spaceship operator can compare a lot more than simple values!</p>
<pre><span class="hl-comment">// It can compare strings,</span>
'<span class="hl-value">a</span>' <span class="hl-operator">&lt;=&gt;</span> '<span class="hl-value">z</span>'; <span class="hl-comment">// -1</span>

<span class="hl-comment">// and arrays,</span>
[2, 1] <span class="hl-operator">&lt;=&gt;</span> [2, 1]; <span class="hl-comment">// 0</span>

<span class="hl-comment">// nested arrays,</span>
[[1, 2], [2, 2]] <span class="hl-operator">&lt;=&gt;</span> [[1, 2], [1, 2]]; <span class="hl-comment">// 1</span>

<span class="hl-comment">// and even casing.</span>
'<span class="hl-property">Z</span>' <span class="hl-operator">&lt;=&gt;</span> '<span class="hl-value">z</span>'; <span class="hl-comment">// -1</span>
</pre>
<p>Strangely enough, when comparing letter casing, the lowercase letter is considered the highest.
There's a simple explanation though.
String comparison is done by comparing character per character.
As soon as a character differs, their ASCII value is compared.
Because lowercase letters come after uppercase ones in the ASCII table, they have a higher value.</p>
<h3 id="comparing-objects"><a href="#comparing-objects" class="heading-anchor">#</a> Comparing objects</h3>
<p>The spaceship operator can almost compare anything, even objects.
The way objects are compared is based on the kind of object.
Built-in PHP classes can define their own comparison,
while userland objects are compared based on their attributes and values.</p>
<p>When would you want to compare objects you ask?
Well, there's actually a very obvious example: dates.</p>
<pre><span class="hl-variable">$dateA</span> = <span class="hl-type">DateTime</span>::<span class="hl-property">createFromFormat</span>('<span class="hl-value">Y-m-d</span>', '<span class="hl-value">2000-02-01</span>');

<span class="hl-variable">$dateB</span> = <span class="hl-type">DateTime</span>::<span class="hl-property">createFromFormat</span>('<span class="hl-value">Y-m-d</span>', '<span class="hl-value">2000-01-01</span>');

<span class="hl-variable">$dateA</span> <span class="hl-operator">&lt;=&gt;</span> <span class="hl-variable">$dateB</span>; <span class="hl-comment">// Returns 1</span>
</pre>
<p>Of course, comparing dates is just one example, but a very useful one nevertheless.</p>
<h3 id="sort-functions"><a href="#sort-functions" class="heading-anchor">#</a> Sort functions</h3>
<p>One great use for this operator, is to sort arrays.
There are quite <a target="_blank" href="http://php.net/manual/en/array.sorting.php">a few ways</a> to sort an array in PHP,
and some of these methods allow a user defined sort function.
This function has to compare two elements, and return <code>1</code>, <code>0</code>, or <code>-1</code> based on their position.</p>
<p>An excellent use case for the spaceship operator!</p>
<pre><span class="hl-variable">$array</span> = [5, 1, 6, 3];

<span class="hl-property">usort</span>(<span class="hl-variable">$array</span>, <span class="hl-keyword">function</span> (<span class="hl-injection">$a, $b</span>) {
    <span class="hl-keyword">return</span> <span class="hl-variable">$a</span> <span class="hl-operator">&lt;=&gt;</span> <span class="hl-variable">$b</span>;
});

<span class="hl-comment">// $array = [1, 3, 5, 6];</span>
</pre>
<p>To sort descending, you can simply invert the comparison result:</p>
<pre><span class="hl-property">usort</span>(<span class="hl-variable">$array</span>, <span class="hl-keyword">function</span> (<span class="hl-injection">$a, $b</span>) {
    <span class="hl-keyword">return</span> -(<span class="hl-variable">$a</span> <span class="hl-operator">&lt;=&gt;</span> <span class="hl-variable">$b</span>);
});

<span class="hl-comment">// $array = [6, 5, 3, 1];</span>
</pre>
<p>Hi there, thanks for reading! I hope this blog post helped you!
If you'd like to contact me, you can do so on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>.
I always love to chat!</p>
 ]]></summary>

                <updated>2020-07-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Why we need named arguments in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/why-we-need-named-params-in-php"/>

                <id>https://www.stitcher.io/blog/why-we-need-named-params-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>There's a new RFC in town for <a href="/blog/new-in-php-8">PHP 8</a>, and its name is the <a target="_blank" href="https://wiki.php.net/rfc/named_params">named arguments RFC</a>.</p>
<p>If you're eligible to vote, or know someone who can: I want to ask you to take five minutes to read this, and to be clear up front: I want you to vote yes.</p>
<p>Here's why from the point of view of a userland developer, both for client projects <em>and</em> <a target="_blank" href="https://spatie.be/open-source">open source</a>.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="as-an-oss-maintainer"><a href="#as-an-oss-maintainer" class="heading-anchor">#</a> As an OSS maintainer</h2>
<p>The main argument against named arguments — the PHP 8 puns continue — is that they would make maintaining open source software a pain: changing the name of an argument would become a breaking change.</p>
<p>Here's what that means. Imagine an open source package which has this function as part of its public API:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">toMediaCollection</span>(<span class="hl-injection"><span class="hl-type">string</span> $collection, <span class="hl-type">string</span> $disk = <span class="hl-keyword">null</span></span>);
</pre>
<p>Named parameters would allow to call this function like so:</p>
<pre><span class="hl-variable">$pendingMedia</span>
    -&gt;<span class="hl-property">toMediaCollection</span>(<span class="hl-property">collection</span>: '<span class="hl-value">downloads</span>', <span class="hl-property">disk</span>: '<span class="hl-value">s3</span>');
</pre>
<p>If, for some reason, the open source maintainer would want to change the name of the <code>$collection</code> or <code>$disk</code> variables, they would have to tag a major release, because named arguments would make that a breaking change.</p>
<p>Now, let me tell you something from my point of view as an open source maintainer: this rarely happens.</p>
<p>As a matter of fact, I can only think of a handful occurrences. And the only reason we decided to do renames on those occurrences, was because we were already working on a new major version and we figured we might as well improve the naming a little bit while we were at it.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>I'm not the only one with that opinion by the way, Nicolas Grekas is amongst the people voting yes, and he knows a thing or two about OSS development. Oh and here's <a target="_blank" href="https://twitter.com/themsaid/status/1281819955231690753?s=20">Mohamed Said</a>, one of the core maintainers of Laravel:</p>
<blockquote>
<p>I've been working at Laravel for 4 years now and I rarely find us wanting to change argument names in a refactor. We either add or remove arguments, but I'd say we never had to change names.</p>
</blockquote>
<p>Actually that's an interesting thought: argument lists already <em>are</em> prone to breaking backwards compatibility: changing the order of arguments already is a breaking change! And we're dealing with that just fine now, aren't we?</p>
<p>Now even <em>if</em> you, as an open source maintainer, don't want to take the responsibility of making sure argument names don't change between major releases, here's what you do: tell your users you won't actively support named arguments, and using them is at their own risk. Just put this in the README:</p>
<pre>**Heads up**: this package doesn't actively support named arguments. 
This means that argument names might change in minor and patch releases. 
You can use them, but at your own risk.
</pre>
<p>Don't deny all PHP developers this flexibility, because you're afraid of a slight chance it might break something somewhere in the far far future. Don't be afraid.</p>
<h2 id="as-a-programmer-doing-client-work"><a href="#as-a-programmer-doing-client-work" class="heading-anchor">#</a> As a programmer doing client work</h2>
<p>Another argument is that this RFC would encourage bad API design. It would encourage people to write large method definitions, which in turn often indicates a code smell.</p>
<p>I as well can come up with lots of examples that aren't a good fit for named parameters. But that doesn't mean there are no use cases for them at all! Have you heard of <a href="/blog/laravel-beyond-crud-02-working-with-data">data transfer objects</a> or value objects before? If you're following this blog, chances are you have.</p>
<p>I'm not going to copy my writing on them in this post, but I can summarise the main thought behind them: treat data as a first class citizen of your application, model them with objects. For example: an address has a street, number, postal code, city, country, sometimes even more than that. That data should be represented by a strongly typed object in PHP, and not passed between contexts as an array full of random stuff, its constructor would look like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Address</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $street,
        <span class="hl-type">string</span> $number,
        <span class="hl-type">string</span> $postal,
        <span class="hl-type">string</span> $city,
        <span class="hl-type">string</span> $country,
    </span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>DTOs and VOs are valid cases where these kinds of large constructors are allowed, it's no code smell at all. I had a quick look at <a href="/blog/a-project-at-spatie">an old project</a> of ours, at the time of tracking its stats, it already had 63 DTO classes, and the project was far from finished at that point!</p>
<p>Large constructors happen, and named parameters would not only add more clarity, but also offer the flexibility of changing the parameter order after the fact, without having to worry about fixing the order at all.</p>
<p>Take our <code>Address</code> object, for example. Let's say we need to support number suffixes. We can add that argument without having to worry about the order that other places called it:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Address</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $street,
        <span class="hl-type">string</span> $number,
        <span class="hl-type">string</span> $numberSuffix,
        <span class="hl-type">string</span> $postal,
        <span class="hl-type">string</span> $city,
        <span class="hl-type">string</span> $country,
    </span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>Sure the calling site still need to add it, but at least you don't have to worry about micro managing the parameter order anymore.</p>
<p>But what if users decide to use ordered arguments instead? You'd need some way to ensure named arguments are used in these cases. The answer is surprisingly dull: establish conventions with your team, and optionally enforce them with tools like phpcs.</p>
<p>Yes, ideally, we'd want the language to prevent us from any possible misstep; but that simply isn't a realistic expectation. To me, that still isn't an argument for voting against this RFC. I've been working with teams of developers for years now, and project conventions need to be established anyway. They work just fine.</p>
<h2 id="dealing-with-php's-own-legacy"><a href="#dealing-with-php's-own-legacy" class="heading-anchor">#</a> Dealing with PHP's own legacy</h2>
<p>Pop quiz! How to set a cookie without a value, which expires two hours from now?</p>
<p>Did you look up the docs or consult your IDE?</p>
<p>That's fine, it's a confusing function after all. Named arguments can offer a little more clarity though. Compare the two following notations:</p>
<pre><span class="hl-property">setcookie</span>(
    '<span class="hl-value">test</span>', 
    '<span class="hl-value"></span>', 
    <span class="hl-property">time</span>() + 60 * 60 * 2
);
</pre>
<p>Or:</p>
<pre><span class="hl-property">setcookie</span>(
    <span class="hl-property">name</span>: '<span class="hl-value">test</span>',
    <span class="hl-property">expires</span>: <span class="hl-property">time</span>() + 60 * 60 * 2,
);
</pre>
<p>I know which I would pick, everyone benefits from named arguments in this case. And since chances are slim that PHP's internal functions will change anytime soon, it's another very good reason to add them.</p>
<h2 id="looking-at-other-languages"><a href="#looking-at-other-languages" class="heading-anchor">#</a> Looking at other languages</h2>
<p>Lastly, let's face the simple facts: several other languages — many also focused on web development — already support named arguments. Some deal with them in slightly different ways, but the base concept is known to many other programmers, and it's a good thing.</p>
<p>Here are a few examples:</p>
<ul>
<li>
<a target="_blank" href="https://treyhunner.com/2018/04/keyword-arguments-in-python/">Python</a>
</li>
<li>
<a target="_blank" href="https://thoughtbot.com/blog/ruby-2-keyword-arguments">Ruby</a>
</li>
<li>
<a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments">C#</a>
</li>
<li>
<a target="_blank" href="https://useyourloaf.com/blog/swift-named-parameters/">Swift</a>
</li>
<li>
<a target="_blank" href="https://kotlinlang.org/docs/reference/functions.html#named-arguments">Kotlin</a>
</li>
</ul>
<p>So let's not spread fear about harder-to-maintain code, or open source software that will become a nightmare to maintain. Named arguments are a known feature in the larger software community, and have proven their worth. No need for hypothetical problems, we will manage.</p>
<hr />
<p>By the way the vote will pass at this point! You can read about <a href="/blog/php-8-named-arguments">named arguments in depth</a> on this blog!</p>
 ]]></summary>

                <updated>2020-07-11T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: match or switch? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-8-match-or-switch"/>

                <id>https://www.stitcher.io/blog/php-8-match-or-switch</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8 introduces the new <code>match</code> expression. A powerful feature that will often be the better choice to using <code>switch</code>. So what exactly are the differences?</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's start by comparing the two. Here's a classic <code>switch</code> example:</p>
<pre><span class="hl-keyword">switch</span> (<span class="hl-variable">$statusCode</span>) {
    <span class="hl-keyword">case</span> <span class="hl-property">200</span>:
    <span class="hl-keyword">case</span> <span class="hl-property">300</span>:
        <span class="hl-variable">$message</span> = <span class="hl-keyword">null</span>;
        <span class="hl-keyword">break</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">400</span>:
        <span class="hl-variable">$message</span> = '<span class="hl-value">not found</span>';
        <span class="hl-keyword">break</span>;
    <span class="hl-keyword">case</span> <span class="hl-property">500</span>:
        <span class="hl-variable">$message</span> = '<span class="hl-value">server error</span>';
        <span class="hl-keyword">break</span>;
    <span class="hl-property">default</span>:
        <span class="hl-variable">$message</span> = '<span class="hl-value">unknown status code</span>';
        <span class="hl-keyword">break</span>;
}
</pre>
<p>Here's its <code>match</code> equivalent:</p>
<pre><span class="hl-variable">$message</span> = <span class="hl-keyword">match</span> (<span class="hl-variable">$statusCode</span>) {
    200, 300 =&gt; <span class="hl-keyword">null</span>,
    400 =&gt; '<span class="hl-value">not found</span>',
    500 =&gt; '<span class="hl-value">server error</span>',
    <span class="hl-keyword">default</span> =&gt; '<span class="hl-value">unknown status code</span>',
};
</pre>
<p>First of all, the <code>match</code> expression is significantly shorter:</p>
<ul>
<li>it doesn't require a <code>break</code> statement</li>
<li>it can combine different arms into one using a comma</li>
<li>it returns a value, so you only have to assign value once</li>
</ul>
<p>That's already quite a lot, but there's even more to it!</p>
<h2 id="no-type-coercion"><a href="#no-type-coercion" class="heading-anchor">#</a> No type coercion</h2>
<p><code>match</code> will do strict type checks instead of loose ones. It's like using <code>===</code> instead of <code>==</code>.
People will probably disagree whether that's a good thing or not, but that's a <a href="/blog/tests-and-types">topic on its own</a>.</p>
<pre><span class="hl-variable">$statusCode</span> = '<span class="hl-value">200</span>';

<span class="hl-variable">$message</span> = <span class="hl-keyword">match</span> (<span class="hl-variable">$statusCode</span>) {
    200 =&gt; <span class="hl-keyword">null</span>,
    <span class="hl-keyword">default</span> =&gt; '<span class="hl-value">unknown status code</span>',
};

<span class="hl-comment">// $message = 'unknown status code'</span>
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="unknown-values-cause-errors"><a href="#unknown-values-cause-errors" class="heading-anchor">#</a> Unknown values cause errors</h2>
<p>If you forget to check for a value, and when there's no <code>default</code> arm specified, PHP will throw an <code>UnhandledMatchError</code> exception. Again more strictness, but it will prevent subtle bugs from going unnoticed.</p>
<pre><span class="hl-variable">$statusCode</span> = 400;

<span class="hl-variable">$message</span> = <span class="hl-keyword">match</span> (<span class="hl-variable">$statusCode</span>) {
    200 =&gt; '<span class="hl-value">perfect</span>',
};

<span class="hl-comment">// UnhandledMatchError</span>
</pre>
<h2 id="only-single-line-expressions,-for-now"><a href="#only-single-line-expressions,-for-now" class="heading-anchor">#</a> Only single-line expressions, for now</h2>
<p>Just like <a href="/blog/short-closures-in-php">short closures</a>, you can only write one expression. Expression blocks will probably get added at one point, but it's still not clear when exactly.</p>
<h2 id="combining-conditions"><a href="#combining-conditions" class="heading-anchor">#</a> Combining conditions</h2>
<p>You already noticed the lack of <code>break</code>? This also means <code>match</code> doesn't allow for fallthrough conditions, like the two combined <code>case</code> lines in the first <code>switch</code> example. On the other hand though, you can combine conditions on the same line, separated by commas.</p>
<p>So you have the same functionality as switch in this regards, but with less writing, and less ways to screw up. Win-win!</p>
<pre><span class="hl-variable">$message</span> = <span class="hl-keyword">match</span> (<span class="hl-variable">$statusCode</span>) {
    200, 300, 301, 302 =&gt; '<span class="hl-value">combined expressions</span>',
};
</pre>
<h2 id="complex-conditions-and-performance"><a href="#complex-conditions-and-performance" class="heading-anchor">#</a> Complex conditions and performance</h2>
<p>During the RFC discussion, some people suggested the following pattern as an argument against adding the <code>match</code> expression:</p>
<pre><span class="hl-variable">$message</span> = [
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">matchesRegex</span>(<span class="hl-variable">$line</span>) =&gt; '<span class="hl-value">match A</span>',
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">matchesOtherRegex</span>(<span class="hl-variable">$line</span>) =&gt; '<span class="hl-value">match B</span>',
][<span class="hl-variable">$line</span>] ?? '<span class="hl-value">no match</span>';
</pre>
<p>There's one big caveat though: this technique will execute all regex functions first, decreasing performance. A good argument for <code>match</code>.</p>
<h2 id="throwing-exceptions"><a href="#throwing-exceptions" class="heading-anchor">#</a> Throwing exceptions</h2>
<p>Finally, because of <a href="/blog/new-in-php-8#throw-expression-rfc">throw expressions in PHP 8</a>, it's also possible to directly throw from an arm, if you'd like to.</p>
<pre><span class="hl-variable">$message</span> = <span class="hl-keyword">match</span> (<span class="hl-variable">$statusCode</span>) {
    200 =&gt; <span class="hl-keyword">null</span>,
    500 =&gt; <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">ServerError</span>(),
    <span class="hl-keyword">default</span> =&gt; '<span class="hl-value">unknown status code</span>',
};
</pre>
<h2 id="pattern-matching"><a href="#pattern-matching" class="heading-anchor">#</a> Pattern matching</h2>
<p>Ok, there's one more thing: pattern matching. It's a technique used in other programming languages, to allow complexer matching than simple values. Think of it as regex, but for variables instead of text.</p>
<p>Pattern matching isn't supported right now, because it's quite a complex feature, but Ilija Tovilo, the <a target="_blank" href="https://wiki.php.net/rfc/match_expression_v2">RFC author</a> did mention it as a possible future feature. Something to look out for!</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="so,-switch-or-match?"><a href="#so,-switch-or-match?" class="heading-anchor">#</a> So, switch or match?</h2>
<p>If I'd need to summarise the <code>match</code> expression in one sentence, I'd say it's the stricter and more modern version of it's little <code>switch</code> brother.</p>
<p>There are some cases — <em>see what I did there?</em> — where <code>switch</code> will offer more flexibility, especially with multiline code blocks. However, the strictness of the <code>match</code> operator is appealing, and the perspective of pattern matching would be a game-changer for PHP.</p>
<p>I admit I never wrote a <code>switch</code> statement in the past years because of its many quirks; quirks that <code>match</code> actually solve. So while it's not perfect yet, there are use cases that I can think of, where <code>match</code> would be a good… match.</p>
<p>What's <a target="_blank" href="https://twitter.com/brendt_gd">your opinion</a>?</p>
 ]]></summary>

                <updated>2020-07-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: JIT performance in real-life web applications ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/jit-in-real-life-web-applications"/>

                <id>https://www.stitcher.io/blog/jit-in-real-life-web-applications</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>For those interested in <a href="/blog/php-jit">the JIT in PHP 8</a>, I did some benchmarks for you in real-world web application scenario. Be aware that these benchmarks don't say anything about whether the JIT is useful or not, they only show whether it can improve the performance of your average web application, or not.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="setup"><a href="#setup" class="heading-anchor">#</a> Setup</h2>
<p>Let's set the scene first. These benchmarks were run on my local machine. As so, they don't say anything about absolute performance gains, I'm only interested in making conclusions about the relative impact the JIT has on real-life code.</p>
<p>I'll be running PHP FPM, configured to spawn 20 child processes, and I'll always make sure to only run 20 concurrent requests at once, just to eliminate any extra performance hits on the FPM level. Sending these requests is done using the following command, with ApacheBench:</p>
<pre>ab -n 100 -c 20 -l http://aggregate.stitcher.io.test:8081/discover
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="jit-setup"><a href="#jit-setup" class="heading-anchor">#</a> JIT Setup</h2>
<p>With the project in place, let's configure the JIT itself. The JIT is enabled by specifying the <code>opcache.jit_buffer_size</code> option in <code>php.ini</code>. If this directive is excluded, the default value is set to 0, and the JIT won't run.</p>
<pre>opcache.jit_buffer_size=100M
</pre>
<p>You'll also want to set a JIT mode, which will determine how the JIT will monitor and react to hot parts of your code. You'll need to use the <code>opcache.jit</code> option. Its default is set to <code>tracing</code>, but you can override it using <code>function</code>:</p>
<pre>opcache.jit=function
; opcache.jit=tracing
</pre>
<p>In our real-life benchmarks, I'll compare both modes with each other.
So let's start benchmarking!</p>
<h2 id="establishing-a-baseline"><a href="#establishing-a-baseline" class="heading-anchor">#</a> Establishing a baseline</h2>
<p>First it's best to establish whether the JIT is working properly or not. We know from the RFC that it does have a significant impact on calculating a fractal. So let's start with that example. I copied the mandelbrot example from the RFC, and accessed it via the same HTTP application I'll run the next benchmarks on:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>()
{
    <span class="hl-keyword">for</span> (<span class="hl-variable">$y</span> = -39; <span class="hl-variable">$y</span> &lt; 39; <span class="hl-variable">$y</span>++) {
        <span class="hl-property">printf</span>(&quot;<span class="hl-value">\n</span>&quot;);

        <span class="hl-keyword">for</span> (<span class="hl-variable">$x</span> = -39; <span class="hl-variable">$x</span> &lt; 39; <span class="hl-variable">$x</span>++) {
            <span class="hl-variable">$i</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">mandelbrot</span>(
                <span class="hl-variable">$x</span> / 40.0,
                <span class="hl-variable">$y</span> / 40.0
            );

            <span class="hl-keyword">if</span> (<span class="hl-variable">$i</span> == 0) {
                <span class="hl-property">printf</span>(&quot;<span class="hl-value">*</span>&quot;);
            } <span class="hl-keyword">else</span> {
                <span class="hl-property">printf</span>(&quot;<span class="hl-value"> </span>&quot;);
            }
        }
    }

    <span class="hl-property">printf</span>(&quot;<span class="hl-value">\n</span>&quot;);
}

<span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">mandelbrot</span>(<span class="hl-injection">$x, $y</span>)
{
    <span class="hl-variable">$cr</span> = <span class="hl-variable">$y</span> - 0.5;
    <span class="hl-variable">$ci</span> = <span class="hl-variable">$x</span>;
    <span class="hl-variable">$zi</span> = 0.0;
    <span class="hl-variable">$zr</span> = 0.0;
    <span class="hl-variable">$i</span> = 0;

    <span class="hl-keyword">while</span> (1) {
        <span class="hl-variable">$i</span>++;
        
        <span class="hl-variable">$temp</span> = <span class="hl-variable">$zr</span> * <span class="hl-variable">$zi</span>;
        
        <span class="hl-variable">$zr2</span> = <span class="hl-variable">$zr</span> * <span class="hl-variable">$zr</span>;
        <span class="hl-variable">$zi2</span> = <span class="hl-variable">$zi</span> * <span class="hl-variable">$zi</span>;
        
        <span class="hl-variable">$zr</span> = <span class="hl-variable">$zr2</span> - <span class="hl-variable">$zi2</span> + <span class="hl-variable">$cr</span>;
        <span class="hl-variable">$zi</span> = <span class="hl-variable">$temp</span> + <span class="hl-variable">$temp</span> + <span class="hl-variable">$ci</span>;

        <span class="hl-keyword">if</span> (<span class="hl-variable">$zi2</span> + <span class="hl-variable">$zr2</span> &gt; 16) {
            <span class="hl-keyword">return</span> <span class="hl-variable">$i</span>;
        }

        <span class="hl-keyword">if</span> (<span class="hl-variable">$i</span> &gt; 5000) {
            <span class="hl-keyword">return</span> 0;
        }
    }
}
</pre>
<p>After running <code>ab</code> for a few hundred requests, we can see the results:</p>
<table>
<tr class="table-head">
    <td></td>
    <td class="right">requests/second (more is better)</td>
</tr>
<tr>
    <td>Mandelbrot without JIT</td>
    <td class="right">3.60</td>
</tr>
<tr>
    <td>Mandelbrot with tracing JIT</td>
    <td class="right">41.36</td>
</tr>
</table>
<p>Great, it looks like the JIT is working! That's even a ten times performance increase! Having verified it works as expected, let's move on to our first real-life comparison. We're going to compare no JIT with the function and tracing JIT; using 100MB of memory. The page we're going to benchmark shows an overview of posts, so there's some recursion happening. We're also touching several core parts of Laravel as well: routing, the dependency container, as well as the ORM layer.</p>
<div class="sidenote">
<h2>Side note:</h2>
<p>If you want to verify whether the JIT is running, you can use <code>opcache_get_status()</code>, it has a <code>jit</code> entry which lists all relevant information:</p>
<pre><span class="hl-property">dd</span>(<span class="hl-property">opcache_get_status</span>()['<span class="hl-value">jit</span>']);

<span class="hl-comment">// array:7 [▼</span>
<span class="hl-comment">//   &quot;enabled&quot; =&gt; true</span>
<span class="hl-comment">//   &quot;on&quot; =&gt; true</span>
<span class="hl-comment">//   &quot;kind&quot; =&gt; 5</span>
<span class="hl-comment">//   &quot;opt_level&quot; =&gt; 4</span>
<span class="hl-comment">//   &quot;opt_flags&quot; =&gt; 6</span>
<span class="hl-comment">//   &quot;buffer_size&quot; =&gt; 104857584</span>
<span class="hl-comment">//   &quot;buffer_free&quot; =&gt; 104478688</span>
<span class="hl-comment">// ]</span>
</pre>
</div>
<table>
<tr class="table-head">
    <td></td>
    <td class="right">requests/second (more is better)</td>
</tr>
<tr>
    <td>No JIT</td>
    <td class="right">63.56</td>
</tr>
<tr>
    <td>Function JIT</td>
    <td class="right">66.32</td>
</tr>
<tr>
    <td>tracing JIT</td>
    <td class="right">69.45</td>
</tr>
</table>
<p>Here we see the results: enabling the JIT only has a slight improvement. In fact, running the benchmarks over and over, the results differ slightly every time: I've even seen cases where a JIT enabled run performs worse than the non JIT'ed version. Before drawing final conclusions, let's bump the memory buffer limit. We'll give the JIT a little more room to breathe with 500MB of memory instead of 100MB.</p>
<table>
<tr class="table-head">
    <td></td>
    <td class="right">requests/second (more is better)</td>
</tr>
<tr>
    <td>No JIT</td>
    <td class="right">71.69</td>
</tr>
<tr>
    <td>Function JIT</td>
    <td class="right">72.82</td>
</tr>
<tr>
    <td>Tracing JIT</td>
    <td class="right">70.11</td>
</tr>
</table>
<p>As you can see: a case of the JIT performing worse. Like I said at the beginning of this post: I want to measure the relative impact the JIT has on real-life web projects. It's clear from these tests that sometimes there might be benefits, but it's in no way as noticeable as the fractal example we started out with. I admit I'm not really surprised by that. Like I wrote before: there's very little hot code to be optimised in real-life applications, we're only rarely doing fractal-like computations.</p>
<p>So am I saying there's no need for the JIT? Not quite, I think the JIT can open up new areas for PHP: areas where complex computations do benefit from JIT'ed code. I'm thinking about machine learning, AI, stuff like that. The JIT <em>might</em> give opportunities to the PHP community that didn't exist yet, but it's unclear to say anything with certainty at this point.</p>
<hr />
<p>So, that concludes my JIT testing. As expected: the JIT probably won't have a significant impact on web applications, at least not right now.</p>
<p>I won't discuss my thoughts on whether the JIT itself is a good addition or not in this post, let's have those discussions together <a target="_blank" href="https://news.ycombinator.com/item?id=23721344">over here</a>!</p>
 ]]></summary>

                <updated>2020-07-02T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Braille, and the evolution of software development ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/braille-and-the-history-of-software"/>

                <id>https://www.stitcher.io/blog/braille-and-the-history-of-software</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Back in 1785, a Frenchman named <a target="_blank" href="https://en.wikipedia.org/wiki/Valentin_Ha%C3%BCy">Valentin Haüy</a> founded the Institute for Blind Youth in Paris. Several years before, he was touched seeing blind children on the streets, cast out by society. They would never be able to receive education, until Haüy came along.</p>
<p>Besides managing the school, he was also a translator for the King of France, Louis XVI. From time to time, he received fancy invitations from the royal family, which had embossed letters on them. It didn't take long before Haüy wondered whether these raised letters could be a way of teaching his pupils to read, via touch.</p>
<p>In 1786, he printed his first book with raised letters: it was readable by touch and by sight, so both blind and seeing people could read it.</p>
<p><img src="/resources/img/blog/braille/hauy.jpg" srcset="/resources/img/blog/braille/hauy-747x43.jpg 747w, /resources/img/blog/braille/hauy-334x19.jpg 334w, /resources/img/blog/braille/hauy-578x33.jpg 578w, /resources/img/blog/braille/hauy-668x38.jpg 668w, /resources/img/blog/braille/hauy-472x27.jpg 472w" sizes="" alt=""></img></p>
<p>It was a revolutionary idea, but with its downsides: the fancy and curly fonts of that time made it very hard for blind people to distinguish between letters; furthermore, it was also rather expensive to print such books.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Fast forward to 1821, when a French army captain came to the Institute for Blind Youth; now called National Institute for the Young Blind, because of the French revolution. This captain gave a lecture about a technique used in the army for nocturnal writing, in other words: blind writing. They used a 12-dot system to pass messages during the night.</p>
<p>In that lecture was a 12-year old boy, named <a target="_blank" href="https://en.wikipedia.org/wiki/Louis_Braille">Louis Braille</a>.</p>
<p>You can probably guess what came next: inspired by the army's nocturnal writing style, Louis came up with a 6-dot system to represent the letters of the alphabet.</p>
<p>It turned out these dots were significantly more easy to distinguish by touch than Haüy's embossed letters.
It was a system built upon previous iterations of the same idea, but most importantly it was invented by someone who was blind himself, who understood the problem that needed to be solved first hand.</p>
<p>It shouldn't be a surprise: this technique grew rapidly in popularity among the blind.</p>
<p>While Braille was still developing his system, an American named <a target="_blank" href="https://en.wikipedia.org/wiki/Samuel_Gridley_Howe">Samuel Howe</a> came to visit France. He was going to start the first school for blind children in the U.S. and wanted to do practical research. He took the original idea of Haüy's embossed letters, and made a new font for it; a font that would be less "artsy" and more "practical" to read. It was called Boston Line Type.</p>
<p><img src="/resources/img/blog/braille/boston.jpg" srcset="/resources/img/blog/braille/boston-536x268.jpg 536w, /resources/img/blog/braille/boston-758x379.jpg 758w, /resources/img/blog/braille/boston-929x464.jpg 929w, /resources/img/blog/braille/boston-1073x536.jpg 1073w, /resources/img/blog/braille/boston-1200x600.jpg 1200w" sizes="" alt=""></img></p>
<p>By the time the system was introduced in the U.S., blind U.S. citizens also heard of braille. Upper management resisted though: it was a European invention, for sure Boston Line Type would be the superior system. It was still readable by both blind and seeing people, and was more clear than Haüy's method.</p>
<p>Despite this reasoning, perhaps even a bit of American pride, it was clear that Boston Line Type would never be able to surpass braille.</p>
<p>Still, schools in the U.S. couldn't live with using the European standard. So what did they do instead? Two or three variations of braille were created over a course of 50 years; all based on the same principle, but all different in their implementation.</p>
<p>This went on until 1932, until braille finally became the accepted standard, probably what most blind people wanted all along. A period that took more than a century; it was later poetically called "The war of the Dots".</p>
<p><img src="/resources/img/blog/braille/braille.png" srcset="/resources/img/blog/braille/braille-1023x349.png 1023w, /resources/img/blog/braille/braille-1447x493.png 1447w, /resources/img/blog/braille/braille-723x246.png 723w, /resources/img/blog/braille/braille-1253x427.png 1253w, /resources/img/blog/braille/braille-1618x552.png 1618w" sizes="" alt=""></img></p>
<hr />
<p>Let's talk about software development, shall we? There are one or two parallels with the history of braille that I think we can learn valuable lessons from.</p>
<p>First of all: we shouldn't always aim to please everyone. Both Haüy's method and Boston Line Type aimed to write text that was accessible both for blind and seeing people. The end result was something suboptimal for both groups.</p>
<p>Sometimes it's better, also in software development, to focus on that one specific problem, and find the best solution for it, instead of trying to solve everything. It's better to focus on a specific problem, instead of a generalised one.</p>
<p>Second: it took braille more than 100 years to become the standard, even though it was clear from the start that it was a great system. Software development is still in its infancy. I don't think there will still be 200 different frameworks solving the same problem in 50 years.</p>
<p>Maybe there will even be only a handful of languages, one or two per field: web development, mobile apps, desktop apps, machine learning, etc. Each field will evolve towards the best solution, and we might already know that solution today, but aren't ready to accept it yet.</p>
<p>Braille is just one example of how much time it takes to optimise a process or system. Let's not fool ourselves thinking we already know the best solutions for our problems in software development. Let's keep that in mind when were advocating for the next big thing. Let's stay humble and realise we're only playing a small part in history.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-06-27T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Abstract resources in Laravel Nova ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/abstract-resources-in-laravel-nova"/>

                <id>https://www.stitcher.io/blog/abstract-resources-in-laravel-nova</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>One of the major coding architecture strategies I use when building a complex Laravel Nova project
is the ability to have an abstract resource class.</p>
<p><em>Before starting by the way, if you want deep dive in Nova, I suggest you subscribe to updates
in my upcoming course <a target="_blank" href="https://www.masteringnova.com">Mastering Nova</a> that will be released
this mid-summer!</em></p>
<hr />
<p>An abstract resource class will inherit the base <code>Resource</code> class. This allows you to
override specific methods to add functionality on your real resource classes.</p>
<p>In the end, any method that you improve in your custom base class, will be available on your model resources.
I'll show you how to create the abstract resource, and then we'll at concrete improvements.</p>
<p>We start by creating a file AbstractResource.php inside <code>app/Nova</code>, like this:</p>
<pre>app/
  Nova/
     AbstractResource.php
</pre>
<p>At first, the <code>AbstractResource</code> looks like this:</p>
<pre><span class="hl-keyword">namespace</span> <span class="hl-type">App\Nova</span>;

<span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">AbstractResource</span> <span class="hl-keyword">extends</span> <span class="hl-type">Resource</span>
{
}
</pre>
<p>Next, in your Resource classes just inherit from this abstract Resource instead
of the Nova Resource one:</p>
<pre><span class="hl-keyword">namespace</span> <span class="hl-type">App\Nova</span>;

<span class="hl-keyword">use</span> <span class="hl-type">App\Nova\AbstractResource</span>;

<span class="hl-keyword">class</span> <span class="hl-type">Review</span> <span class="hl-keyword">extends</span> <span class="hl-type">AbstractResource</span>
{
    <span class="hl-comment">//</span>
}
</pre>
<hr />
<p>So, let's look at some examples of improvements you can add to your new
abstract resource.</p>
<h3 id="default-sorting"><a href="#default-sorting" class="heading-anchor">#</a> Default sorting</h3>
<p>On your abstract Resource write this code:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">indexQuery</span>(<span class="hl-injection"><span class="hl-type">NovaRequest</span> $request, $query</span>)
{
    <span class="hl-variable">$uriKey</span> = <span class="hl-keyword">static</span>::<span class="hl-property">uriKey</span>();
    
    <span class="hl-keyword">if</span> ((<span class="hl-variable">$request</span>-&gt;<span class="hl-property">orderByDirection</span> ?? <span class="hl-keyword">null</span>) !== <span class="hl-keyword">null</span>) {
        <span class="hl-keyword">return</span> <span class="hl-variable">$query</span>;
    }
    
    <span class="hl-keyword">if</span> (! <span class="hl-keyword">empty</span>(<span class="hl-keyword">static</span>::<span class="hl-property">$indexDefaultOrder</span>)) {
        <span class="hl-variable">$query</span>-&gt;<span class="hl-property">getQuery</span>()-&gt;<span class="hl-property">orders</span> = [];

        <span class="hl-keyword">return</span> <span class="hl-variable">$query</span>-&gt;<span class="hl-property">orderBy</span>(
            <span class="hl-property">key</span>(<span class="hl-keyword">static</span>::<span class="hl-property">$indexDefaultOrder</span>), 
            <span class="hl-property">reset</span>(<span class="hl-keyword">static</span>::<span class="hl-property">$indexDefaultOrder</span>)
        );
    }
}
</pre>
<p>Then on your model resource:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-property">$indexDefaultOrder</span> = ['<span class="hl-value">email</span>' =&gt; '<span class="hl-value">asc</span>'];
</pre>
<p>This will sort your index query by "email, asc" in case there is not a pre-selected
sorting order.</p>
<h3 id="search-relationships"><a href="#search-relationships" class="heading-anchor">#</a> Search relationships</h3>
<p>If you have a relationship field, you might have seen that you cannot use it
to search on your Resource search field. In that case, you can use the
<code>titasgailius/search-relations</code> <a target="_blank" href="https://github.com/TitasGailius/nova-search-relations">package</a>.</p>
<p>To install it, just import it via Composer:</p>
<pre>composer require titasgailius/search-relations
</pre>
<p>Then in your Abstract Resource, you can add it like:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Titasgailius\SearchRelations\SearchesRelations</span>;

<span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">AbstractResource</span> <span class="hl-keyword">extends</span> <span class="hl-type">Resource</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">SearchesRelations</span>;
}
</pre>
<p>Henceforth, on your model resources, you can simply add:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-property">$searchRelations</span> = [
    '<span class="hl-value">user</span>' =&gt; ['<span class="hl-value">username</span>', '<span class="hl-value">email</span>'],
];
</pre>
<p>where the key is your relationship name, and then an array of searchable column values. Therefore you can now search on your relationship columns!</p>
<h3 id="sharing-cards,-lenses,-actions-and-filters"><a href="#sharing-cards,-lenses,-actions-and-filters" class="heading-anchor">#</a> Sharing Cards, Lenses, Actions and Filters</h3>
<p>Let's say you would like to have a generic card that shows information about when
was the last time your current resource was updated, and some other extra information
regarding your resource; or an action that actually will change status on models
that share a <code>status_type</code> column.</p>
<p>All of this functionality can be shared between model resources.</p>
<p>As an example, let's say you want to add a new Card to all of the model resources that share your abstract resource, you can do it like:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">cards</span>(<span class="hl-injection"><span class="hl-type">Request</span> $request</span>){
    <span class="hl-keyword">return</span> [
        <span class="hl-keyword">new</span> <span class="hl-type">ResourceInformation</span>(
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">getCurrentResourceInstance</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">getModelInstance</span>())
        ),
    ];
}

<span class="hl-keyword">protected</span> <span class="hl-keyword">function</span> <span class="hl-property">getModelInstance</span>()
{
    <span class="hl-variable">$resourceKey</span> = <span class="hl-property">explode</span>('<span class="hl-value">/</span>', <span class="hl-property">request</span>()-&gt;<span class="hl-property">path</span>())[1];

    <span class="hl-variable">$resourceClass</span> = <span class="hl-type">Nova</span>::<span class="hl-property">resourceForKey</span>(<span class="hl-variable">$resourceKey</span>);

    <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-variable">$resourceClass</span>::<span class="hl-property">$model</span>;
}
</pre>
<p>and in your model Resource:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">cards</span>(<span class="hl-injection"><span class="hl-type">Request</span> $request</span>)
{
    <span class="hl-keyword">return</span> <span class="hl-property">array_merge</span>(
        [<span class="hl-comment">/* your cards */</span>], 
        <span class="hl-keyword">parent</span>::<span class="hl-property">cards</span>(<span class="hl-variable">$request</span>),
    );
}
</pre>
<h3 id="disable-'trashed'-behavior"><a href="#disable-'trashed'-behavior" class="heading-anchor">#</a> Disable 'trashed' behavior</h3>
<p>The <code>BelongsTo</code> field already has an option to remove the checkbox 'With Trashed'
(basically not to show trashed items), but what if want to remove it from any
other relationship operation (e.g.: <code>BelongsToMany</code>)?</p>
<p>You just need to apply the following code in your abstract resource:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Illuminate\Support\Facades\Gate</span>;

<span class="hl-comment">/**
 * Based the trashed behavior on a new policy called trashedAny()
 *
 * <span class="hl-value">@return</span> <span class="hl-type">boolean</span>
 */</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">softDeletes</span>()
{
    <span class="hl-comment">// Is this resource authorized on trashedAny?</span>
    <span class="hl-keyword">if</span> (<span class="hl-keyword">static</span>::<span class="hl-property">authorizable</span>()) {
        <span class="hl-keyword">if</span> (! <span class="hl-property">method_exists</span>(
            <span class="hl-type">Gate</span>::<span class="hl-property">getPolicyFor</span>(<span class="hl-keyword">static</span>::<span class="hl-property">newModel</span>()),
            '<span class="hl-value">trashedAny</span>'
        )) {
            <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>;
        }       

        <span class="hl-keyword">return</span> <span class="hl-type">Gate</span>::<span class="hl-property">check</span>('<span class="hl-value">trashedAny</span>', <span class="hl-keyword">static</span>::<span class="hl-keyword">class</span>));
    };

    <span class="hl-keyword">return</span> <span class="hl-keyword">parent</span>::<span class="hl-property">softDeletes</span>();
}
</pre>
<p>in this example, all you have to do is to define a policy for your model, and then
create a new method called <code>trashedAny(User $user)</code>, as example:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">trashedAny</span>(<span class="hl-injection"><span class="hl-type">User</span> $user</span>)
{
    <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
}
</pre>
<hr />
<p>These were examples that can trigger your thoughts about how to leverage
Abstract Resources on your Nova projects.</p>
<p><em>And if I was able to convince you :) I suggest you subscribe to updates
in my upcoming course <a target="_blank" href="https://www.masteringnova.com">Mastering Nova</a> that will be released
this mid-summer!</em></p>
<p>Best,
Bruno</p>
 ]]></summary>

                <updated>2020-06-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: Constructor property promotion ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/constructor-promotion-in-php-8"/>

                <id>https://www.stitcher.io/blog/constructor-promotion-in-php-8</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Personally, I use value objects and data transfer objects all the time in my projects. I even wrote a dedicated post on <a href="/blog/laravel-beyond-crud-02-working-with-data">how to treat data in our code</a> a while back.</p>
<p>Naturally, I'm very happy with the constructor property promotion RFC, it's passed and will be added in <a href="/blog/new-in-php-8">PHP 8</a>. You see, this feature reduces a lot of boilerplate code when constructing simple objects such as VOs and DTOs.</p>
<p>In short: property promotion allows you to combine class fields, constructor definition and variable assignments all into one syntax, in the construct parameter list.</p>
<p>So instead of doing this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CustomerDTO</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>;

    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$email</span>;

    <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$birth_date</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $name, 
        <span class="hl-type">string</span> $email, 
        <span class="hl-type">DateTimeImmutable</span> $birth_date
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">name</span> = <span class="hl-variable">$name</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">email</span> = <span class="hl-variable">$email</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">birth_date</span> = <span class="hl-variable">$birth_date</span>;
    }
}
</pre>
<p>You would write this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CustomerDTO</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>, 
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$email</span>, 
        <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$birth_date</span>,
    </span>) {}
}
</pre>
<p>Let's look at how it works!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<hr />
<h2 id="how-it-works"><a href="#how-it-works" class="heading-anchor">#</a> How it works</h2>
<p>The basic idea is simple: ditch all the class properties and the variable assignments, and prefix the constructor parameters with <code>public</code>, <code>protected</code> or <code>private</code>. PHP will take that new syntax, and transform it to normal syntax under the hood, before actually executing the code.</p>
<p>So it goes from this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyDTO</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span> = 'Brent',
    </span>) {}
}
</pre>
<p>To this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyDTO</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $name = 'Brent'
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">name</span> = <span class="hl-variable">$name</span>;
    }
}
</pre>
<p>And only executes it afterwards.</p>
<p>Note by the way that the default value is not set on the class property, but on the method argument in the constructor.</p>
<h2 id="promoted-property-properties"><a href="#promoted-property-properties" class="heading-anchor">#</a> Promoted property properties</h2>
<p>So let's look at what promoted properties can and can't do, there's quite a lot of little intricacies worth mentioning!</p>
<hr />
<h3 id="only-in-constructors"><a href="#only-in-constructors" class="heading-anchor">#</a> Only in constructors</h3>
<p>Promoted properties can only be used in constructors. That might seem obvious but I thought it was worth mentioning this, just to be clear.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h3 id="no-duplicates-allowed"><a href="#no-duplicates-allowed" class="heading-anchor">#</a> No duplicates allowed</h3>
<p>You're not able to declare a class property and a promoted property with the same name. That's also rather logical, since the promoted property is simply transpiled to a class property at runtime.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyClass</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$a</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$a</span>,
    </span>) {}
}
</pre>
<hr />
<h3 id="untyped-properties-are-allowed"><a href="#untyped-properties-are-allowed" class="heading-anchor">#</a> Untyped properties are allowed</h3>
<p>You're allowed to promote untyped properties, though I'd argue that these days with <a href="/blog/php-in-2020">modern PHP</a>, you're better off typing everything.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyDTO</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> $untyped,
    </span>) {}
}
</pre>
<hr />
<h3 id="simple-defaults"><a href="#simple-defaults" class="heading-anchor">#</a> Simple defaults</h3>
<p>Promoted properties can have default values, but expressions like <code>new …</code> are not allowed.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span> = 'Brent',
    <span class="hl-keyword">public</span> <span class="hl-type">DateTimeImmutable</span> <span class="hl-property">$date</span> = <span class="hl-keyword">new</span> <span class="hl-type">DateTimeImmutable</span>(),
</span>) {}
</pre>
<hr />
<h3 id="combining-promoted--and-normal-properties"><a href="#combining-promoted--and-normal-properties" class="heading-anchor">#</a> Combining promoted- and normal properties</h3>
<p>Not all constructor properties should be promoted, you can mix and match.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyClass</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$b</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$a</span>,
        <span class="hl-type">string</span> $b,
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">b</span> = <span class="hl-variable">$b</span>;
    }
}
</pre>
<p>I'd say: be careful mixing the syntaxes, if it makes the code less clear, consider using a normal constructor instead.</p>
<hr />
<h3 id="access-promoted-properties-from-the-constructor-body"><a href="#access-promoted-properties-from-the-constructor-body" class="heading-anchor">#</a> Access promoted properties from the constructor body</h3>
<p>You're allowed to read the promoted properties in the constructor body. This can be useful if you want to do extra validation checks. You can use both the local variable and the instance variable, both work fine.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$a</span>,
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$b</span>,
</span>) {
    <span class="hl-property">assert</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">a</span> &gt;= 100);

    <span class="hl-keyword">if</span> (<span class="hl-variable">$b</span> &gt;= 0) {
        <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">InvalidArgumentException</span>('<span class="hl-value">…</span>');
    }
}
</pre>
<hr />
<h3 id="doc-comments-on-promoted-properties"><a href="#doc-comments-on-promoted-properties" class="heading-anchor">#</a> Doc comments on promoted properties</h3>
<p>You can add doc comments on promoted properties, and they are still available via reflection.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyClass</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        /** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/
        <span class="hl-keyword">public</span> $a,
    </span>) {}
}
</pre>
<pre><span class="hl-variable">$property</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionProperty</span>(<span class="hl-type">MyClass</span>::<span class="hl-keyword">class</span>, '<span class="hl-value">a</span>');

<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getDocComment</span>(); <span class="hl-comment">// &quot;/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/&quot;</span>
</pre>
<hr />
<h3 id="attributes"><a href="#attributes" class="heading-anchor">#</a> Attributes</h3>
<p>Just like doc blocks, <a href="/blog/attributes-in-php-8">attributes</a> are allowed on promoted properties. When transpiled, they will be present both on the constructor parameter, as well as the class property.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyClass</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-attribute">#[MyAttribute]</span>
        <span class="hl-keyword">public</span> $a,  
    </span>) {}
}
</pre>
<p>Will be transpiled to:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyClass</span> 
{
    <span class="hl-attribute">#[<span class="hl-type">MyAttribute</span>]</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$a</span>;
 
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-attribute">#[MyAttribute]</span>
        $a,
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">a</span> = <span class="hl-variable">$a</span>;
    }
}
</pre>
<hr />
<h3 id="not-allowed-in-abstract-constructors"><a href="#not-allowed-in-abstract-constructors" class="heading-anchor">#</a> Not allowed in abstract constructors</h3>
<p>I didn't even know abstract constructors were a thing, but here goes! Promoted properties are not allowed in them.</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">abstract</span> <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$a</span>,
    </span>) {}
}
</pre>
<hr />
<h3 id="allowed-in-traits"><a href="#allowed-in-traits" class="heading-anchor">#</a> Allowed in traits</h3>
<p>On the other hand, they are allowed in traits. This makes sense, since the transpiled syntax is also valid in traits.</p>
<pre><span class="hl-keyword">trait</span> <span class="hl-type">MyTrait</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$a</span>,
    </span>) {}
}
</pre>
<hr />
<h3 id="var-is-not-supported"><a href="#var-is-not-supported" class="heading-anchor">#</a> <code>var</code> is not supported</h3>
<p>Old, I mean, experienced PHP developers might have used <code>var</code> in a distant past to declare class variables. It's not allowed with constructor promotion. Only <code>public</code>, <code>protected</code> and <code>private</code> are valid keywords.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    var <span class="hl-type">string</span> $a,
</span>) {}
</pre>
<hr />
<h3 id="variadic-parameters-cannot-be-promoted"><a href="#variadic-parameters-cannot-be-promoted" class="heading-anchor">#</a> Variadic parameters cannot be promoted</h3>
<p>Since you can't convert to a type that's <code>array of type</code>, it's not possible to promote variadic parameters.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-keyword">public</span> string ...$a,
</span>) {}
</pre>
<p>Still waiting for generics…</p>
<hr />
<h3 id="reflection-for-ispromoted"><a href="#reflection-for-ispromoted" class="heading-anchor">#</a> Reflection for <code>isPromoted</code></h3>
<p>Both <code>ReflectionProperty</code> and <code>ReflectionParameter</code> have a new <code>isPromoted</code> method to check whether the class property or method parameter is promoted.</p>
<hr />
<h3 id="inheritance"><a href="#inheritance" class="heading-anchor">#</a> Inheritance</h3>
<p>Since PHP constructors don't need to follow the declaration of their parent constructor, there's little to be said: inheritance is allowed. If you need to pass properties from the child constructor to the parent constructor though, you'll need to manually pass them:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-keyword">public</span> $a,
    </span>) {}
}

<span class="hl-keyword">class</span> <span class="hl-type">B</span> <span class="hl-keyword">extends</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        $a,
        <span class="hl-keyword">public</span> $b,    
    </span>) {
        <span class="hl-keyword">parent</span>::<span class="hl-property">__construct</span>(<span class="hl-variable">$a</span>);
    }
}
</pre>
<hr />
<p>That's about it for property promotion! I for sure will use them, what about you? Let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>!</p>
<hr />
 ]]></summary>

                <updated>2020-06-12T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Survey results: type systems in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/type-system-in-php-survey-results"/>

                <id>https://www.stitcher.io/blog/type-system-in-php-survey-results</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I use PHP's type system as much as possible, though often found resistance with the people I interact with on Twitter and Reddit.
After having discussed the topic numerous times, I felt like both "camps" were not really listening to each other, or at least not understanding each others point.</p>
<p>It made me wonder if and how the team we work in, and the kind of projects we work on, might influence our view of type system usage.</p>
<p>I decided to do a little survey, and gather some actual insights in the topic.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Fair warning: I'm no neutral player in this discussion, but I want to make clear that it wasn't my intention to make my own case. I wanted to see whether our seemingly pointless discussions might be caused by the difference in context; I don't want to prove there's one and only true answer.</p>
<p>With all that being said, let's look at the results.</p>
<hr />
<p>First of all I'd like to thank all 686 people who participated in this survey. I realise this is a small group, though I hope it's representative enough to draw some conclusions. If you think that the results aren't accurate enough, please reach out to me to discuss whether and how we can redo this survey on a larger scale.</p>
<p>Based on the answers in the survey, I made five groups of profiles: <code>A</code>, <code>B</code>, <code>C</code>, <code>D</code> and <code>E</code>. <code>A</code> and <code>B</code> lean (strongly) towards a stricter type system, <code>C</code> is somewhat neutral, and <code>D</code> and <code>E</code> lean (strongly) towards not using type systems.</p>
<p>This "type profile" was determined by mapping the answers to relevant questions to a score: 1 and 2 points were given to answers favorable to strict type systems, 0 to neutral answers and -1 and -2 to answers leaning towards no type systems.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/survey/1.png" srcset="/resources/img/blog/survey/1-1504x851.png 1504w, /resources/img/blog/survey/1-752x425.png 752w, /resources/img/blog/survey/1-1063x601.png 1063w, /resources/img/blog/survey/1-1682x952.png 1682w, /resources/img/blog/survey/1-1302x736.png 1302w" sizes="" alt=""></img></p>
<p><em class="center small">Type profile of all participants</em></p>
<p>One thing that immediately stood out is the large amount of people who lean towards the use of a strict type system. I did not expect this. From discussions I had on Twitter, I had the feeling that more people would be in group <code>C</code>, <code>D</code> or <code>E</code>.</p>
<p>These are some of the most popular arguments against the use of PHP's type system, at least the ones I heard in my discussions:</p>
<ul>
<li>PHP's type system still fails at runtime, so there's no advantage to using it</li>
<li>Types add unnecessary visual overload</li>
<li>The flexibility of using PHP's type juggling is preferred</li>
</ul>
<p>Of course this survey wanted to examine whether there's a correlation between personal preference and team- and project size. Let's look at team size first.</p>
<p>This chart shows the average team size, and for each group the distribution of type profiles within that group.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/survey/2.png" srcset="/resources/img/blog/survey/2-1312x516.png 1312w, /resources/img/blog/survey/2-927x365.png 927w, /resources/img/blog/survey/2-1136x447.png 1136w, /resources/img/blog/survey/2-656x258.png 656w, /resources/img/blog/survey/2-1467x578.png 1467w" sizes="" alt=""></img></p>
<p><em class="center small">Type profile distribution, grouped by team size</em></p>
<p>We'd need to look at relative results to test whether there's a correlation or not. So here goes, but keep in mind that the group with <code>2-10 people</code>, is by far the largest.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/survey/3.png" srcset="/resources/img/blog/survey/3-1147x439.png 1147w, /resources/img/blog/survey/3-662x253.png 662w, /resources/img/blog/survey/3-1324x507.png 1324w, /resources/img/blog/survey/3-1481x568.png 1481w, /resources/img/blog/survey/3-936x358.png 936w" sizes="" alt=""></img></p>
<p><em class="center small">Relative type profile distribution, grouped by team size</em></p>
<p>As I expected, based on discussions: profiles <code>D</code> and <code>E</code> are more present in smaller teams. Yet I admit I expected that group to be larger again.</p>
<p>Next I looked at project size. I asked participants to describe the size of an average project they work on: small, medium, large or extra large.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/survey/4.png" srcset="/resources/img/blog/survey/4-1096x434.png 1096w, /resources/img/blog/survey/4-895x355.png 895w, /resources/img/blog/survey/4-633x251.png 633w, /resources/img/blog/survey/4-1266x502.png 1266w, /resources/img/blog/survey/4-1416x562.png 1416w" sizes="" alt=""></img></p>
<p><em class="center small">Relative type profile distribution, grouped by project size</em></p>
<p>This chart shows a growth of type <code>A</code> and <code>B</code>, related to the size of the project. Most times, "project size" also translates to "project duration", which is why I also asked participants to rate the project duration of such an average project.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/survey/5.png" srcset="/resources/img/blog/survey/5-1425x773.png 1425w, /resources/img/blog/survey/5-1103x599.png 1103w, /resources/img/blog/survey/5-1274x691.png 1274w, /resources/img/blog/survey/5-901x489.png 901w, /resources/img/blog/survey/5-637x345.png 637w" sizes="" alt=""></img></p>
<p><em class="center small">Relative type profile distribution, grouped by project duration</em></p>
<p>Again we see a preference for stricter type systems in longer projects, but we should of course be aware that there were less participants in these groups. Furthermore, I found it interesting that in this case, there' no linear pattern to discover, as with the previous charts.</p>
<h2 id="conclusions"><a href="#conclusions" class="heading-anchor">#</a> Conclusions</h2>
<p>Unfortunately, I think there weren't enough participants distributed across all kinds of projects and team sizes to draw final conclusions here.</p>
<p>Up front, I assumed that the group who preferred not to use type systems would have been larger; but maybe it's simply a more vocal group, even though smaller? I can't say that for sure though.</p>
<p>I do think that, even with a small amount of participants, we can assume there is a correlation between type system usage and project- and team size; but ideally, we'd need a larger participant pool.</p>
<p>My personal takeaway is that when entering type system discussions, we should be wary to compare each others preference: there might be a good case that you're simply working in a completely different kind of project, and there's no way of telling who's right or wrong.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-06-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: Attributes ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/attributes-in-php-8"/>

                <id>https://www.stitcher.io/blog/attributes-in-php-8</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>As of PHP 8, we'll be able to use attributes. The goal of these attributes, also known as annotations in many other languages, is to add meta data to classes, methods, variables and what not; in a structured way.</p>
<p>The concept of attributes isn't new at all, we've been using docblocks to simulate their behaviour for years now. With the addition of attributes though, we now have a first-class citizen in the language to represent this kind of meta data, instead of having to manually parse docblocks.</p>
<p>So what do they look like? How do we make custom attributes? Are there any caveats? Those are the questions that will be answered in this post. Let's dive in!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="rundown"><a href="#rundown" class="heading-anchor">#</a> Rundown</h2>
<p>First things first, here's what attribute would look like in the wild:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">\Support\Attributes\ListensTo</span>;

<span class="hl-keyword">class</span> <span class="hl-type">ProductSubscriber</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ListensTo</span>(<span class="hl-type">ProductCreated</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onProductCreated</span>(<span class="hl-injection"><span class="hl-type">ProductCreated</span> $event</span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ListensTo</span>(<span class="hl-type">ProductDeleted</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onProductDeleted</span>(<span class="hl-injection"><span class="hl-type">ProductDeleted</span> $event</span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>I'll be showing other examples later in this post, but I think the example of event subscribers is a good one to explain the use of attributes at first.</p>
<p>Also yes, I know, the syntax might not be what you wished or hoped for. You might have preferred <code>@</code>, or <code>@:</code>, or docblocks or, … It's here to stay though, so we better learn to deal with it. The only thing that's worth mentioning on the syntax is that all options were discussed, and there are very good reasons why this syntax was chosen. You can read the whole discussion about the RFC on the <a target="_blank" href="https://externals.io/message/110640">internals list</a>.</p>
<p>That being said, let's focus on the cool stuff: how would this <code>ListensTo</code> work under the hood?</p>
<p>First of all, custom attributes are simple classes, annotated themselves with the <code>#[Attribute]</code> attribute; this base <code>Attribute</code> used to be called <code>PhpAttribute</code> in the original RFC, but was changed with <a target="_blank" href="https://wiki.php.net/rfc/attribute_amendments">another RFC</a> afterwards.</p>
<p>Here's what it would look like:</p>
<pre><span class="hl-attribute">#[<span class="hl-type">Attribute</span>]</span>
<span class="hl-keyword">class</span> <span class="hl-type">ListensTo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$event</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">string</span> $event</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">event</span> = <span class="hl-variable">$event</span>;
    }
}
</pre>
<p>That's it — pretty simple right? Keep in mind the goal of attributes: they are meant to add meta data to classes and methods, nothing more. They shouldn't — and can't — be used for, for example, argument input validation. In other words: you wouldn't have access to the parameters passed to a method within its attributes. There was a previous RFC that allowed this behaviour, but this RFC specifically kept things more simple.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>Back to the event subscriber example: we still need to read the meta data and register our subscribers based somewhere. Coming from a Laravel background, I'd use a service provider as the place to do this, but feel free to come up with other solutions.</p>
<p>Here's the boring boilerplate setup, just to provide a little context:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">EventServiceProvider</span> <span class="hl-keyword">extends</span> <span class="hl-type">ServiceProvider</span>
{
    <span class="hl-comment">// In real life scenarios, </span>
    <span class="hl-comment">//  we'd automatically resolve and cache all subscribers</span>
    <span class="hl-comment">//  instead of using a manual array.</span>
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$subscribers</span> = [
        <span class="hl-type">ProductSubscriber</span>::<span class="hl-keyword">class</span>,
    ];

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">register</span>(): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// The event dispatcher is resolved from the container</span>
        <span class="hl-variable">$eventDispatcher</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">app</span>-&gt;<span class="hl-property">make</span>(<span class="hl-type">EventDispatcher</span>::<span class="hl-keyword">class</span>);

        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">subscribers</span> <span class="hl-keyword">as</span> <span class="hl-variable">$subscriber</span>) {
            <span class="hl-comment">// We'll resolve all listeners registered </span>
            <span class="hl-comment">//  in the subscriber class,</span>
            <span class="hl-comment">//  and add them to the dispatcher.</span>
            <span class="hl-keyword">foreach</span> (
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">resolveListeners</span>(<span class="hl-variable">$subscriber</span>) 
                <span class="hl-keyword">as</span> [<span class="hl-variable">$event</span>, <span class="hl-variable">$listener</span>]
            ) {
                <span class="hl-variable">$eventDispatcher</span>-&gt;<span class="hl-property">listen</span>(<span class="hl-variable">$event</span>, <span class="hl-variable">$listener</span>);
            }       
        }       
    }
}
</pre>
<p>Note that if the <code>[$event, $listener]</code> syntax is unfamiliar to you, you can get up to speed with it in my post about <a href="/blog/array-destructuring-with-list-in-php#in-loops">array destructuring</a>.</p>
<p>Now let's look at <code>resolveListeners</code>, which is where the magic happens.</p>
<pre><span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">resolveListeners</span>(<span class="hl-injection"><span class="hl-type">string</span> $subscriberClass</span>): <span class="hl-type">array</span>
{
    <span class="hl-variable">$reflectionClass</span> = <span class="hl-keyword">new</span> <span class="hl-type">ReflectionClass</span>(<span class="hl-variable">$subscriberClass</span>);

    <span class="hl-variable">$listeners</span> = [];

    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$reflectionClass</span>-&gt;<span class="hl-property">getMethods</span>() <span class="hl-keyword">as</span> <span class="hl-variable">$method</span>) {
        <span class="hl-variable">$attributes</span> = <span class="hl-variable">$method</span>-&gt;<span class="hl-property">getAttributes</span>(<span class="hl-type">ListensTo</span>::<span class="hl-keyword">class</span>);
        
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$attributes</span> <span class="hl-keyword">as</span> <span class="hl-variable">$attribute</span>) {
            <span class="hl-variable">$listener</span> = <span class="hl-variable">$attribute</span>-&gt;<span class="hl-property">newInstance</span>();
            
            <span class="hl-variable">$listeners</span>[] = [
                <span class="hl-comment">// The event that's configured on the attribute</span>
                <span class="hl-variable">$listener</span>-&gt;<span class="hl-property">event</span>,
    
                <span class="hl-comment">// The listener for this event </span>
                [<span class="hl-variable">$subscriberClass</span>, <span class="hl-variable">$method</span>-&gt;<span class="hl-property">getName</span>()],
            ];
        }
    }

    <span class="hl-keyword">return</span> <span class="hl-variable">$listeners</span>;
}
</pre>
<p>You can see it's easier to read meta data this way, compared to parsing docblock strings. There are two intricacies worth looking into though.</p>
<p>First there's the <code>$attribute-&gt;newInstance()</code> call. This is actually the place where our custom attribute class is instantiated. It will take the parameters listed in the attribute definition in our subscriber class, and pass them to the constructor.</p>
<p>This means that, technically, you don't even need to construct the custom attribute. You could call <code>$attribute-&gt;getArguments()</code> directly. Furthermore, instantiating the class means you've got the flexibility of the constructor the parse input whatever way you like. All in all I'd say it would be good to always instantiate the attribute using <code>newInstance()</code>.</p>
<p>The second thing worth mentioning is the use of <code>ReflectionMethod::getAttributes()</code>, the function that returns all attributes for a method. You can pass two arguments to it, to filter its output.</p>
<p>In order to understand this filtering though, there's one more thing you need to know about attributes first. This might have been obvious to you, but I wanted to mention it real quick anyway: it's possible to add several attributes to the same method, class, property or constant.</p>
<p>You could, for example, do this:</p>
<pre>#[
    <span class="hl-type">Route</span>(<span class="hl-type">Http</span>::<span class="hl-property">POST</span>, '<span class="hl-value">/products/create</span>'),
    <span class="hl-type">Autowire</span>,
]
<span class="hl-keyword">class</span> <span class="hl-type">ProductsCreateController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>() { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>With that in mind, it's clear why <code>Reflection*::getAttributes()</code> returns an array, so let's look at how its output can be filtered.</p>
<p>Say you're parsing controller routes, you're only interested in the <code>Route</code> attribute. You can easily pass that class as a filter:</p>
<pre><span class="hl-variable">$attributes</span> = <span class="hl-variable">$reflectionClass</span>-&gt;<span class="hl-property">getAttributes</span>(<span class="hl-type">Route</span>::<span class="hl-keyword">class</span>);
</pre>
<p>The second parameter changes how that filtering is done. You can pass in <code>ReflectionAttribute::IS_INSTANCEOF</code>, which will return all attributes implementing a given interface.</p>
<p>For example, say you're parsing container definitions, which relies on several attributes, you could do something like this:</p>
<pre><span class="hl-variable">$attributes</span> = <span class="hl-variable">$reflectionClass</span>-&gt;<span class="hl-property">getAttributes</span>(
    <span class="hl-type">ContainerAttribute</span>::<span class="hl-keyword">class</span>, 
    <span class="hl-type">ReflectionAttribute</span>::<span class="hl-property">IS_INSTANCEOF</span>
);
</pre>
<p>It's a nice shorthand, built into the core.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="technical-theory"><a href="#technical-theory" class="heading-anchor">#</a> Technical theory</h2>
<p>Now that you have an idea of how attributes work in practice, it's time for some more theory, making sure you understand them thoroughly. First of all, I mentioned this briefly before, attributes can be added in several places.</p>
<p>In classes, as well as anonymous classes;</p>
<pre><span class="hl-attribute">#[<span class="hl-type">ClassAttribute</span>]</span>
<span class="hl-keyword">class</span> <span class="hl-type">MyClass</span> { <span class="hl-comment">/* … */</span> }

<span class="hl-variable">$object</span> = <span class="hl-keyword">new</span> <span class="hl-attribute">#[<span class="hl-type">ObjectAttribute</span>]</span> <span class="hl-keyword">class</span> () { <span class="hl-comment">/* … */</span> };
</pre>
<p>Properties and constants;</p>
<pre><span class="hl-attribute">#[<span class="hl-type">PropertyAttribute</span>]</span>
<span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$foo</span>;

<span class="hl-attribute">#[<span class="hl-type">ConstAttribute</span>]</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">const</span> <span class="hl-property">BAR</span> = 1;
</pre>
<p>Methods and functions;</p>
<pre><span class="hl-attribute">#[<span class="hl-type">MethodAttribute</span>]</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">doSomething</span>(): <span class="hl-type">void</span> { <span class="hl-comment">/* … */</span> }

<span class="hl-attribute">#[<span class="hl-type">FunctionAttribute</span>]</span>
<span class="hl-keyword">function</span> <span class="hl-property">foo</span>() { <span class="hl-comment">/* … */</span> }
</pre>
<p>As well as closures;</p>
<pre><span class="hl-variable">$closure</span> = <span class="hl-attribute">#[<span class="hl-type">ClosureAttribute</span>]</span> <span class="hl-keyword">fn</span>() =&gt; <span class="hl-comment">/* … */</span>;
</pre>
<p>And method and function parameters;</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-attribute">#[ArgumentAttribute]</span> $bar</span>) { <span class="hl-comment">/* … */</span> }
</pre>
<p>They can be declared before or after docblocks;</p>
<pre><span class="hl-comment">/** <span class="hl-value">@return</span> <span class="hl-type">void </span>*/</span>
<span class="hl-attribute">#[<span class="hl-type">MethodAttribute</span>]</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">doSomething</span>(): <span class="hl-type">void</span> { <span class="hl-comment">/* … */</span> }
</pre>
<p>And can take no, one or several arguments, which are defined by the attribute's constructor:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Listens</span>(<span class="hl-type">ProductCreatedEvent</span>::<span class="hl-keyword">class</span>)]</span></span>
<span class="hl-attribute">#[<span class="hl-type">Autowire</span>]</span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Route</span>(<span class="hl-type">Http</span>::<span class="hl-property">POST</span>, '<span class="hl-value">/products/create</span>')]</span></span>
</pre>
<p>As for allowed parameters you can pass to an attribute, you've already seen that class constants, <code>::class</code> names and scalar types are allowed. There's a little more to be said about this though: attributes only accept constant expressions as input arguments.</p>
<p>This means that scalar expressions are allowed — even bit shifts — as well as <code>::class</code>, constants, arrays and array unpacking, boolean expressions and the null coalescing operator. A list of everything that's allowed as a constant expression can be found in the <a target="_blank" href="https://github.com/php/php-src/blob/9122638ecd7dfee1cbd141a15a8d59bfc47f6ab3/Zend/zend_compile.c#L8500-L8514">source code</a>.</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">AttributeWithScalarExpression</span>(1 + 1)]</span></span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">AttributeWithClassNameAndConstants</span>(<span class="hl-type">PDO</span>::<span class="hl-keyword">class</span>, <span class="hl-property">PHP_VERSION_ID</span>)]</span></span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">AttributeWithClassConstant</span>(<span class="hl-type">Http</span>::<span class="hl-property">POST</span>)]</span></span>
<span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">AttributeWithBitShift</span>(4 &gt;&gt; 1, 4 &lt;&lt; 1)]</span></span>
</pre>
<h2 id="attribute-configuration"><a href="#attribute-configuration" class="heading-anchor">#</a> Attribute configuration</h2>
<p>By default, attributes can be added in several places, as listed above. It's possible, however, to configure them so they can only be used in specific places. For example you could make it so that <code>ClassAttribute</code> can only be used on classes, and nowhere else. Opting-in this behaviour is done by passing a flag to the <code>Attribute</code> attribute on the attribute class.</p>
<p>It looks like this:</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Attribute</span>(<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_CLASS</span>)]</span></span>
<span class="hl-keyword">class</span> <span class="hl-type">ClassAttribute</span>
{
}
</pre>
<p>The following flags are available:</p>
<pre><span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_CLASS</span>
<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_FUNCTION</span>
<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_METHOD</span>
<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_PROPERTY</span>
<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_CLASS_CONSTANT</span>
<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_PARAMETER</span>
<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_ALL</span>
</pre>
<p>These are bitmask flags, so you can combine them <a href="/blog/bitwise-booleans-in-php">using a binary OR operation</a>.</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Attribute</span>(<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_METHOD</span>|<span class="hl-type">Attribute</span>::<span class="hl-property">TARGET_FUNCTION</span>)]</span></span>
<span class="hl-keyword">class</span> <span class="hl-type">ClassAttribute</span>
{
}
</pre>
<p>Another configuration flag is about repeatability. By default the same attribute can't be applied twice, unless it's specifically marked as repeatable. This is done the same way as target configuration, with a bit flag.</p>
<pre><span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">Attribute</span>(<span class="hl-type">Attribute</span>::<span class="hl-property">IS_REPEATABLE</span>)]</span></span>
<span class="hl-keyword">class</span> <span class="hl-type">ClassAttribute</span>
{
}
</pre>
<p>Note that all these flags are only validated when calling <code>$attribute-&gt;newInstance()</code>, not earlier.</p>
<h2 id="built-in-attributes"><a href="#built-in-attributes" class="heading-anchor">#</a> Built-in attributes</h2>
<p>Once the base RFC had been accepted, new opportunities arose to add built-in attributes to the core. One such example is the <a target="_blank" href="https://wiki.php.net/rfc/deprecated_attribute"><code>#[Deprecated]</code></a> attribute, and a popular example has been a <code>#[Jit]</code> attribute — if you're not sure what that last one is about, you can read my post about <a href="/blog/php-jit">what the JIT is</a>.</p>
<p>I'm sure we'll see more and more built-in attributes in the future.</p>
<p>As a final note, for those worrying about generics: the syntax won't conflict with them, if they ever were to be added in PHP, so we're safe!</p>
<hr />
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<hr />
<p>I've got some use-cases already in mind for attributes, what about you? If you've got some thoughts to share about this awesome new feature in PHP 8, you can reach me on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>, or we can discuss it over on <a target="_blank" href="https://www.reddit.com/r/PHP/comments/gixnf3/attributes_in_php_8/">Reddit</a>.</p>
 ]]></summary>

                <updated>2020-09-03T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ How to merge multidimensional arrays in PHP? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/merging-multidimensional-arrays-in-php"/>

                <id>https://www.stitcher.io/blog/merging-multidimensional-arrays-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>If you want to join two multidimensional arrays in PHP, you should still use <code>array_merge</code>, and not <code>array_merge_recursive</code>. Confused? So was I. Let's explain what's happening.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's first explain what <code>array_merge_recursive</code> does, take for example these two arrays:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">key</span>' =&gt; '<span class="hl-value">original</span>'
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">key</span>' =&gt; '<span class="hl-value">override</span>'
];
</pre>
<p>Using <code>array_merge_recursive</code> will result in the following:</p>
<pre><span class="hl-property">array_merge_recursive</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>);

<span class="hl-comment">// [</span>
<span class="hl-comment">//     'key' =&gt; [</span>
<span class="hl-comment">//         'original',</span>
<span class="hl-comment">//         'override',</span>
<span class="hl-comment">//     ],</span>
<span class="hl-comment">// ]</span>
</pre>
<p>Instead of overriding the original <code>key</code> value, <code>array_merge_recursive</code> created an array, with the original and new value both in it.</p>
<p>While that looks strange in this simple example, it's actually more useful in cases where one of the values already is an array, and you want to merge another item in that array, instead of overriding it.</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">key</span>' =&gt; ['<span class="hl-value">original</span>']
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">key</span>' =&gt; '<span class="hl-value">override</span>'
];
</pre>
<p>In this case, <code>array_merge_recursive</code> will yield the same result as the first example: it takes the value from the <code>$second</code> array, and appends it to the value in the <code>$first</code> array, which already was an array itself.</p>
<pre><span class="hl-property">array_merge_recursive</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>);

<span class="hl-comment">// [</span>
<span class="hl-comment">//     'key' =&gt; [</span>
<span class="hl-comment">//         'original',</span>
<span class="hl-comment">//         'override',</span>
<span class="hl-comment">//     ],</span>
<span class="hl-comment">// ]</span>
</pre>
<p>So if you want to merge multidimensional arrays, you can simply use <code>array_merge</code>, it can handle multiple levels of arrays just fine:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">level 1</span>' =&gt; [
        '<span class="hl-value">level 2</span>' =&gt; '<span class="hl-value">original</span>'
    ]
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">level 1</span>' =&gt; [
        '<span class="hl-value">level 2</span>' =&gt; '<span class="hl-value">override</span>'
    ]
];

<span class="hl-property">array_merge</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>);

<span class="hl-comment">// [  </span>
<span class="hl-comment">//     'level 1' =&gt; [</span>
<span class="hl-comment">//         'level 2' =&gt; 'override'</span>
<span class="hl-comment">//     ]</span>
<span class="hl-comment">// ]</span>
</pre>
<p>All of that being said, you could also use the <code>+</code> operator to merge multidimensional arrays, but <a href="/blog/what-is-array-plus-in-php">it will work slightly different</a> compared to <code>array_merge</code>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-06-05T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What does array + do in PHP? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/what-is-array-plus-in-php"/>

                <id>https://www.stitcher.io/blog/what-is-array-plus-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In PHP it's possible to do array + array. The "plus" sign is a shorthand way of merging arrays, but there's a difference in how they are merged compared to using <code>array_merge</code>.</p>
<p>Let's imagine these two arrays:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">a</span>',
    '<span class="hl-value">b</span>',
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">c</span>',
];
</pre>
<p>Merging them using <code>+</code> would result in the following:</p>
<pre><span class="hl-variable">$first</span> + <span class="hl-variable">$second</span>;

<span class="hl-comment">// ['a', 'b']</span>
</pre>
<p>While using <code>array_merge</code>, would result in this:</p>
<pre><span class="hl-property">array_merge</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>);

<span class="hl-comment">// ['a', 'b', 'c']</span>
</pre>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>What's happening here is that <code>array_merge</code> will override existing keys, while <code>+</code> will not. In other words: when a key exists in the first array, <code>+</code> will not merge an item with the same key from another array into the first one.</p>
<p>In our example, both arrays actually had numerical keys, like so:</p>
<pre><span class="hl-variable">$first</span> = [
    0 =&gt; '<span class="hl-value">a</span>',
    1 =&gt; '<span class="hl-value">b</span>',
];

<span class="hl-variable">$second</span> = [
    0 =&gt; '<span class="hl-value">c</span>',
];
</pre>
<p>Which explains why <code>$first + $second</code> doesn't add 'c' as an element: there already is an item with index <code>0</code> in the original.</p>
<p>The same applies for textual keys:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">a</span>' =&gt; '<span class="hl-value">a</span>',
    '<span class="hl-value">b</span>' =&gt; '<span class="hl-value">b</span>',
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">a</span>' =&gt; '<span class="hl-value">a - override</span>',
];

<span class="hl-variable">$first</span> + <span class="hl-variable">$second</span>;

<span class="hl-comment">// ['a' =&gt; 'a', 'b' =&gt; 'b']</span>
</pre>
<p>And finally, <code>+</code> also works with nested arrays:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">level 1</span>' =&gt; [
        '<span class="hl-value">level 2</span>' =&gt; '<span class="hl-value">original</span>'
    ],
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">level 1</span>' =&gt; [
        '<span class="hl-value">level 2</span>' =&gt; '<span class="hl-value">override</span>'
    ],
];
</pre>
<p>Using <code>+</code> will keep the <code>original</code> value, while <code>array_merge</code> would <code>override</code> it.</p>
<p>One more thing to mention is that <code>+</code> will apply the same behaviour when <a href="/blog/merging-multidimensional-arrays-in-php">merging multidimensional arrays</a>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-06-05T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Survey: type systems in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/type-system-in-php-survey"/>

                <id>https://www.stitcher.io/blog/type-system-in-php-survey</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Hi there! Thanks for spending 5 minutes of your time on this quick survey. My goal with it is to investigate the correlation between type-systems and project size in the PHP community.</p>
<p>Once this survey has gathered enough results, I will publish my conclusions on this blog. If you want stay updated on that, you can <a target="_blank" href="https://stitcher.us20.list-manage.com/subscribe?u=ca00be85f8183f513ec127063&amp;id=0c24251135">subscribe to my newsletter</a>, <a target="_blank" href="https://twitter.com/brendt_gd">follow me on Twitter</a> or <a target="_blank" href="/rss">subscribe to my RSS feed</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>A small update, I've gathered enough results, you can read about them <a href="/blog/type-system-in-php-survey-results">here</a>.</p>
 ]]></summary>

                <updated>2020-06-03T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Improvements on Laravel Nova ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/improvements-on-laravel-nova"/>

                <id>https://www.stitcher.io/blog/improvements-on-laravel-nova</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <h2 id="a-long-time-ago-in-a-galaxy-far,-far-away…"><a href="#a-long-time-ago-in-a-galaxy-far,-far-away…" class="heading-anchor">#</a> A long time ago in a galaxy far, far away…</h2>
<p><a target="_blank" href="https://nova.laravel.com">Laravel Nova</a> was launched on 22nd August 2018, as
the official administration panel for Laravel web applications.</p>
<p><img src="/resources/img/blog/improvements-on-laravel-nova/nova-1.jpg" srcset="/resources/img/blog/improvements-on-laravel-nova/nova-1-659x415.jpg 659w, /resources/img/blog/improvements-on-laravel-nova/nova-1-932x587.jpg 932w, /resources/img/blog/improvements-on-laravel-nova/nova-1-466x293.jpg 466w, /resources/img/blog/improvements-on-laravel-nova/nova-1-807x509.jpg 807w, /resources/img/blog/improvements-on-laravel-nova/nova-1-1043x658.jpg 1043w" sizes="" alt=""></img></p>
<p>That was <a target="_blank" href="https://twitter.com/taylorotwell">Taylor Otwell</a> making the presentation at
the Laracon US 2018, and since then Nova has evolved a lot, offering a better a UI experience,
faster performance, and at the end giving backend creators a true experience on how
to have a seamless integration between a Laravel application and the respective Resources
(or Eloquent <em>empowered</em> models) integrated into a nice CRUD interface.</p>
<p>When Nova was created, a lot of expectations were already present in the Laravel community
in the way that Laravel Nova should be a real administration back-office system, since
this was a niche that was already covered by very nice alternative CRUD platforms like
<a target="_blank" href="https://2019.quickadminpanel.com/">QuickAdminPanel</a> or <a target="_blank" href="https://backpackforlaravel.com/">Laravel BackPack</a>
but they weren't an official Laravel product. So, when Nova was launched right after Laracon
it went like a sales hit, everybody was talking about it, and everybody that bought a license
experienced challenges to using it too. But those are things from the past :)</p>
<p>Nova evolved since then and evolved a lot! It's no longer a simple Resource Management tool
and I want to share with you 6 must-have features that might help you when you are developing
your Nova projects. Also, if you want deep dive in Nova, I suggest you subscribe to updates
in my upcoming course <a target="_blank" href="https://www.masteringnova.com">Mastering Nova</a> that will be released
this mid-summer!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="1.-creating-your-custom-css-theme"><a href="#1.-creating-your-custom-css-theme" class="heading-anchor">#</a> 1. Creating your custom CSS theme</h2>
<p>The first versions of Nova you weren't able to customize your Theme and to tweak it
in a way without having your CSS code being overridden each time a new version of Nova was
being published.</p>
<p>Now you can create your CSS theme, like this:</p>
<pre>php artisan nova:theme brunocfalcao/masteringnova-theme
</pre>
<p>After that, you have a CSS class in your new package at <code>resources/css/theme.css</code> where
you can then apply all the new <a target="_blank" href="https://tailwindcss.com">Tailwind</a> classes that you want
to use in your Nova instance.</p>
<p>If you want to even fully customize the entire Nova classes you can enable it using a
custom package, then use the Nova::enableThemingClasses() to fully brand it to your needs.</p>
<p>This feature will prefix the Vue components with the string <code>nova-</code>.
For example, Nova will
add the class name nova-heading to the top-level of the Heading component so you can
then style it from there.</p>
<pre><span class="hl-comment">// NovaServiceProvider.php</span>

<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">boot</span>()
{
    <span class="hl-type">Nova</span>::<span class="hl-property">enableThemingClasses</span>()
}
</pre>
<pre><span class="hl-comment">// app.js</span>

<span class="hl-comment">/**
 * If configured, register a global mixin to add theming-friendly CSS
 * classnames to Nova's built-in Vue components. This allows the user
 * to fully customize Nova's theme to their project's branding.
 */</span>
<span class="hl-keyword">if</span> (window.<span class="hl-property">config</span>.<span class="hl-property">themingClasses</span>) {
    <span class="hl-type">Vue</span>.<span class="hl-property">mixin</span>(ThemingClasses)
}
</pre>
<h2 id="2.-dynamic-field-visibility-statuses"><a href="#2.-dynamic-field-visibility-statuses" class="heading-anchor">#</a> 2. Dynamic Field visibility statuses</h2>
<p>in the version 1.x of Nova you would control your Fields visibility using 8 methods:</p>
<pre><span class="hl-property">hideFromIndex</span>()
<span class="hl-property">hideFromDetail</span>()
<span class="hl-property">hideWhenCreating</span>()
<span class="hl-property">hideWhenUpdating</span>()
<span class="hl-property">onlyOnIndex</span>()
<span class="hl-property">onlyOnDetail</span>()
<span class="hl-property">onlyOnForms</span>()
<span class="hl-property">exceptOnForms</span>()
</pre>
<p>Now, you have the <code>show*()</code> methods that allow you to show your Resource in the
respective display context without the dependency of other display contexts. For instance
you can have a <code>showOnIndex()</code> and a <code>showOnCreating()</code>, using a callback on the method
that should return <code>true</code>.</p>
<pre>showOnIndex()
showOnDetail()
showOnCreating()
showOnUpdating()
</pre>
<h2 id="3.-new-field-types-to-create-a-better-user-experience"><a href="#3.-new-field-types-to-create-a-better-user-experience" class="heading-anchor">#</a> 3. New field types to create a better user experience</h2>
<p>Since version 1.x that we see being added new field types to Nova. Let me highlight
you some of the ones I consider the best additions:</p>
<h3 id="sparkline-field"><a href="#sparkline-field" class="heading-anchor">#</a> SparkLine Field</h3>
<p>See it a Chart "on-the-fly" directly in your Resource index or detail contexts.</p>
<p><img src="/resources/img/blog/improvements-on-laravel-nova/sparkline-field.jpg" srcset="/resources/img/blog/improvements-on-laravel-nova/sparkline-field-335x124.jpg 335w, /resources/img/blog/improvements-on-laravel-nova/sparkline-field-670x249.jpg 670w, /resources/img/blog/improvements-on-laravel-nova/sparkline-field-580x215.jpg 580w, /resources/img/blog/improvements-on-laravel-nova/sparkline-field-750x279.jpg 750w, /resources/img/blog/improvements-on-laravel-nova/sparkline-field-474x176.jpg 474w" sizes="" alt=""></img></p>
<pre><span class="hl-type">Sparkline</span>::<span class="hl-property">make</span>('<span class="hl-value">Total devices Per Week</span>')
    -&gt;<span class="hl-property">data</span>(<span class="hl-variable">$data</span>)
    -&gt;<span class="hl-property">asBarChart</span>()
    -&gt;<span class="hl-property">width</span>(300),
</pre>
<h3 id="key-value-field"><a href="#key-value-field" class="heading-anchor">#</a> Key-Value Field</h3>
<p>Key-value fields are ways for you to interact with JSON data type columns, providing
a way to manage Key-Value entries in a CRUD way.</p>
<p><img src="/resources/img/blog/improvements-on-laravel-nova/key-value-field.jpg" srcset="/resources/img/blog/improvements-on-laravel-nova/key-value-field-1583x284.jpg 1583w, /resources/img/blog/improvements-on-laravel-nova/key-value-field-1001x179.jpg 1001w, /resources/img/blog/improvements-on-laravel-nova/key-value-field-1415x253.jpg 1415w, /resources/img/blog/improvements-on-laravel-nova/key-value-field-1226x219.jpg 1226w, /resources/img/blog/improvements-on-laravel-nova/key-value-field-707x126.jpg 707w" sizes="" alt=""></img></p>
<pre><span class="hl-type">KeyValue</span>::<span class="hl-property">make</span>('<span class="hl-value">Server Data</span>', '<span class="hl-value">server_data</span>')
    -&gt;<span class="hl-property">keyLabel</span>('<span class="hl-value">Parameter</span>')
    -&gt;<span class="hl-property">valueLabel</span>('<span class="hl-value">Value</span>')
    -&gt;<span class="hl-property">actionText</span>('<span class="hl-value">Add Server Parameter</span>')
    -&gt;<span class="hl-property">rules</span>('<span class="hl-value">json</span>')
    -&gt;<span class="hl-property">nullable</span>(),

<span class="hl-comment">// In your model:</span>
<span class="hl-keyword">protected</span> <span class="hl-property">$casts</span> = [
    '<span class="hl-value">server_data</span>' =&gt; '<span class="hl-value">json</span>'
];
</pre>
<h3 id="hidden-field"><a href="#hidden-field" class="heading-anchor">#</a> Hidden Field</h3>
<p>At first, it might not be useful, but believe me, it's great to have it since
you can apply data computations to be sent to your UI components.</p>
<pre>Hidden::make('User', 'user_id')-&gt;default(
    fn($request) =&gt; $request-&gt;user()-&gt;id
);
</pre>
<h3 id="vaporfile-and-vaporimage-fields"><a href="#vaporfile-and-vaporimage-fields" class="heading-anchor">#</a> VaporFile and VaporImage Fields</h3>
<p>These are the <em>newest kids on the block</em> since they allow you to upload files or
images into your Laravel Vapor instance. They will generate a temporary upload
URL for Amazon S3 and will immediately upload the file.</p>
<p><img src="/resources/img/blog/improvements-on-laravel-nova/vapor-fields.jpg" srcset="/resources/img/blog/improvements-on-laravel-nova/vapor-fields-518x172.jpg 518w, /resources/img/blog/improvements-on-laravel-nova/vapor-fields-299x99.jpg 299w, /resources/img/blog/improvements-on-laravel-nova/vapor-fields-423x140.jpg 423w, /resources/img/blog/improvements-on-laravel-nova/vapor-fields-670x223.jpg 670w, /resources/img/blog/improvements-on-laravel-nova/vapor-fields-599x199.jpg 599w" sizes="" alt=""></img></p>
<pre>VaporFile::make('Filename'),
VaporImage::make('Avatar')-&gt;maxWidth(80)-&gt;rounded(false),
</pre>
<h3 id="searchable-select-fields"><a href="#searchable-select-fields" class="heading-anchor">#</a> Searchable Select Fields</h3>
<p>On the latest Nova version 3.6.0 you can now have a Searchable Select field.</p>
<p><img src="/resources/img/blog/improvements-on-laravel-nova/select-searchable.jpg" srcset="/resources/img/blog/improvements-on-laravel-nova/select-searchable-701x182.jpg 701w, /resources/img/blog/improvements-on-laravel-nova/select-searchable-859x223.jpg 859w, /resources/img/blog/improvements-on-laravel-nova/select-searchable-495x128.jpg 495w, /resources/img/blog/improvements-on-laravel-nova/select-searchable-1109x288.jpg 1109w, /resources/img/blog/improvements-on-laravel-nova/select-searchable-991x257.jpg 991w" sizes="" alt=""></img></p>
<pre><span class="hl-type">Select</span>::<span class="hl-property">make</span>('<span class="hl-value">Tags</span>', '<span class="hl-value">tag_id</span>')
    -&gt;<span class="hl-property">searchable</span>()
    -&gt;<span class="hl-property">options</span>(<span class="hl-type">\App\Tag</span>::<span class="hl-property">all</span>()-&gt;<span class="hl-property">pluck</span>('<span class="hl-value">name</span>', '<span class="hl-value">id</span>'))
    -&gt;<span class="hl-property">displayUsingLabels</span>(),
</pre>
<h2 id="4.-you-can-change-the-stubs"><a href="#4.-you-can-change-the-stubs" class="heading-anchor">#</a> 4. You can change the Stubs</h2>
<p>Since version 3.3.0 it's possible to publish the Nova stubs so you can change them to your
own needs.</p>
<pre>php artisan nova:stubs [--force]
</pre>
<p>The stubs are published directly in your app folder in a directory called "stubs".</p>
<h2 id="5.-ability-to-sort-your-resources-by-priority-on-the-sidebar"><a href="#5.-ability-to-sort-your-resources-by-priority-on-the-sidebar" class="heading-anchor">#</a> 5. Ability to sort your Resources by priority on the Sidebar</h2>
<p>This one I think it's undocumented but you can sort your Resources given a specific attribute in your Resource.</p>
<pre><span class="hl-comment">// In NovaServiceProvider.php</span>
<span class="hl-type">Nova</span>::<span class="hl-property">sortResourcesBy</span>(<span class="hl-keyword">function</span> (<span class="hl-injection">$resource</span>) {
    <span class="hl-keyword">return</span> <span class="hl-variable">$resource</span>::<span class="hl-property">$priority</span> ?? 9999;
});

<span class="hl-comment">// In your Resource</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-property">$priority</span> = 10; <span class="hl-comment">// Or any other number.</span>
</pre>
<p>The Sidebar Resources will then be sorted by this priority. Neat!</p>
<h2 id="6.-customize-where-a-global-search-link-can-take-you-to"><a href="#6.-customize-where-a-global-search-link-can-take-you-to" class="heading-anchor">#</a> 6. Customize where a Global Search link can take you to</h2>
<p>In specific cases, you might want to have your Global Search targeted Resource
to go to Edit and not to Detail, or vice-versa. All you have to do is to add
this static property on your Resource:</p>
<pre>public static $globalSearchLink = 'detail';
</pre>
<hr />
<p>Hope you enjoyed, and in case you want to continue learning Laravel Nova you can
pre-subscribe my <a target="_blank" href="https://www.masteringnova.com">Mastering Nova Course</a> anytime!</p>
<hr />
<p>Once again thanks to <a target="_blank" href="https://twitter.com/brunocfalcao">Bruno</a> for writing this post!</p>
 ]]></summary>

                <updated>2020-05-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 7.4 in 7 code blocks ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-74-in-7-code-blocks"/>

                <id>https://www.stitcher.io/blog/php-74-in-7-code-blocks</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 7.4, the last edition in the 7.* series, brings lots of new and handy changes. This post lists the highlights, though there's much more to this release. You can read all about the full release in this post about <a href="/blog/new-in-php-74">what's new in PHP 7.4</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<hr />
<pre><span class="hl-property">array_map</span>(
    <span class="hl-keyword">fn</span>(<span class="hl-injection"><span class="hl-type">User</span> $user</span>) =&gt; <span class="hl-variable">$user</span>-&gt;<span class="hl-property">id</span>,
    <span class="hl-variable">$users</span>
);
</pre>
<p>Arrow functions, a.k.a. short closures. You can read about them in depth in <a href="/blog/short-closures-in-php">this post</a>.</p>
<hr />
<pre><span class="hl-keyword">class</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">?Foo</span> <span class="hl-property">$foo</span>;
}
</pre>
<p>Type properties. There's quite a lot to tell <a href="/blog/typed-properties-in-php-74">about them</a>.</p>
<hr />
<pre><span class="hl-variable">$data</span>['<span class="hl-value">date</span>'] ??= <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>();
</pre>
<p>The null coalescing assignment operator. If you're unfamiliar with the null coalescing operator, you can read all about <a href="/blog/shorthand-comparisons-in-php">shorthand operators</a> in this blog.</p>
<hr />
<pre><span class="hl-keyword">class</span> <span class="hl-type">ParentType</span> {}
<span class="hl-keyword">class</span> <span class="hl-type">ChildType</span> <span class="hl-keyword">extends</span> <span class="hl-type">ParentType</span> {}

<span class="hl-keyword">class</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">covariantReturnTypes</span>(): <span class="hl-type">ParentType</span>
    { <span class="hl-comment">/* … */</span> }
}

<span class="hl-keyword">class</span> <span class="hl-type">B</span> <span class="hl-keyword">extends</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">covariantReturnTypes</span>(): <span class="hl-type">ChildType</span>
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>Improved type variance. If you're not sure what that's about, you should take a look at this post about <a href="/blog/liskov-and-type-safety">Liskov and type safety</a>.</p>
<hr />
<pre><span class="hl-variable">$result</span> = [...<span class="hl-variable">$arrayA</span>, ...<span class="hl-variable">$arrayB</span>];
</pre>
<p>The array spread operator. There are a few <a href="/blog/new-in-php-74#array-spread-operator-rfc">sidenotes</a> to be made about them.</p>
<hr />
<pre><span class="hl-variable">$formattedNumber</span> = 107_925_284.88;
</pre>
<p>The numeric literal separator, which is only a visual aid.</p>
<hr />
<pre>[preloading]
opcache.preload=/path/to/project/preload.php
</pre>
<p>Preloading improves PHP performance across requests. It's a complicated topic, but I wrote about it <a href="/blog/preloading-in-php-74">here</a>.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-05-23T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The IKEA effect ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/the-ikea-effect"/>

                <id>https://www.stitcher.io/blog/the-ikea-effect</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <h2 id="the-spark"><a href="#the-spark" class="heading-anchor">#</a> The spark</h2>
<p>A few days ago while I was browsing the forums, I stumbled across a discussion that was the spark for this article.
In short the OP was having problems with an expensive query and trying his best to optimize it.
The thread had a lot of responses suggesting ways of optimizing the query like, index this column, use sub selects instead of joins, chunk the results etc…</p>
<p>What was weird for me was the fact that the OP was trying to load 13k options into a select element. I tried to suggest him that even if he manages to optimize the query to a few milliseconds the user experience would be less than poor. I spent time making my case presenting him with alternatives, articles with ux best practices and mobile device optimizations. The focus didn't change. The dedication to improve his existing solution was absolute. Needless to say that the thread is still open to this day…</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="the-revelation"><a href="#the-revelation" class="heading-anchor">#</a> The revelation</h2>
<p>The whole thing made me think how many times I encountered this behavior in my working environment including myself. I tried to find a real life example that simulates this behavior while drinking my early morning coffee. I stretched and carefully rested my cup to my poorly constructed coffee table. I purchased this table 2 years ago from IKEA and spend hours trying to build it only to realise at the end that I was left with one extra screw. I messed up and skipped a part of the instructions but I was done. I wasn't gonna build the whole thing again for one screw.</p>
<p>To this day my coffee table is supported by a string attached to the legs and all my friends visiting know that the table needs to be treated gently.</p>
<h2 id="the-bummer"><a href="#the-bummer" class="heading-anchor">#</a> The bummer</h2>
<p>I immediately came up with the name "The IKEA effect" and I congratulated myself for the coolness of it. Sure enough, after googling it I realized that yep that was a thing: there is a very interesting paper from Michael I. Norton, a professor in Harvard, titled <a target="_blank" href="https://www.hbs.edu/faculty/publication%20files/11-091.pdf">The “IKEA Effect”: When Labor Leads to Love</a> and to sum it up here is the wikipedia definition:</p>
<blockquote>
<p>The IKEA effect is a cognitive bias in which consumers place a disproportionately high value on products they partially created</p>
</blockquote>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/ikea/1.png" srcset="/resources/img/blog/ikea/1-1754x719.png 1754w, /resources/img/blog/ikea/1-1109x454.png 1109w, /resources/img/blog/ikea/1-784x321.png 784w, /resources/img/blog/ikea/1-1568x642.png 1568w, /resources/img/blog/ikea/1-1358x556.png 1358w" sizes="" alt=""></img></p>
<h2 id="the-ikea-effect-revisited"><a href="#the-ikea-effect-revisited" class="heading-anchor">#</a> The IKEA Effect revisited</h2>
<p>In my career as a programmer I noticed this phenomenon's negative side effects quite often. It manifests itself in different ways and in different levels of an organization.</p>
<p>From the top level management dedicating time and effort to define the next big thing only to get grounded by the technical constrains or the level of effort required to build it. From the designer spending days to come up with a high fidelity design that at the end gets negative feedback and has to go back to the drawing board. Finally for the programmer who gets a code review after spending days working on a feature that basically requires rewriting the whole thing!</p>
<h2 id="the-bigger-the-effort-the-greater-the-blindness"><a href="#the-bigger-the-effort-the-greater-the-blindness" class="heading-anchor">#</a> The bigger the effort the greater the blindness</h2>
<p>When working on a solution to a problem, the deeper you go, your focus switches to specifics parts of the problem. Many times those parts might require a disproportional amount of effort in order to solve them.</p>
<p>How many times I found myself searching and furiously going through stackoverflow to make this one thing work! When I finally got this little piece of the solution working, I was so attached to it that I wouldn't even consider the thought that it might not be the right way to do it.</p>
<p>I was ready to defend its honor against anyone who dared to challenge it! At this stage the feedback in any kind or form — either this comes from code review or over the water cooler — the result is tension. The worst part is that the feedback is probably right, but you are already too blind to see or accept it.</p>
<h2 id="the-assembly-manual"><a href="#the-assembly-manual" class="heading-anchor">#</a> The assembly manual</h2>
<p>So how do we stop investing more and more into what we have already worked on, rather than striving for better or more efficient alternatives?</p>
<p>This are my takeaways.</p>
<p><strong>Read the instructions</strong>: don't jump into the solution without understanding the problem. Invest time and ask for clarifications when needed.</p>
<p><strong>Early feedback</strong>: write a summary of your proposed solution and communicate it to your colleagues, make sure that everybody that needs to be involved is aware.</p>
<p><strong>Build a draft</strong>: code it, make it work, don't think about abstractions and future maintainability, just make it as simple as possible. Again ask for feedback and iterate.</p>
<p><strong>Rebuild it</strong>: you've got some feedback that requires you to heavily refactor? Big deal you were going to rewrite the thing anyhow, no hard feelings.</p>
<p><strong>Know when to stop</strong>: if something doesn't feel right, gets weirdly complicated to model it in your solution, then it smells bad. Stop and revisit your approach better now than later. Do you find yourself lost? Struggling to find a way to make it work? Maybe the problem is too hard for your level of expertise. There is no shame in this. Communicate it early with your senior experts ask for tips, pair coding, anything that can help you grow your game to be able to fight the beast.</p>
<p><strong>Wrap it up</strong>: don't try to make every little part perfect. Pay attention to the core of the solution and learn to live with the rest. Ship it and after some time when you are emotionally detached revisit and refactor.</p>
<hr />
<p>Once again thanks to <a target="_blank" href="https://twitter.com/gpanos00">Dimitris</a>, be sure to check him out! If you're interested in discussing your thoughts in this topic, you can share them <a target="_blank" href="https://news.ycombinator.com/item?id=23256032">on HN</a>.</p>
 ]]></summary>

                <updated>2020-05-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Builders and architects: two types of programmers ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/builders-and-architects-two-types-of-programmers"/>

                <id>https://www.stitcher.io/blog/builders-and-architects-two-types-of-programmers</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>You're probably familiar with the feeling: a programmer in your vicinity or online just doesn't seem to get your point of view. Even though there's no doubt they are <em>clearly</em> wrong. These kinds of encounters make you feel misunderstood, frustrated, yes, even angry.</p>
<p>I, too, deal with these feelings on a regular basis. I read a tweet and think to myself: they are so wrong. I get angry because of the misinformation that's spread, the anti-patterns that are promoted, the lack of understanding.</p>
<p>I've had some insights in these kinds of situations though, and I want to share these with you today. I won't be able to tell you who's wrong or right — if there even is such a thing — and it will also take an effort on your part to succeed.</p>
<p>The payoff? A better understanding of why your colleague or that one guy on Reddit thinks such different thoughts than you, as well as a better grip on those circumstances. It allows you to rise above conflicts, become a problem solver instead of a troublemaker.</p>
<p>In this post I'll share a mental framework for programmers to manage these kinds of conflicts. To do that, we'll need to start with a simplified example.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's imagine two types of programmers: builders and architects.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/builders-and-architects/builders-1.png" srcset="/resources/img/blog/builders-and-architects/builders-1-1341x846.png 1341w, /resources/img/blog/builders-and-architects/builders-1-670x422.png 670w, /resources/img/blog/builders-and-architects/builders-1-1500x947.png 1500w, /resources/img/blog/builders-and-architects/builders-1-1161x732.png 1161w, /resources/img/blog/builders-and-architects/builders-1-948x598.png 948w" sizes="" alt=""></img></p>
<p>If you ever had to work in teams — in school, as your job or in hobby projects — you're probably familiar with these two types of people.</p>
<p>The first ones, the builders, are the programmers who get things done. They work efficiently. Besides their daytime job, they come up with these amazing side projects and to the outside world it looks like writing code comes naturally to them.</p>
<p>On the other hand there are architects. They are concerned about sturdy and structurally sound code. They spend hours, sometimes days, debating the right way to solve a problem.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/builders-and-architects/builders-2.png" srcset="/resources/img/blog/builders-and-architects/builders-2-670x422.png 670w, /resources/img/blog/builders-and-architects/builders-2-948x598.png 948w, /resources/img/blog/builders-and-architects/builders-2-1341x846.png 1341w, /resources/img/blog/builders-and-architects/builders-2-1500x947.png 1500w, /resources/img/blog/builders-and-architects/builders-2-1161x732.png 1161w" sizes="" alt=""></img></p>
<p>These two types of programmers seem like opposites. They themselves look at the other group and often think exactly that. They have a different way of handling the same problems. The other group's solutions are so different, they can't possibly be right, or so it seems.</p>
<p>Builders often find architects too rigid and conservative. They follow the rules for the sake of following them, without any practical benefit. Architects in turn, think of builders as careless, too focused on results, instead of thinking about long-term maintainability.</p>
<p>This tension often leads to confrontations between the groups, at the office or online. Interestingly enough, these kinds of discussions focus on trying to change the other person's point of view. I've been guilty of this myself more than I can count.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/builders-and-architects/builders-3.png" srcset="/resources/img/blog/builders-and-architects/builders-3-1341x846.png 1341w, /resources/img/blog/builders-and-architects/builders-3-670x422.png 670w, /resources/img/blog/builders-and-architects/builders-3-1161x732.png 1161w, /resources/img/blog/builders-and-architects/builders-3-1500x947.png 1500w, /resources/img/blog/builders-and-architects/builders-3-948x598.png 948w" sizes="" alt=""></img></p>
<p>What's fascinating about these situations though, is that people from both sides almost never realise there's strength in their differences.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/builders-and-architects/builders-3b.png" srcset="/resources/img/blog/builders-and-architects/builders-3b-1341x846.png 1341w, /resources/img/blog/builders-and-architects/builders-3b-1500x947.png 1500w, /resources/img/blog/builders-and-architects/builders-3b-1161x732.png 1161w, /resources/img/blog/builders-and-architects/builders-3b-948x598.png 948w, /resources/img/blog/builders-and-architects/builders-3b-670x422.png 670w" sizes="" alt=""></img></p>
<p>Instead of focusing on what they disagree on, let's try another approach: let's, for a minute, try to support the other party. Mind you: not just agree with them for the sake of ending a discussion, but actually trying to help them solve their problem, with your skill set.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/builders-and-architects/builders-4.png" srcset="/resources/img/blog/builders-and-architects/builders-4-1500x947.png 1500w, /resources/img/blog/builders-and-architects/builders-4-670x422.png 670w, /resources/img/blog/builders-and-architects/builders-4-1161x732.png 1161w, /resources/img/blog/builders-and-architects/builders-4-1341x846.png 1341w, /resources/img/blog/builders-and-architects/builders-4-948x598.png 948w" sizes="" alt=""></img></p>
<p>Here's how that looks: while architects enjoy abstract thinking, they often have difficulties putting their thoughts into practice: they run into problems they didn't anticipate, or the actual implementation is too complex and they lose their drive. On the other hand, builders enjoy working towards a clear goal, they find energy in a project taking shape. So let's sit them down, together, and combine their strengths.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/builders-and-architects/builders-5.png" srcset="/resources/img/blog/builders-and-architects/builders-5-1161x732.png 1161w, /resources/img/blog/builders-and-architects/builders-5-670x422.png 670w, /resources/img/blog/builders-and-architects/builders-5-948x598.png 948w, /resources/img/blog/builders-and-architects/builders-5-1500x947.png 1500w, /resources/img/blog/builders-and-architects/builders-5-1341x846.png 1341w" sizes="" alt=""></img></p>
<hr />
<p>The illustration is easy enough — right? Though professional programmers still fall in the trap of endless discussions way too often.
In fact, many human beings assume that the world around them thinks like they do. When the reality proves that's not the case, conflicts arise.</p>
<p>When you become aware of this personality trait, both in yourself and in others, you can use that knowledge to both your advantage. The reality is that most people won't have the same vision as you do, it's better to embrace that reality instead of fighting it.</p>
<p>One framework which differentiates between all kinds of personality types is called the Myers-Briggs Type Indicator — MBTI for short. It differentiates between 16 types of personalities. Obviously every person is unique, but those 16 types give an indication of how you and your colleagues think, how you'll react to situations, how you'll handle problems.</p>
<p>MBTI will map your personality into four different aspects:</p>
<ul>
<li>Introvert or Extrovert</li>
<li>Observant or Intuitive</li>
<li>Thinking or Feeling</li>
<li>Judging or Prospecting</li>
</ul>
<p>Like I said, every person is unique, so you're not either introvert or extrovert, you're not only thinking or feeling. It's a scale that balances one way or the other. Based on those aspects though, you can get a better understanding of why other people have such a different approach to the same problem as you do.</p>
<p>For example, builders would lean more towards the intuitive and prospective side, while architects are observant and judging. Builders are imaginative and flexible, architects are organized and practical. One isn't better than the other, rather they should support each other.</p>
<p>Having this knowledge about yourself and your co-workers allows for better team dynamics. At my previous job we mapped our MBTI profiles with around 25 colleagues. We sat down one afternoon to talk about the results. Not only did the majority of people recognise themselves in their profile, it also exposed struggles and hidden frustrations that were never shared before, because no one knew how to deal with them. Now we did.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/builders-and-architects/builders-6.png" srcset="/resources/img/blog/builders-and-architects/builders-6-1341x846.png 1341w, /resources/img/blog/builders-and-architects/builders-6-948x598.png 948w, /resources/img/blog/builders-and-architects/builders-6-1161x732.png 1161w, /resources/img/blog/builders-and-architects/builders-6-670x422.png 670w, /resources/img/blog/builders-and-architects/builders-6-1500x947.png 1500w" sizes="" alt=""></img></p>
<hr />
<p>One thing I want to emphasize at the end of this post, is that my goal was not to promote MBTI. Rather it's to make you think about how people's personalities differ from each other, and how this can result both in conflicts as well as opportunities. MBTI is just an example of how one could visualise these differences.</p>
<p>Understanding there are different kinds of people who think differently than you do, seems like such a simple realisation. Yet the internet and suboptimal or even broken teams show that a principle so easy to understand, is difficult to bring into practice.</p>
<p>If you want to, you can truly change the way you handle inter-personal conflicts. Even though you probably are right, try to think about ways to support your adversary, yes even leveraging them to a higher level. You'll be surprised that you're the one who benefits the most.</p>
<p>If you do want to know your own MBTI profile, you can test it for free online. Again this profile won't tell you who you really are, but it has to power to address the differences in personalities between you and other programmers. There's a great website called <a target="_blank" href="https://www.16personalities.com/">16personalities.com</a> providing a 20-minutes test. I'm interested to see the results! Let me know your profile and check up on others in <a target="_blank" href="https://twitter.com/brendt_gd/status/1262986404231077890">this poll</a>.</p>
<p>Want to share your own thoughts on the topic? You can send me an <a href="mailto:brendt@stitcher.io">email</a> or we can discuss it on <a target="_blank" href="https://news.ycombinator.com/item?id=23243740">HN</a>.</p>
<p>Thanks for reading, until next time!</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-05-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8 in 8 code blocks ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-8-in-8-code-blocks"/>

                <id>https://www.stitcher.io/blog/php-8-in-8-code-blocks</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP 8 brings lots of new features, in this list we'll look at the most outstanding ones. If you want a full list and background information, you can read about all things <a href="/blog/new-in-php-8">new in PHP 8</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<hr />
<pre><span class="hl-keyword">use</span> <span class="hl-type">Support\Attributes\ListensTo</span>;

<span class="hl-keyword">class</span> <span class="hl-type">ProductSubscriber</span>
{
    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ListensTo</span>(<span class="hl-type">ProductCreated</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onProductCreated</span>(<span class="hl-injection"><span class="hl-type">ProductCreated</span> $event</span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-injection"><span class="hl-attribute">#[<span class="hl-type">ListensTo</span>(<span class="hl-type">ProductDeleted</span>::<span class="hl-keyword">class</span>)]</span></span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onProductDeleted</span>(<span class="hl-injection"><span class="hl-type">ProductDeleted</span> $event</span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>Attributes — aka annotations — you can read about them in depth in <a href="/blog/attributes-in-php-8">this post</a>.</p>
<hr />
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">foo</span>(<span class="hl-injection"><span class="hl-type">Foo|Bar</span> $input</span>): <span class="hl-type">int|float</span>;

<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>(<span class="hl-injection"><span class="hl-type">mixed</span> $input</span>): <span class="hl-type">mixed</span>;
</pre>
<p>Union types allows for type hinting several types. There's also a new <code>mixed</code> type which represents <a href="/blog/new-in-php-8#new-mixed-type-rfc">several types</a> at once.</p>
<hr />
<pre><span class="hl-keyword">interface</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">bar</span>(): <span class="hl-keyword">static</span>;
}
</pre>
<p>The <code>static</code> return type is built-in.</p>
<hr />
<pre>[JIT]
opcache.jit=1225
</pre>
<p><a href="/blog/php-jit">The just-in-time compiler</a> for PHP.</p>
<hr />
<pre><span class="hl-variable">$triggerError</span> = <span class="hl-keyword">fn</span>() =&gt; <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">MyError</span>();

<span class="hl-variable">$foo</span> = <span class="hl-variable">$bar</span>['<span class="hl-value">offset</span>'] ?? <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">OffsetDoesNotExist</span>('<span class="hl-value">offset</span>');
</pre>
<p><code>throw</code> can be used in expressions.</p>
<hr />
<pre><span class="hl-keyword">try</span> {
    <span class="hl-comment">// Something goes wrong</span>
} <span class="hl-keyword">catch</span> (<span class="hl-type">MySpecialException</span>) {
    <span class="hl-type">Log</span>::<span class="hl-property">error</span>(&quot;<span class="hl-value">Something went wrong</span>&quot;);
}
</pre>
<p>Non-capturing catches: no need to specify an exception variable if you don't need it.</p>
<hr />
<pre><span class="hl-property">setcookie</span>(
    <span class="hl-property">name</span>: '<span class="hl-value">test</span>',
    <span class="hl-property">expires</span>: <span class="hl-property">time</span>() + 60 * 60 * 2,
);
</pre>
<p><a href="/blog/php-8-named-arguments">Named arguments</a>.</p>
<hr />
<pre><span class="hl-variable">$result</span> = <span class="hl-keyword">match</span>(<span class="hl-variable">$input</span>) {
    0 =&gt; &quot;<span class="hl-value">hello</span>&quot;,
    '<span class="hl-value">1</span>', '<span class="hl-value">2</span>', '<span class="hl-value">3</span>' =&gt; &quot;<span class="hl-value">world</span>&quot;,
};
</pre>
<p>The <code>match</code> expression as an improvement to the <code>switch</code> expression.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>There's even more. If you want a full list, you can find it <a href="/blog/new-in-php-8">on this blog</a>.</p>
<p>What feature are you looking forward to the most? Let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">email</a>.</p>
 ]]></summary>

                <updated>2020-05-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ array_chunk in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/array-chunk-in-php"/>

                <id>https://www.stitcher.io/blog/array-chunk-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP has a lot of undiscovered native functions for many devs. Usually, we don't discover these functions until there is a true need for them. <code>array_chunk</code> is certainly one of these functions for me personally. In this article, we will discover what <code>array_chunk</code> is, what it does, and see it used in action.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="array_chunk-and-how-it-works"><a href="#array_chunk-and-how-it-works" class="heading-anchor">#</a> <code>array_chunk</code> and how it works</h2>
<p><code>array_chunk</code> is a pretty nifty name for slicing an array into chunks. This is essentially what the function does, it reads an array, and splits it into chunks.</p>
<p>Let me explain this in developer terms: we have an array, <code>[1, 2, 3, 4, 5, 6, 7, 8]</code>, we use <code>array_chunk</code> on the array, specifying we want chunks of 2 items. The output would look similar to below.</p>
<pre>$input = [1, 2, 3, 4, 5, 6, 7, 8];

array_chunk($input, 2);

[
    0 =&gt; [1, 2], 
    1 =&gt; [3, 4], 
    2 =&gt; [5, 6], 
    3 =&gt; [7, 8],
]
</pre>
<p>Pretty cool eh? With this function, you can quickly see how it can be utilized for statistical purposes, especially with segment averaging.</p>
<p>This function accepts 3 parameters as follows:</p>
<ul>
<li>The <code>array</code>
</li>
<li>The size of the chunks required as an <code>int</code>
</li>
<li>A <code>boolean</code> to instruct the functions to preserve the keys of the original array or to not. <em>Note</em>: the default is <code>false</code>.</li>
</ul>
<h2 id="a-real-life-problem"><a href="#a-real-life-problem" class="heading-anchor">#</a> A real-life problem</h2>
<p>Walk with me now through this scenario: my boss wants to know for each working week, the average profits from his shop. Each working week has 5 days.</p>
<p>So, let's say for argument's sake say we have just queried the last 20 days of shop sales from the shop's database. The data returned populate our array with 20 entries and therefore has 4 working weeks.</p>
<p>Now this leaves us with the problem at hand, we need to calculate the average sales across every 5 days for 4 weeks. Follow me through this next section to achieve the result.</p>
<h2 id="average-segments-with-array_chunk"><a href="#average-segments-with-array_chunk" class="heading-anchor">#</a> Average segments with <code>array_chunk</code></h2>
<p>We know our data array has 20 entries, and we know that we need an average of each week of sales (5 entries). Let's utilize <code>array_chunk</code> with a little bit of extra native PHP to do the calculations.</p>
<pre><span class="hl-variable">$sales</span> = [
   250.70, 220.10, 233, 243.50, 255,
   200, 300, 234, 350, 222,
   237.99, 200.30, 150.98, 201, 209,
   200, 300, 240, 203, 280,
];

<span class="hl-comment">// Split the array into groups of five, </span>
<span class="hl-comment">//  representing a 5 days working week.</span>
<span class="hl-variable">$salesPerWeek</span> = <span class="hl-property">array_chunk</span>(<span class="hl-variable">$sales</span>, 5);

<span class="hl-comment">// Map all items to their averages, week by week.</span>
<span class="hl-variable">$averageSales</span> = <span class="hl-property">array_map</span>(
   <span class="hl-keyword">fn</span>(<span class="hl-injection"><span class="hl-type">array</span> $items</span>) =&gt; <span class="hl-property">array_sum</span>(<span class="hl-variable">$items</span>) / <span class="hl-property">count</span>(<span class="hl-variable">$items</span>),
   <span class="hl-variable">$salesPerWeek</span>
);
</pre>
<p>Now, if we print the contents of <code>$averageSales</code> we will get something like the following:</p>
<pre>[
    240.46,
    261.2,
    199.854,
    244.6,
]
</pre>
<p>Let's break down the code for complete transparency:</p>
<ul>
<li>First, we have our array with 20 entries of sales data for each day.</li>
<li>Next, we use <code>array_chunk</code> to split it into groups of five.</li>
<li>Then we use <code>array_map</code> on each chunk, and use <code>array_sum</code> to divide by the count of the chunk to give us the average.</li>
</ul>
<p>And that is it!</p>
<p>This type of functionality could be used in many statistical applications that require segmentation. The example in this article tries to show you how <code>array_chunk</code> works in layman terms with a bit of a pretend use-case behind it. I hope this was interesting, if you would like to see any more of my content, please check out my blog, <a target="_blank" href="https://www.codewall.co.uk/">https://www.codewall.co.uk/</a></p>
 ]]></summary>

                <updated>2020-05-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Combining event sourcing and stateful systems ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/combining-event-sourcing-and-stateful-systems"/>

                <id>https://www.stitcher.io/blog/combining-event-sourcing-and-stateful-systems</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In this two-part series, my colleague <a target="_blank" href="https://twitter.com/freekmurze">Freek</a> and I will discuss the architecture of a project we're working on. We will share our insights and answers to problems we encountered along the way. This part will be about the design of the system, while <a target="_blank" href="https://freek.dev/1634-mixing-event-sourcing-in-a-traditional-laravel-app">Freek's part</a> will look at the concrete implementation.</p>
<p>Let's set the scene.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>This project is one of the larger ones we've worked on. In the end it will serve hundreds of thousands of users, handle large amounts of financial transactions and standalone tenant-specific installations will need to be created on the fly.</p>
<p>One key requirement is that the product ordering flow — the core of the business — can be easily reported on, as well as tracked throughout history.</p>
<p>Besides this front-facing client process, there's also a complex admin panel to manage products. Within this context, there's little to no need for reporting or tracking history of the admin activities; the main goal here is to have an easy-to-use product management system.</p>
<p>I hope you understand that I deliberately am keeping these terms a little vague because obviously this isn't an open-source project, though I think the concepts of "product management" and "orders" is clear enough for you to understand the design decisions we've made.</p>
<p>Let’s first discuss an approach of how to design this system based on my <a href="/blog/laravel-beyond-crud">Laravel beyond CRUD</a> series.</p>
<p>In such a system there would probably be two domain groups: <code>Product</code> and <code>Order</code>, and two applications making use of both these domains: an <code>AdminApplication</code> and a <code>CustomerApplication</code>.</p>
<p>A simplified version would look something like this:</p>
<div class="image-noborder mobile-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_1_mobile.png"><img src="/resources/img/blog/event-sourcing/es_1_mobile.png" srcset="/resources/img/blog/event-sourcing/es_1_mobile-638x2049.png 638w, /resources/img/blog/event-sourcing/es_1_mobile-403x1294.png 403w, /resources/img/blog/event-sourcing/es_1_mobile-494x1586.png 494w, /resources/img/blog/event-sourcing/es_1_mobile-285x915.png 285w, /resources/img/blog/event-sourcing/es_1_mobile-570x1830.png 570w" sizes="" alt=""></img></a></p>
</div> 
<div class="image-noborder desktop-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_1.png"><img src="/resources/img/blog/event-sourcing/es_1.png" srcset="/resources/img/blog/event-sourcing/es_1-549x562.png 549w, /resources/img/blog/event-sourcing/es_1-951x975.png 951w, /resources/img/blog/event-sourcing/es_1-776x795.png 776w, /resources/img/blog/event-sourcing/es_1-1098x1125.png 1098w, /resources/img/blog/event-sourcing/es_1-1228x1258.png 1228w" sizes="" alt=""></img></a></p>
</div> 
<p>Having used this architecture successfully in previous projects, we could simply rely on it and call it a day. There are a few downsides with it though, specifically for this new project: we have to keep in mind that reporting and historical tracking are key aspects of the ordering process. We want to treat them as such in our code, and not as a mere side effect.</p>
<p>For example: we could use our activity log package to keep track of "history messages" about what happened with an order. We could also start writing custom queries on the order and history tables to generate reports.</p>
<p>However, these solutions only work properly when they are minor side effects of the core business. In this case, they are not. So Freek and I were tasked with figuring out a design for this project that made reporting and historical tracking an easy-to-maintain and easy-to-use, core part of the application.</p>
<p>Naturally we looked at event sourcing, a wonderful and flexible solution that fulfills the above requirements. Nothing comes for free though: event sourcing requires quite a lot of extra code to be written in order to do otherwise simple things. Where you'd normally have simple CRUD actions manipulating data in the database, you now have to worry about dispatching events, handling them with projectors and reactors, whilst always keeping versioning in mind.</p>
<p>While it was clear that an event sourced system would solve many of the problems, it would also introduce lots of overhead, even in places where it wouldn't add any value.</p>
<p>Here's what I mean with that: if we decide to event source the <code>Orders</code> module, which relies on data from the <code>Products</code> module, we also need to event source that one, because otherwise we could end up with an invalid state. If <code>Products</code> weren't event sourced, and one was deleted, we couldn't rebuild the <code>Orders</code> state anymore, since it's missing information.</p>
<p>So either we event source everything, or find a solution for this problem.</p>
<h2 id="event-source-all-the-things?!"><a href="#event-source-all-the-things?!" class="heading-anchor">#</a> Event source all the things?!</h2>
<p>From playing around with event sourcing in some of our hobby projects, we were painfully aware that we shouldn't underestimate the complexity it adds. Furthermore, Greg Young stated that event sourcing a whole system is often a bad idea — he has a <a target="_blank" href="https://www.youtube.com/watch?v=LDW0QWie21s">whole talk</a> on misconceptions about event sourcing and is worth a watch!</p>
<p>It was clear to us that we did not want to event source the whole application; it simply wouldn't make sense to do so. The only alternative was to find a way to combine a stateful system, together with an event sourced system, but surprisingly, we couldn't find many resources on this topic.</p>
<p>Nevertheless, we did some labour intensive research, and managed to find an answer to our question. The answer didn't come from the event sourcing community though, but rather from well-established DDD practices: bounded contexts.</p>
<p>If we wanted the <code>Products</code> module to be an independent, stateful system, we had to clearly respect the boundaries between <code>Products</code> and <code>Orders</code>. Instead of one monolithic application, we would have to treat these two modules as two separate contexts — separate services, which were only allowed to speak with each other in such a way that it be could guaranteed the <code>Order</code> context would never end up in an invalid state.</p>
<p>If the <code>Order</code> context is built whereby it doesn't rely on the <code>Product</code> context directly, it wouldn't matter how that <code>Product</code> context was built.</p>
<p>When discussing this with Freek, I phrased it like this: think of <code>Products</code> as a separate service, accessed via a REST API. How would we guarantee our event sourced application would still work, even if the API goes offline, or makes changes to its data structure.</p>
<p>Obviously we wouldn't actually build an API to communicate between our services, since they would live within the same codebase on the same server. Still it was a good mindset to start designing the system.</p>
<p>The boundary would look like this, where each service has its own internal design.</p>
<div class="image-noborder mobile-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_2_mobile.png"><img src="/resources/img/blog/event-sourcing/es_2_mobile.png" srcset="/resources/img/blog/event-sourcing/es_2_mobile-494x1053.png 494w, /resources/img/blog/event-sourcing/es_2_mobile-349x744.png 349w, /resources/img/blog/event-sourcing/es_2_mobile-553x1179.png 553w, /resources/img/blog/event-sourcing/es_2_mobile-247x526.png 247w, /resources/img/blog/event-sourcing/es_2_mobile-428x912.png 428w" sizes="" alt=""></img></a></p>
</div> 
<div class="image-noborder desktop-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_2.png"><img src="/resources/img/blog/event-sourcing/es_2.png" srcset="/resources/img/blog/event-sourcing/es_2-518x333.png 518w, /resources/img/blog/event-sourcing/es_2-733x472.png 733w, /resources/img/blog/event-sourcing/es_2-898x578.png 898w, /resources/img/blog/event-sourcing/es_2-1037x667.png 1037w, /resources/img/blog/event-sourcing/es_2-1160x747.png 1160w" sizes="" alt=""></img></a></p>
</div> 
<p>If you read my Laravel beyond CRUD series, you're already familiar with how the <code>Product</code> context works. There's nothing new going on over there. The <code>Order</code> context deserves a little more background information though.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="event-source-some-parts"><a href="#event-source-some-parts" class="heading-anchor">#</a> Event source some parts</h2>
<p>So let's look at the event sourced part. I assume you that if you're reading this post, you have at least an interest in event sourcing, so I won't explain everything in detail.</p>
<p>The <code>OrderAggregateRoot</code> will keep track of everything that happens within this context and will be the entry point for applications to talk with. It will also dispatch events, which are stored and propagated to all reactors and projectors.</p>
<p>Reactors will handle side effects which will never be replayed and projectors will make projections. In our case these are simple Laravel models. These models can be read from any other context, though they can only be written to from within projectors.</p>
<div class="image-noborder mobile-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_3_mobile.png"><img src="/resources/img/blog/event-sourcing/es_3_mobile.png" srcset="/resources/img/blog/event-sourcing/es_3_mobile-389x418.png 389w, /resources/img/blog/event-sourcing/es_3_mobile-275x295.png 275w, /resources/img/blog/event-sourcing/es_3_mobile-550x591.png 550w, /resources/img/blog/event-sourcing/es_3_mobile-616x663.png 616w, /resources/img/blog/event-sourcing/es_3_mobile-477x513.png 477w" sizes="" alt=""></img></a></p>
</div> 
<div class="image-noborder desktop-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_3.png"><img src="/resources/img/blog/event-sourcing/es_3.png" srcset="/resources/img/blog/event-sourcing/es_3-1183x767.png 1183w, /resources/img/blog/event-sourcing/es_3-748x484.png 748w, /resources/img/blog/event-sourcing/es_3-916x593.png 916w, /resources/img/blog/event-sourcing/es_3-529x342.png 529w, /resources/img/blog/event-sourcing/es_3-1058x685.png 1058w" sizes="" alt=""></img></a></p>
</div>
<p>One design decision we made here was to not split our read and write models, for now we rely on a spoken <em>and</em> written convention that these models are only written to via their projectors. One example of such a projection model would be an <code>Order</code>.</p>
<p>The most important rule to remember is that the whole state of the <code>Order</code> context should be able to be rebuilt only from its stored events.</p>
<p>So how do we pull in data from other contexts? How can the <code>Order</code> context be notified when something happens within the <code>Product</code> context that's relevant to it? One thing is for sure: all relevant information regarding <code>Products</code> will need to be stored as events within the <code>Order</code> context; since within that context, events are the only source of truth.</p>
<p>To achieve this, we introduced a third kind of event listener. There already are projectors and reactors; now we add the concept of subscribers. These subscribers are allowed to listen to events from other contexts, and handle them accordingly within their current context. Most likely, they will almost always convert external events to internal, stored ones.</p>
<div class="image-noborder mobile-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_4_mobile.png"><img src="/resources/img/blog/event-sourcing/es_4_mobile.png" srcset="/resources/img/blog/event-sourcing/es_4_mobile-247x526.png 247w, /resources/img/blog/event-sourcing/es_4_mobile-494x1053.png 494w, /resources/img/blog/event-sourcing/es_4_mobile-349x744.png 349w, /resources/img/blog/event-sourcing/es_4_mobile-553x1179.png 553w, /resources/img/blog/event-sourcing/es_4_mobile-428x912.png 428w" sizes="" alt=""></img></a></p>
</div> 
<div class="image-noborder desktop-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_4.png"><img src="/resources/img/blog/event-sourcing/es_4.png" srcset="/resources/img/blog/event-sourcing/es_4-518x333.png 518w, /resources/img/blog/event-sourcing/es_4-1160x747.png 1160w, /resources/img/blog/event-sourcing/es_4-733x472.png 733w, /resources/img/blog/event-sourcing/es_4-1037x667.png 1037w, /resources/img/blog/event-sourcing/es_4-898x578.png 898w" sizes="" alt=""></img></a></p>
</div>
<p>From the moment events are stored within the <code>Order</code> context, we can safely forget about any dependency on the <code>Product</code> context.</p>
<p>Some readers might think that we're duplicating data by copying events between these two contexts. We're of course storing an <code>Orders</code> specific event, based on when a <code>Product</code> was <code>created</code>, so yes, some data will be copied. There are, however, more benefits to this than you might think.</p>
<p>First of all: the <code>Product</code> context doesn't need to know anything about which other contexts will use its data. It doesn't have to take event versioning into account, because its events will never be stored. This allows us to work in the <code>Product</code> context as if it was any normal, stateful application, without the complexity event sourcing adds.</p>
<p>Second: there will be more than just the <code>Order</code> context that's event sourced, and all of these contexts can individually listen to relevant events triggered within the <code>Product</code> context.</p>
<p>And third: we don't have to store a full copy of the original <code>Product</code> events since each context can cherry-pick and store the data that's relevant for its own use case.</p>
<h2 id="what-about-data-migrations?"><a href="#what-about-data-migrations?" class="heading-anchor">#</a> What about data migrations?</h2>
<p>A new question arose.</p>
<p>Say this system has been in production for a year, and we decide to add a new context that's event sourced; one which also requires knowledge about the <code>Product</code> context. The original <code>Product</code> events weren't stored — because of the reasons listed above — so how can we build an initial state for our new context?</p>
<p>The answer is this: at the time of deployment, we'll have to read all product data, and send relevant events to the newly added context, based on the existing products. This one-time migration is an added cost, though it gives us the freedom to work within the <code>Product</code> context without ever having to worry about the outside. For this project that's a price worth paying.</p>
<h2 id="final-integration"><a href="#final-integration" class="heading-anchor">#</a> Final integration</h2>
<p>Finally we're able to consume data in our applications gathered from all contexts, by using readonly models. Again, in our case and as of now, these models are readonly by convention; we might change that in the future.</p>
<div class="image-noborder mobile-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_5_mobile.png"><img src="/resources/img/blog/event-sourcing/es_5_mobile.png" srcset="/resources/img/blog/event-sourcing/es_5_mobile-456x1399.png 456w, /resources/img/blog/event-sourcing/es_5_mobile-322x988.png 322w, /resources/img/blog/event-sourcing/es_5_mobile-721x2213.png 721w, /resources/img/blog/event-sourcing/es_5_mobile-644x1976.png 644w, /resources/img/blog/event-sourcing/es_5_mobile-558x1712.png 558w" sizes="" alt=""></img></a></p>
</div> 
<div class="image-noborder desktop-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_5.png"><img src="/resources/img/blog/event-sourcing/es_5.png" srcset="/resources/img/blog/event-sourcing/es_5-786x894.png 786w, /resources/img/blog/event-sourcing/es_5-1243x1414.png 1243w, /resources/img/blog/event-sourcing/es_5-555x631.png 555w, /resources/img/blog/event-sourcing/es_5-1111x1263.png 1111w, /resources/img/blog/event-sourcing/es_5-962x1094.png 962w" sizes="" alt=""></img></a></p>
</div>
<p>Communication from applications to the <code>Product</code> context is done like any normal stateful application would do. Communication between applications and event sourced contexts such as <code>Orders</code> is done via its aggregate root.</p>
<p>Now, here's a final overview. Some arrows are still missing from this diagram, but I hope that the relevant flow between and inside contexts and applications is clear.</p>
<div class="image-noborder"></div>
<div class="image-noborder mobile-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_6_mobile.png"><img src="/resources/img/blog/event-sourcing/es_6_mobile.png" srcset="/resources/img/blog/event-sourcing/es_6_mobile-855x2213.png 855w, /resources/img/blog/event-sourcing/es_6_mobile-662x1713.png 662w, /resources/img/blog/event-sourcing/es_6_mobile-382x988.png 382w, /resources/img/blog/event-sourcing/es_6_mobile-540x1397.png 540w, /resources/img/blog/event-sourcing/es_6_mobile-764x1977.png 764w" sizes="" alt=""></img></a></p>
</div> 
<div class="image-noborder desktop-only">
<p><a target="_blank" href="/resources/img/blog/event-sourcing/es_6.png"><img src="/resources/img/blog/event-sourcing/es_6.png" srcset="/resources/img/blog/event-sourcing/es_6-1286x1414.png 1286w, /resources/img/blog/event-sourcing/es_6-1150x1264.png 1150w, /resources/img/blog/event-sourcing/es_6-813x893.png 813w, /resources/img/blog/event-sourcing/es_6-575x632.png 575w, /resources/img/blog/event-sourcing/es_6-996x1095.png 996w" sizes="" alt=""></img></a></p>
</div>
<hr />
<p>The key in solving our problem was to look at DDD's bounded contexts. They describe strict boundaries within our codebase - ones that we cannot simply cross whenever we want. Sure this adds a layer of complexity, though it also adds the freedom to build each context whatever way we want, without having to worry about supporting others.</p>
<p>The final piece of the puzzle was to solely rely on events as a means of communication between contexts. Once again it adds a layer of complexity, but also a means of decoupling and flexibility.</p>
<p>Now it's time to take a deep dive into how we programmed this within a Laravel project. Here's my colleague Freek with <a target="_blank" href="https://freek.dev/1634-mixing-event-sourcing-in-a-traditional-laravel-app">part two</a>.</p>
 ]]></summary>

                <updated>2020-04-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Minor versions, breaking changes ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/minor-versions-breaking-changes"/>

                <id>https://www.stitcher.io/blog/minor-versions-breaking-changes</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>When my colleague Sebastian <a target="_blank" href="https://sebastiandedeyne.com/composer-semver-and-underlying-dependency-changes/">wrote</a> about how bumping major versions isn't a breaking change, I would wholeheartedly agree.</p>
<p>I can't anymore. At least, not with how composer works today.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>See yesterday, we stumbled upon a breaking change. And yet we didn't do any major version upgrades. Luckily another colleague of mine, Ruben, discovered the issue before pushing it to production.</p>
<p>Here's what happened.</p>
<p>One of our projects is now nearing its two-year anniversary mark, so suffice to say it has had its fair share of version bumps. After two years of development, these were some packages we used:</p>
<pre><span class="hl-property">{</span>
    <span class="hl-value">&quot;laravel/framework&quot;</span>: <span class="hl-value">&quot;^6.5&quot;</span>,
    <span class="hl-value">&quot;league/commonmark&quot;</span>: <span class="hl-value">&quot;^0.17.5&quot;</span>,
    <span class="hl-value">&quot;spatie/laravel-view-components&quot;</span>: <span class="hl-value">&quot;^1.2&quot;</span>,

    // …
<span class="hl-property">}</span>
</pre>
<p>First of all, <code>laravel/framework:^6.5</code>. We usually wait a month or two before updating to the next major Laravel version. As of today we're running 7 — which was needed to fix what went wrong.</p>
<p>Next there's <code>league/commonmark:^0.17.5</code>; a very specific dependency, added in May, 2018. At the time, this specific dependency was needed: according to the changelog it <code>Fixed incorrect version constant value (again)</code>. If we didn't use this version, it would conflict with other packages.</p>
<p>Two years went by, and <code>league/commonmark</code> has since tagged a first stable release. This is something they should have done way more early — but that's a topic for another day.</p>
<p>Finally there's <code>spatie/laravel-view-components:^1.2</code>. A package that has been archived recently, in favour of Laravel's blade components in version 7. Again, back in the day it made lots of sense to use this package. We might remove it at one point in the future, but this of course requires time, and costs money for our client. It isn't something we can "just do".</p>
<p>With the stage being set, it's time to look into the issue. Yesterday we ran a <code>composer update</code>, and things broke.</p>
<p>More specifically, our <code>spatie/laravel-view-components</code> package simply stopped working. Instead of rendering the view component, it only showed the render tag instead. It turned out it was a <a target="_blank" href="https://github.com/spatie/laravel-view-components/issues/21">known issue</a> as of version <code>1.3.0</code>, and <a target="_blank" href="https://github.com/spatie/laravel-view-components/pull/22">fixed</a> in <code>1.3.1</code>. This fix already existed when we ran our disastrous <code>composer update</code>, yet we never received it. Our <code>spatie/laravel-view-components</code> seemed to be locked on <code>1.3.0</code>, and didn't want to update to <code>1.3.1</code>.</p>
<p>Whenever you find yourself in such a pickle, don't panic and keep calm: composer can help you. Simply use <code>composer why-not spatie/laravel-view-components:1.3.1</code> and it will tell you exactly what's wrong.</p>
<p>It turned out that with <code>spatie/laravel-view-components:1.3.1</code>, its <code>laravel/framework</code> dependency version <a target="_blank" href="https://github.com/spatie/laravel-view-components/commit/1ae57dcd9919de9019d30801cfb7dc2deea0cdbf">was bumped</a> from <code>^6.0</code> to <code>^6.18</code>.</p>
<p>That in itself shouldn't be a problem, we require <code>laravel/framework:^6.5</code> in our project, so we should be able to load <code>^6.18</code> just fine.</p>
<p>Unfortunately that didn't happen. You see, <code>laravel/framework</code> added a dependency on <code>league/commonmark:^1.1</code> in version <code>6.10</code>. In practice, this addition has the same effect as updating the major version of a dependency: from nothing to <code>^1.1</code>.</p>
<p>Again, that change in itself isn't a breaking change, yet it <em>did</em> prevent <code>laravel/framework</code> in our project from updating higher than <code>6.9</code>, because of our requirement on <code>league/commonmark:^0.17.5</code>. That in turn prevented <code>spatie/laravel-view-components</code> updating from <code>1.3.0</code> to <code>1.3.1</code>, which contained a much needed bugfix.</p>
<hr />
<p>So who's to blame? Let's point the finger at myself first: we should have updated <code>league/commonmark</code> sooner. You could also say that combining a bugfix and a dependency version bump, like <code>spatie/laravel-view-components</code> did with <code>1.3.1</code>, should be avoided. Yet if the version bump is needed for a fix to work, there's little you can do.</p>
<p>You could say that <code>laravel/framework</code> shouldn't have updated one of its (implicit) dependencies, yet it's a perfectly normal thing to do, especially if the update fixes a security issue.</p>
<p>The solution, by the way, consisted of updating <code>laravel/framework</code> to <code>^7.0</code> — we had to do this anyway sooner or later — and removing the <code>league/commonmark</code> dependency. So I don't think this change should be avoided by any open source vendors. Open source code should push us towards regular updates, I encourage that myself regularly.</p>
<p>The real problem though, is that composer never notified us that <code>laravel/framework</code> wasn't able to update further than <code>6.9</code> because of underlying conflicts. If you're not carefully managing each dependency, you're in danger of getting stuck on an outdated dependency, which might prevent much needed bug fixes being installed.</p>
<p>As far as I know, there's no option that can be passed to <code>composer update</code> which can notify you about such situations and I think that would be a good future addition.</p>
<p>My colleague Freek pointed out that there is an external library that does exactly this: <a target="_blank" href="https://github.com/Soullivaneuh/composer-versions-check">https://github.com/Soullivaneuh/composer-versions-check</a>. It'd be nice to have this functionality built-into composer.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
 ]]></summary>

                <updated>2020-03-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Event driven server in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/event-driven-php"/>

                <id>https://www.stitcher.io/blog/event-driven-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Lately I've been tinkering with a unique kind of architecture for PHP applications. I want to tell you up front that I don't think it will solve any real-life problems soon; still I want to involve you in the thought-process. Who knows what kind of great ideas might arise?</p>
<p>In this post I'll go through the architecture step-by-step and address its benefits as well as its downsides — at least, the ones I can think of right now. I do have a proof-of-concept codebase open sourced, and I'll share insights from it throughout this post.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>So, first things first, what the architecture is about. It's a long-running PHP server, with its entire state loaded in memory, built from stored events. In other words: it's event sourcing as we know it in PHP, but all aggregates and projections are loaded in-memory and never stored on disk.</p>
<p>Let's break it down!</p>
<h2 id="a-long-running-php-server"><a href="#a-long-running-php-server" class="heading-anchor">#</a> A long-running PHP server</h2>
<p>The first pillar of this architecture is a long running server. The modern PHP landscape offers several battle-tested solutions for managing these kinds of processes: frameworks like ReactPHP, Amphp and Swoole allowed the PHP community to venture into another, unexplored world, while day-to-day PHP was most often related to its characterizing fast request/response cycle.</p>
<p>This fast request/response cycle is of course one of the things that made PHP great: you never had to worry about leaking state or keeping everything in sync: when a request comes in, a clean PHP process is started, and your application boots from 0. After the response is sent, the application gets completely destroyed.</p>
<p>I'm not proposing we ditch this battle-tested technique altogether; the fast request/response cycle is actually a critical part of the architecture I'll be describing. On the other hand, always booting the whole application from scratch has its downsides.</p>
<p>In the architecture I'm describing, an application is split into two parts: one part is a regular PHP app, accepting HTTP requests and generating responses, while the other part is a behind-the-scenes backend server that's always running. A server that always has the whole application state loaded in memory, which allows the clients — our regular PHP apps — to connect with it, read data and store events.</p>
<p>Because the whole application state is always loaded in memory, you never need to perform database queries, spending resources on mapping data from the database to objects, or performance issues like circular references between ORM entities.</p>
<p>This sounds nice in theory, but we probably still need to be able to perform complex queries - something that databases are highly optimised for. It's clear that this architecture will require us to rethink certain aspects we're used to in regular PHP applications. I'll come back to this later.</p>
<p>First, let's look at the second pillar: event sourcing.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="event-sourcing"><a href="#event-sourcing" class="heading-anchor">#</a> Event sourcing</h2>
<p>Why would I suggest to make event sourcing part of the core of this architecture? You could very well have a long running server with all data loaded in-memory from a normal database.</p>
<p>Let's go down that road for a moment: say a client performs an update and sends it to the backend server. The server will need to store the data in the database, as well as refresh its in-memory state. Such systems will need to take care of updating the application state properly so that everything is correct after an update.</p>
<p>The most naive approach would be to perform the updates in the database and reload the whole application state, which in practice isn't possible due to performance issues. Another approach could be to keep track of everything that needs to happen when an update is received, and the most flexible way to do that is by using events.</p>
<p>If we're naturally leaning towards an event-driven system to keep the in-memory state synchronised, why then add the overhead of storing everything in a database and require an ORM to map the data back to objects? That's why event sourcing is the better approach: it solves all state syncing problems automatically, and offers a performance gain since you don't have to communicate with a database and work with an ORM.</p>
<p>What about complex queries though? How would you search, for example, a product store containing millions of items, when everything is loaded in memory. PHP doesn't particularly excel at these kinds of tasks. But again, event sourcing offers a solution: projections. You're perfectly able to make an optimised projection for a given task, and even store it in a database! This could be a lightweight in-memory SQLite database, or a full-blown MySQL or PostgreSQL server.</p>
<p>Most importantly, these databases aren't part of the application core anymore. No longer are they the source of truth, but rather useful tools living on the edge of the application's core and very much comparable to building optimised search indices like ElasticSearch or Algolia. You can destroy these data sources at any point in time, and rebuild them from the stored events.</p>
<p>That brings us to the final reason why event sourcing is such a great match for this architecture. When the server requires a reboot — because of a server crash or after a deploy — event sourcing offers you a way to rebuild the application's state much faster: snapshots.</p>
<p>In this architecture, a snapshot of the whole application state would be stored once or twice a day. It's a point where the server can be rebuilt from, without needing to replay all events.</p>
<p>As you can see, there are several benefits by building an event sourced system within this architecture. Now we're moving on to the last pillar: the clients.</p>
<h2 id="clients"><a href="#clients" class="heading-anchor">#</a> Clients</h2>
<p>I've mentioned this before: with "clients" I mean server-side PHP applications communicating with the centralised backend server. They are normal PHP applications, only living a short time within the typical request/response cycle.</p>
<p>You can use whatever existing framework you want for these clients, as long as there's a way to use the event-server instead of directly communicating with eg. a database. Instead of using an ORM like Doctrine in Symfony or Eloquent in Laravel, you'd be using a small communication layer to communicate via sockets with the backend server.</p>
<p>Also keep in mind that the backend server and clients can share the same codebase, which means that from a developer's point of view, you don't need to worry about communication between a client and the server, it's done transparently.</p>
<p>Take the example of bank accounts with a balance. With this architecture, you'd write code like this:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">AccountsController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>(): <span class="hl-type">View</span>
    {
        <span class="hl-variable">$accounts</span> = <span class="hl-type">Account</span>::<span class="hl-property">all</span>();

        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">View</span>('<span class="hl-value">accounts.index</span>', [
            '<span class="hl-value">accounts</span>' =&gt; <span class="hl-variable">$accounts</span>,
        ]);
    }
}
</pre>
<p>Keep in mind that I mainly work in a Laravel context and I'm used to the Eloquent ORM. If you prefer to use a repository pattern, that's also fine.</p>
<p>Behind the scenes, <code>Account::all()</code> or <code>$accountRepository-&gt;all()</code> will not perform database queries, rather they will send a small message to the backend server, which will send the accounts, from memory, back to the client.</p>
<p>If we're making a change to the accounts balance, that's done like so:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">BalanceController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">increase</span>(<span class="hl-injection"><span class="hl-type">Account</span> $account, <span class="hl-type">int</span> $amount</span>): <span class="hl-type">Redirect</span>
    {
        <span class="hl-variable">$aggregateRoot</span> = <span class="hl-type">AccountAggregateRoot</span>::<span class="hl-property">find</span>(<span class="hl-variable">$account</span>);
   
        <span class="hl-variable">$aggregateRoot</span>-&gt;<span class="hl-property">increaseBalance</span>(<span class="hl-variable">$amount</span>);

        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">Redirect</span>(
            [<span class="hl-type">AccountsController</span>::<span class="hl-keyword">class</span>, '<span class="hl-value">index</span>'], 
            [<span class="hl-variable">$account</span>]
        );
    }
}
</pre>
<p>Behind the scenes, <code>AccountAggregateRoot::increaseBalance()</code> will send an event to the server, which will store it and notify all relevant subscribers.</p>
<p>If you're wondering what such an implementation of <code>AccountAggregateRoot</code> might look like, here's a simplified version:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">AccountAggregateRootRoot</span> <span class="hl-keyword">extends</span> <span class="hl-type">AggregateRoot</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">increaseBalance</span>(<span class="hl-injection"><span class="hl-type">int</span> $amount</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">event</span>(<span class="hl-keyword">new</span> <span class="hl-type">BalanceIncreased</span>(<span class="hl-variable">$amount</span>));

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }
}
</pre>
<p>And finally this is what the <code>Account</code> entity looks like. Notice the lack of ORM-style configuration; these are simple in-memory PHP objects!</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Account</span> <span class="hl-keyword">extends</span> <span class="hl-type">Entity</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$uuid</span>;

    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>;

    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$balance</span> = 0;
}
</pre>
<p>One final note to make: remember that I mentioned PHP's fast request/response cycle would actually be critical? Here's why: if we're sending updates to the server, we don't need to worry about broadcasting those updates back to the clients. Every client generally only lives for a second or two, so there's little to worry about keeping them in sync.</p>
<h2 id="the-downsides"><a href="#the-downsides" class="heading-anchor">#</a> The downsides</h2>
<p>All of this sounds interesting in theory, but what about in practice? What about performance? How much RAM will you need to store everything in memory? Will we be able to optimise reading the state by performing complex queries? How will snapshots be stored? What about versioning?</p>
<p>Lots of questions are still unanswered. The goal of this post was not to provide all answers, but rather share some thoughts and questions with you, the community. Who knows what you can come up with?</p>
<p>I mentioned that the code for this is open source, you can take a look at it <a target="_blank" href="https://github.com/spatie/event-server">over here</a>. I'm looking forward to hearing your feedback, on <a target="_blank" href="https://www.reddit.com/r/PHP/comments/fk3qne/event_driven_application_server_in_php/?">Reddit</a>, via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2020-03-13T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Bitwise booleans in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/bitwise-booleans-in-php"/>

                <id>https://www.stitcher.io/blog/bitwise-booleans-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In my <a href="/blog/enums-without-enums">previous post</a> I wrote about applying enum patterns in PHP, without native enum support.</p>
<p>In that post, I gave the example of a "date range boundaries" enum, one that represents which boundaries are included in the range, and which are not. It had four possible values:</p>
<ul>
<li>
<code>Boundaries::INCLUDE_NONE();</code>
</li>
<li>
<code>Boundaries::INCLUDE_START();</code>
</li>
<li>
<code>Boundaries::INCLUDE_END();</code>
</li>
<li>
<code>Boundaries::INCLUDE_ALL();</code>
</li>
</ul>
<p>To represent these boundaries, I stored two boolean flags on the enum value classes: <code>$startIncluded</code> and <code>$endIncluded</code>.</p>
<p>In this post, I want to show another way to store these two boolean flags, using bitmasks.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Here's a quick recap of what (part of) our enum class looked like:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Boundaries</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">bool</span> <span class="hl-property">$startIncluded</span> = <span class="hl-keyword">false</span>;
    <span class="hl-keyword">private</span> <span class="hl-type">bool</span> <span class="hl-property">$endIncluded</span> = <span class="hl-keyword">false</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">startIncluded</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">endIncluded</span>;
    }

    <span class="hl-comment">// …</span>
}
</pre>
<p>In this case, we're using <em>two</em> variables to store <em>two</em> boolean values.</p>
<p>Them being booleans though, means they can only have one of two values: <code>true</code> or <code>false</code>; <code>1</code> or <code>0</code>. Instead of using a whole byte, we only need one bit to store this value.</p>
<p>Hang on though, a whole byte? — It's actually a lot more: 16 bytes to be exact. PHP stores all variables in a structure called a <code>zval</code>, which reserves memory not only for the payload, but also type information, bit flags and what not. You can take a look at it <a target="_blank" href="https://github.com/php/php-src/blob/master/Zend/zend_types.h#L302-L328">here</a>.</p>
<p>Of those 16 bytes, there's 8 reserved per <code>zval</code> to store a payload in; that's 64 bits!</p>
<p>Now, as a precursor, let's make clear that you probably will never need these kinds of micro-optimisations. Boolean bitmasks are often used in game development, compilers and the like, because they are very memory-efficient. In web applications, though, you can be assured you will probably never need them.</p>
<p>Nevertheless, it's a cool, geeky thing to know, and possible in PHP.</p>
<p>So let's store these two flags in one variable.</p>
<pre>abstract class Boundaries
{
    protected int $inclusionMask = 0b00;
}
</pre>
<p>What's happening here? We're making use of the <a target="_blank" href="https://www.php.net/manual/en/language.types.integer.php#language.types.integer.syntax">binary notation</a> of integers to easily work with individual bits. If you ever learned about binary systems in school or somewhere else, you know that <code>0b00</code> equals 0, <code>0b01</code> equals 1, <code>0b10</code> equals 2 and <code>0b11</code> equals 3. <code>0b</code> is a prefix that PHP uses to know you're writing binary, and <code>00</code> are the two actual bits.</p>
<p>Now that we've got two bits to work with, it's easy to store two boolean values in them. Let's say that the rightmost bit represents <code>endIncluded</code>, and the leftmost bit represents <code>startIncluded</code>.</p>
<p>So <code>0b01</code> means that the start boundary is not included, while the end boundary is; <code>0b11</code> means both are included — you get the gist.</p>
<p>Now that we know how to store data in bits, we still need a way of reading the information in our <code>startIncluded()</code> and <code>endIncluded()</code> methods: we don't want to program everything in binary.</p>
<p>Here's where <a target="_blank" href="https://www.php.net/manual/en/language.operators.bitwise.php">bitwise operators</a> come into play, more specifically the <code>and</code> operator.</p>
<p>Take the following two binary values:</p>
<pre>0b0100101;
0b1010101;
</pre>
<p>What happens when we apply an <code>and</code> operation on both of these values? The result will have all bits set to <code>1</code> wherever both bits were <code>1</code> in the two original values:</p>
<pre>0b0100101;
0b1010101;
</pre>
<p>This is the end result:</p>
<pre>0b0000101;
</pre>
<p>Back to our boundaries example. How can we know whether the start is included or not? Since the start boundary is represented by the leftmost bit, we can apply a bitmask on our inclusion variable. If we want to know whether the start bit is set, we simply need to do an <code>and</code> operation between the inclusion mask, and the binary value <code>0b10</code>.</p>
<p>How so? Since we're only interested in knowing the value of the start boundary, we'll make a mask for that bit only. If we apply an <code>and</code> operation between these two values, the result will always be <code>0b00</code>, unless the start bit was actually set.</p>
<p>Here's an example where the start bit is <code>0</code>:</p>
<pre>0b10; // The mask we're applying
0b01; // The inclusion mask

0b00; // The result
</pre>
<p>And here's one where the start bit is <code>1</code>:</p>
<pre>0b10; // The mask we're applying
0b10; // The inclusion mask

0b10; // The result
</pre>
<p>The end bit will always be <code>0</code> in this case, because the mask we're applying has it set to <code>0</code>. Hence, whatever value is stored for the end boundary in the inclusion mask, will always result in <code>0</code>.</p>
<p>So how to do this in PHP? By using the binary <code>and</code> operator, which is a single <code>&amp;</code>:</p>
<pre>public function startIncluded(): bool 
{
    return $this-&gt;inclusionMask &amp; 0b10;
}

public function endIncluded(): bool 
{
    return $this-&gt;inclusionMask &amp; 0b01;
}
</pre>
<p>PHP's dynamic type system will automatically cast the result, <code>0</code> or a numeric value, to a boolean. If you want to be more explicit though, you can write it like so:</p>
<pre>public function startIncluded(): bool 
{
    return ($this-&gt;inclusionMask &amp; 0b10) !== 0;
}

public function endIncluded(): bool 
{
    return ($this-&gt;inclusionMask &amp; 0b01) !== 0;
}
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>Let's make clear that you shouldn't be doing this for performance motivations in PHP. There might even be edge cases where this approach would be less optimal, because our inclusion mask can't be garbage collected unless there are no reference anymore to <em>any</em> of the boolean flags.</p>
<p><em>However</em>, if you're working with several boolean flags at once, it might be useful to store them in one variable instead of several, to reduce cognitive load. You could think of "storing the boolean values" as a behind-the-scenes implementation detail, while the public API of a class still provides a clear way of working with them.</p>
<p>So, who knows, there might be cases where this technique is useful. If you have some real-life use cases, be sure to let me know on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2020-02-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Enums without enums in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/enums-without-enums"/>

                <id>https://www.stitcher.io/blog/enums-without-enums</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Enums are still lacking in PHP — <strong><a href="/blog/php-enums">SCRATCH THAT: enums are added in PHP 8.1</a></strong> — yet there is a clean way to have enum-like behaviour in your code bases, without using  external dependencies. Take the example of <a href="/blog/comparing-dates">date range boundaries</a>: its boundaries can be included or excluded. Here's how a <code>Boundaries</code> enum would be used:</p>
<pre><span class="hl-variable">$dateRange</span> = <span class="hl-type">DateRange</span>::<span class="hl-property">make</span>(
    '<span class="hl-value">2020-02-01</span>', 
    '<span class="hl-value">2020-03-01</span>', 
    <span class="hl-type">Boundaries</span>::<span class="hl-property">INCLUDE_ALL</span>()
);
</pre>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>This is what the constructor signature of <code>DateRange</code> looks like:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">$start, $end, <span class="hl-type">Boundaries</span> $boundaries</span>);
</pre>
<p>That's the first requirement: <strong>we want to use the type system to ensure only valid enum values are used</strong>.</p>
<p>Next, we want to be able to ask the enum which boundaries are included, like so:</p>
<pre><span class="hl-variable">$dateRange</span>-&gt;<span class="hl-property">boundaries</span>-&gt;<span class="hl-property">startIncluded</span>();
<span class="hl-variable">$dateRange</span>-&gt;<span class="hl-property">boundaries</span>-&gt;<span class="hl-property">endIncluded</span>();
</pre>
<p>This means that each enum value should support its own implementation of <code>startIncluded</code> and <code>endIncluded</code>.</p>
<p>That's the second requirement: <strong>we want our enums to support value-specific behaviour</strong>.</p>
<p>On first sight, the easiest solution is to have a <code>Boundaries</code> class, and implement <code>startIncluded</code> and <code>endIncluded</code> like so:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Boundaries</span>
{
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">INCLUDE_NONE</span> = '<span class="hl-value">none</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">INCLUDE_START</span> = '<span class="hl-value">start</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">INCLUDE_END</span> = '<span class="hl-value">end</span>';
    <span class="hl-keyword">private</span> <span class="hl-keyword">const</span> <span class="hl-property">INCLUDE_ALL</span> = '<span class="hl-value">all</span>';

    <span class="hl-keyword">private</span> <span class="hl-type">string</span> <span class="hl-property">$value</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_START</span>(): <span class="hl-type">self</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">self</span>(<span class="hl-type">self</span>::<span class="hl-property">INCLUDE_START</span>);
    }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">string</span> $value</span>) 
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> = <span class="hl-variable">$value</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> === <span class="hl-type">self</span>::<span class="hl-property">INCLUDE_START</span>
            <span class="hl-operator">||</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> === <span class="hl-type">self</span>::<span class="hl-property">INCLUDE_ALL</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> === <span class="hl-type">self</span>::<span class="hl-property">INCLUDE_END</span>
            <span class="hl-operator">||</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">value</span> === <span class="hl-type">self</span>::<span class="hl-property">INCLUDE_ALL</span>;
    }
}
</pre>
<p>In short: using conditionals on an enum's value to add behaviour.</p>
<p>For this example, it's a clean enough solution. However: it doesn't scale that well. Imagine our enum needs more complex value-specific functionality; you often end up with large functions containing large conditional blocks.</p>
<p>The more conditionals, the more paths your code can take, the more complex it is to understand and maintain, and the more prone to bugs.</p>
<p>That's the third requirement: <strong>we want to avoid using conditionals on enum values</strong>.</p>
<p>In summary, we want our enums to match these three requirements:</p>
<ul>
<li>Enum values should be strongly typed, so that the type system can do checks on them</li>
<li>Enums should support value-specific behaviour</li>
<li>Value-specific conditions should be avoided at all costs</li>
</ul>
<p>Polymorphism can offer a solution here: each enum value can be represented by its own class, extending the <code>Boundaries</code> enum. Therefore, each value can implement its own version of <code>startIncluded</code> and <code>endIncluded</code>, returning a simple boolean.</p>
<p>Maybe we'd make something like this:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Boundaries</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_NONE</span>(): <span class="hl-type">IncludeNone</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">IncludeNone</span>();
    }
    
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">abstract</span> <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span>;

    <span class="hl-keyword">abstract</span> <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span>;
}
</pre>
<p>And have a concrete implementation of <code>Boundaries</code> like this — you can imagine what the other three would look like:</p>
<pre><span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">IncludeNone</span> <span class="hl-keyword">extends</span> <span class="hl-type">Boundaries</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
    }
} 
</pre>
<p>While there's more initial work to program these enums, we now meet all requirements.</p>
<p>There's one more improvement to be made. There's no need to use dedicated classes for specific values; they will never be used on their own. So instead of making four classes extending <code>Boundaries</code>, we could use anonymous classes:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Boundaries</span>
{
    <span class="hl-keyword">abstract</span> <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span>;

    <span class="hl-keyword">abstract</span> <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_NONE</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span> 
        {
            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>; 
            }

            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>; 
            }
        };
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_START</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span> 
        {
            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>; 
            }

            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>; 
            }
        };
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_END</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span> 
        {
            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>; 
            }

            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>; 
            }
        };
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_ALL</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span> 
        {
            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>; 
            }

            <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span> {
                <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>; 
            }
        };
    }
}
</pre>
<p>Ok, I was mistaken: there were two more improvements to be made. This is a lot of repeated code! But again there's a solution for that! Let's simply define two properties on each value-specific class (<code>$startIncluded</code> and <code>$endIncluded</code>) and let's implement their getters on the abstract <code>Boundaries</code> class instead!</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Boundaries</span>
{
    <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$startIncluded</span>;
    <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$endIncluded</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">startIncluded</span>(): <span class="hl-type">bool</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">startIncluded</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">endIncluded</span>(): <span class="hl-type">bool</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">endIncluded</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_NONE</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span> 
        {
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$startIncluded</span> = <span class="hl-keyword">false</span>;
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$endIncluded</span> = <span class="hl-keyword">false</span>;
        };
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_START</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span>
        {
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$startIncluded</span> = <span class="hl-keyword">true</span>;
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$endIncluded</span> = <span class="hl-keyword">false</span>;
        };
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_END</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span>
        {
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$startIncluded</span> = <span class="hl-keyword">false</span>;
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$endIncluded</span> = <span class="hl-keyword">true</span>;
        };
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">INCLUDE_ALL</span>(): <span class="hl-type">Boundaries</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-keyword">class</span> <span class="hl-type">extends</span> <span class="hl-type">Boundaries</span>
        {
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$startIncluded</span> = <span class="hl-keyword">true</span>;
            <span class="hl-keyword">protected</span> <span class="hl-type">bool</span> <span class="hl-property">$endIncluded</span> = <span class="hl-keyword">true</span>;
        };
    }
}
</pre>
<p>The above is my favourite approach to implement enums in PHP. If there's one downside I can think of, it's that they require a little setup work, though I find that this is a small, one-off cost, that pays off highly in the long run.</p>
 ]]></summary>

                <updated>2020-02-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP in 2020 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-in-2020"/>

                <id>https://www.stitcher.io/blog/php-in-2020</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's no secret among web developers and programmers in general: PHP doesn't have the best reputation. Despite still being one of the most used languages to build web applications; over the years PHP has managed to get itself a reputation of messy codebases, inexperienced developers, insecure code, an inconsistent core library, and what not.</p>
<p>While many of the arguments against PHP still stand today, there's also a bright side: you <em>can</em> write clean and maintainable, fast and reliable applications in PHP.</p>
<p>In this post, I want to look at this bright side of PHP development. I want to show you that, despite its many shortcomings, PHP is a worthwhile language to learn. I want you to know that the PHP 5 era is coming to an end. That, if you want to, you can write modern and clean PHP code, and leave behind much of the mess it was 10 years ago.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>So let's look at how the language has changed, matured even, over the past few years.
I want to ask you to set aside any prejudice for just a few minutes, and possibly be surprised by what PHP is today.</p>
<p>Let's dive in.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="history-summarized"><a href="#history-summarized" class="heading-anchor">#</a> History summarized</h2>
<p>Before diving into details, let's review how PHP, the language, is developed these days.
We're at version 7.4 now, and <a href="/blog/new-in-php-8">PHP 8</a> will be the next version after that, at the end of 2020.</p>
<p>Ever since the late 5.* era, the core team tries to keep a <a target="_blank" href="https://www.php.net/supported-versions.php">consistent yearly release cycle</a>,
and have succeeded in doing so for the past four years.</p>
<p>In general, every new release is actively supported for two years,
and gets another year of "security fixes only".
The goal is to motivate developers to stay up-to-date as much as possible:
small upgrades every year are easier than making the jump between 5.4 to 7.0, for example.</p>
<p>Lastly, PHP 5.6 was the latest 5.* release, with 7.0 being the next one.
If you want to know what happened to PHP 6, you can listen to this episode of the <a target="_blank" href="https://www.phproundtable.com/episode/what-happened-to-php-6">PHP Roundtable podcast</a>.</p>
<p>PHP's development these days is done by a group of volunteers, some of them are paid by their employers to work on the core full time. Most discussion of how the language is evolved happens on a <a target="_blank" href="https://externals.io/">mailing list</a>.</p>
<p>With all of that out of the way, let's debunk some common misconceptions about modern PHP.</p>
<h2 id="php's-type-system"><a href="#php's-type-system" class="heading-anchor">#</a> PHP's type system</h2>
<p>PHP started out as a very weakly and dynamically typed language, which had its benefits at the time. Ever since people started to use PHP for larger projects though, the shortcomings of its type system became clear, and the need for stronger type support arose.</p>
<p>Today, PHP is a rather unique language: it still allows you to write completely dynamically and weakly typed code, but also has a much stronger, opt-in type system. Combined with static analysis, tools like <a target="_blank" href="https://github.com/vimeo/psalm">Psalm</a>, <a target="_blank" href="https://github.com/phan/phan">Phan</a> and <a target="_blank" href="https://github.com/phpstan/phpstan">PHPStan</a>, you can write secure, strongly typed and statically analysed code.</p>
<p>Take, for example, a look at this snippet of PHP code, using its modern type system in full:</p>
<pre>&lt;?php

<span class="hl-keyword">declare</span>(strict_types=1);

<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$intProperty</span> = 2;

    <span class="hl-keyword">public</span> <span class="hl-type">?string</span> <span class="hl-property">$nullableString</span> = <span class="hl-keyword">null</span>;

    <span class="hl-keyword">private</span> <span class="hl-type">Bar</span> <span class="hl-property">$bar</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">Bar</span> $bar</span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">bar</span> = <span class="hl-variable">$bar</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">withInt</span>(<span class="hl-injection"><span class="hl-type">int</span> $value</span>): <span class="hl-type">self</span>
    {
        <span class="hl-variable">$clone</span> = <span class="hl-keyword">clone</span> <span class="hl-variable">$this</span>;
    
        <span class="hl-variable">$clone</span>-&gt;<span class="hl-property">intProperty</span> = <span class="hl-variable">$value</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$clone</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">unionTypes</span>(<span class="hl-injection"><span class="hl-type">int|float</span> $input</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// Union types will be added in PHP 8</span>
    }
}
</pre>
<p>Truth be told, there's one important feature still missing in PHP's type system: generics. There's hope they will be added, but there's nothing concrete yet. In case of typed arrays, you'll need to rely on docblocks to get proper IDE support:</p>
<pre><span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">int[] </span>*/</span>
<span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$arrayOfInts</span> = [];
</pre>
<p>And while typed arrays are a common use case for generics, solvable with docblocks, there's a lot more functionality we're missing out on because they are not in the language… yet.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="php's-syntax"><a href="#php's-syntax" class="heading-anchor">#</a> PHP's syntax</h2>
<p>The 7.* era has done many good things in terms of making PHP a more mature language when it comes to syntax. To illustrate this I've made a non-exhaustive list of new things in PHP.</p>
<p>Array <a href="/blog/array-destructuring-with-list-in-php">destructuring</a>:</p>
<pre>[<span class="hl-variable">$a</span>, <span class="hl-variable">$b</span>] = <span class="hl-variable">$array</span>;
</pre>
<p>The <a href="/blog/shorthand-comparisons-in-php">null coalescing</a> operator:</p>
<pre><span class="hl-variable">$value</span> = <span class="hl-variable">$object</span>-&gt;<span class="hl-property">property</span> ?? '<span class="hl-value">fallback if null</span>';

<span class="hl-variable">$value</span> = <span class="hl-variable">$array</span>['<span class="hl-value">foo</span>'] ?? &quot;<span class="hl-value">fallback if key doesn't exists</span>&quot;; 
</pre>
<p>The null coalescing assignment operator:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">get</span>(<span class="hl-injection"><span class="hl-type">string</span> $input</span>): <span class="hl-type">string</span> 
{
    <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">cache</span>[<span class="hl-variable">$input</span>] ??= <span class="hl-variable">$this</span>-&gt;<span class="hl-property">sanitize</span>(<span class="hl-variable">$input</span>);
}
</pre>
<p>Array spreading:</p>
<pre><span class="hl-variable">$a</span> = [<span class="hl-comment">/* … */</span>];
<span class="hl-variable">$b</span> = [<span class="hl-comment">/* … */</span>];

<span class="hl-variable">$mergedArray</span> = [...<span class="hl-variable">$a</span>, ...<span class="hl-variable">$b</span>];
</pre>
<p>Variadic functions:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">get</span>(<span class="hl-injection">Foo ...$foos</span>): <span class="hl-type">void</span>
{
    <span class="hl-keyword">foreach</span>(<span class="hl-variable">$foos</span> <span class="hl-keyword">as</span> <span class="hl-variable">$foo</span>) {
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>Argument unpacking:</p>
<pre><span class="hl-variable">$this</span>-&gt;<span class="hl-property">get</span>(...<span class="hl-variable">$arrayOfFoo</span>);
</pre>
<p><a href="/blog/typed-properties-in-php-74">Typed properties</a>:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$intProperty</span>;
</pre>
<p><a href="/blog/short-closures-in-php">Arrow functions</a>, also called short closures:</p>
<pre><span class="hl-variable">$ids</span> = <span class="hl-property">array_map</span>(<span class="hl-keyword">fn</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>): <span class="hl-type">int</span> =&gt; <span class="hl-variable">$post</span>-&gt;<span class="hl-property">id</span>, <span class="hl-variable">$posts</span>);
</pre>
<p>Generators:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">make</span>(<span class="hl-injection"><span class="hl-type">array</span> $input</span>): <span class="hl-type">Generator</span>
{
    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$input</span> <span class="hl-keyword">as</span> <span class="hl-variable">$item</span>) {
        <span class="hl-keyword">yield</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">doSomethingWith</span>(<span class="hl-variable">$item</span>);
    }
}
</pre>
<p>And quite a lot more. I hope that it's clear from this list that PHP is still evolving today, and you can be sure there's more good stuff to come.</p>
<h2 id="php's-performance"><a href="#php's-performance" class="heading-anchor">#</a> PHP's performance</h2>
<p>Back in the 5.* days, PHP's performance was… average at best.
With 7.0 though, large parts of PHP's core were rewritten from the ground up,
resulting in two or three times performance increases.
Furthermore, each 7.* release has had a positive impact on performance.</p>
<p>Words don't suffice though. Let's look at benchmarks.
Luckily other people have spent lots of time in benchmarking PHP performance.
I find that <a target="_blank" href="https://kinsta.com/blog/php-benchmarks/">Kinsta</a> has a good updated list.</p>
<p>The latest performance related feature is called <a href="/blog/preloading-in-php-74">preloading</a>, which basically allows you to store compiled parts of your PHP code in memory. You can look at some benchmarks <a href="/blog/php-preload-benchmarks">over here</a>.</p>
<p>When <a href="/blog/new-in-php-8">PHP 8</a> arrives, we'll also have a <a href="/blog/php-jit">JIT compiler</a> at our disposal, promising interesting performance improvements, and allowing PHP to enter new areas besides web development.</p>
<h2 id="frameworks-and-ecosystem"><a href="#frameworks-and-ecosystem" class="heading-anchor">#</a> Frameworks and ecosystem</h2>
<p>Moving on to what's done by the community <em>with</em> PHP. Let's be clear: PHP isn't just WordPress anymore, on the contrary.</p>
<p>In general there are two major web application frameworks, and a few smaller ones: <a target="_blank" href="https://symfony.com/">Symfony</a> and <a target="_blank" href="https://laravel.com/">Laravel</a>.
Sure there's also Laminas, Yii, Cake, Code Igniter etc.
— but if you want to know what modern PHP development looks like, you're good with one of the first two.</p>
<p>Both frameworks have a large ecosystem of packages and products.
Ranging from admin panels and CRMs to standalone packages, CI to profilers,
numerous services like web sockets servers, queuing managers, payment integrations;
honestly there's too much to list.</p>
<p>These frameworks are meant for actual development;
if you're instead in need of pure content management,
platforms like WordPress, CraftCMS and Statamic are improving more and more.</p>
<p>One way to measure the current state of PHP's ecosystem is to look at Packagist, the main package repository for PHP.
It has seen exponential growth.
With ±25 million downloads a day, it's fair to say that the PHP ecosystem isn't the small underdog it used to be.</p>
<p>Take a look at this graph, listing the amount of packages and versions over time.
It can also be found on <a target="_blank" href="https://packagist.org/statistics">the Packagist website</a>.</p>
<p><img src="/resources/img/blog/php-in-2020/packagist.png" srcset="/resources/img/blog/php-in-2020/packagist-1061x452.png 1061w, /resources/img/blog/php-in-2020/packagist-1838x783.png 1838w, /resources/img/blog/php-in-2020/packagist-1501x639.png 1501w, /resources/img/blog/php-in-2020/packagist-2123x905.png 2123w, /resources/img/blog/php-in-2020/packagist-2374x1011.png 2374w" sizes="" alt=""></img></p>
<p>Besides application frameworks and CMSs, we've also seen the rise of asynchronous frameworks the past years.
These are frameworks and servers, written in PHP or other languages,
that allow users to run truly asynchronous PHP code.
Some major players are <a target="_blank" href="https://www.swoole.co.uk/">Swoole</a>, <a target="_blank" href="https://amphp.org/">Amp</a> and <a target="_blank" href="https://reactphp.org/">ReactPHP</a>.</p>
<p>Since we've ventured into the async world,
stuff like web sockets and applications with lots of IO have become actually relevant in the PHP world.</p>
<p>There has also been talk on the internals mailing list to <a target="_blank" href="https://externals.io/message/102415#102415">add libuv to the core</a>.
For those unaware of libuv: it's the same library Node.js uses to allow all its asynchronicity.
Who knows? PHP 8 might be the version adding it to the core!</p>
<h2 id="in-closing"><a href="#in-closing" class="heading-anchor">#</a> In closing</h2>
<p>I hope I was able to show you that PHP has evolved tremendously over the past years, and you're perfectly able to write clean and maintainable code with it.</p>
<p>If you're interested in what PHP code looks like in the wild these days, you can check out <a target="_blank" href="https://github.com/brendt/aggregate.stitcher.io">the source code</a> of one of my own projects, as well as many <a target="_blank" href="https://spatie.be/open-source/packages">open source packages</a> we personally maintain.</p>
<p>So while the language definitely has its drawbacks and 20 years of legacy to carry with it;
I can say with confidence that I enjoy working with it.</p>
<p>In my experience, I'm able to create reliable, maintainable and quality software.
The clients I work for are happy with the end result, as am I.
While it's still possible to do lots of messed up things with PHP,
I'd say it's a great choice for web development if used wisely and correctly.</p>
<p>Don't you agree? Let me know why!
You can reach me via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2020-01-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Preloading benchmarks in PHP 7.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-preload-benchmarks"/>

                <id>https://www.stitcher.io/blog/php-preload-benchmarks</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>After writing about <a href="/blog/preloading-in-php-74">how preloading works</a>, it's time to measure its impact in practice.
Before diving into results, we need to make sure we're all on the same page: what we're measuring, and what not.</p>
<p>Because I want to know whether preloading will have a practical impact on my projects, I'll be running benchmarks on a real project, on the homepage of my hobby project <a target="_blank" href="https://aggregate.stitcher.io/">aggregate.stitcher.io</a>.</p>
<p>This project is a Laravel project, and will obviously do some database calls, view rendering etc. I want to make clear that these benchmarks don't tell anything about the performance of Laravel projects, they <em>only</em> measure the relative performance gains preloading could offer.</p>
<p>Let me repeat that again, just to make sure no one draws wrong conclusions from these results: my benchmarks will <em>only</em> measure whether preloading has a relative performance impact compared to not using it. These benchmarks say nothing about how much performance gain there is. This will depend on several variables: server load, the code being executed, what page you're on, etc.</p>
<p>Let's set the stage.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="preloading-setup"><a href="#preloading-setup" class="heading-anchor">#</a> Preloading Setup</h2>
<p>Since I don't want to measure how much exactly will be gained by using preloading or not, I decided to run these benchmarks on my local machine, using Apache Bench. I'll be sending 5000 requests, with 50 concurrent requests at a time.
The webserver is nginx, using php-fpm. Because there were some bugs in early versions of preloading, we're only able to successfully run our benchmarks as early as PHP 7.4.2.</p>
<p>I'll be benchmarking three scenarios: one with preloading disabled, one with all Laravel and application code preloaded, and one with an optimised list of preloaded classes. The reasoning for that latter one is that preloading also comes with a memory overhead, if we're only preloading "hot" classes — classes that are used very often — we might be able to find a sweet spot between performance gain and memory usage.</p>
<h2 id="preloading-disabled"><a href="#preloading-disabled" class="heading-anchor">#</a> Preloading disabled</h2>
<p>We start php-fpm and run our benchmarks:</p>
<pre>./php-7_4_2/sbin/php-fpm --nodaemonize

ab -n 5000 -c 50 -l http://aggregate.stitcher.io.test:8080/discover
</pre>
<p>These were the results: we're able to process <code>64.79</code> requests per second, with an average time of <code>771ms</code> per request.
This is our baseline scenario, we can compare the next results to this one.</p>
<h2 id="naive-preloading"><a href="#naive-preloading" class="heading-anchor">#</a> Naive preloading</h2>
<p>Next we'll preload all Laravel and application code. This is the naive approach, because we're never using all Laravel classes in a request. Because we're preloading many more files than strictly needed, we'll have to pay a penalty for it. In this case 1165 classes and their dependencies were preloaded, resulting in a total of 1366 functions and 1256 classes to be preloaded.</p>
<p>Like I mentioned before,you can read that info from <code>opcache_get_status</code>:</p>
<pre><span class="hl-property">opcache_get_status</span>()['<span class="hl-value">preload_statistics</span>'];
</pre>
<p>Another metric we get from <code>opcache_get_status</code> is the memory used for preloaded scripts. In this case it's 17.43 MB.
Even though we're preloading more code than we actually need, naive preloading already has a positive impact on performance.</p>
<table>
<tr class="table-head">
    <td></td>
    <td class="right">requests/second</td>
    <td class="right">time per request</td>
</tr>
<tr>
    <td>No preloading</td>
    <td class="right">64.79</td>
    <td class="right">771ms</td>
</tr>
<tr>
    <td>Naive preloading</td>
    <td class="right">79.69</td>
    <td class="right">627ms</td>
</tr>
</table>
<p>You can already see a performance gain: we're able to manage more requests per second, and the average amount of time to process one request has dropped with ±20%.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="optimised"><a href="#optimised" class="heading-anchor">#</a> Optimised</h2>
<p>Finally we want to compare the performance gain when we're using an optimised preloading list. For testing purposes I started the server without preloading enabled, and dumped all classes that are used within that request:</p>
<pre><span class="hl-property">get_declared_classes</span>();
</pre>
<p>Next, I only preloaded these classes, 427 in total. Together with all their dependencies this makes for 643 classes and 1034 functions being preloaded, occupying about 11.76 MB of memory.</p>
<p>These are the benchmark results for this setup:</p>
<table>
<tr class="table-head">
    <td></td>
    <td class="right">requests/second</td>
    <td class="right">time per request</td>
</tr>
<tr>
    <td>No preloading</td>
    <td class="right">64.79</td>
    <td class="right">771ms</td>
</tr>
<tr>
    <td>Naive preloading</td>
    <td class="right">79.69</td>
    <td class="right">627ms</td>
</tr>
<tr>
    <td>Optimised preloading</td>
    <td class="right">86.12</td>
    <td class="right">580ms</td>
</tr>
</table>
<p>That's around a 25% performance gain compared to not using preloading, and an 8% gain compared to using the naive approach. There's a flaw with this setup though, since I generated an optimised preloading list for one specific page. In practice you would probably need to preload more code, if you want all your pages covered.</p>
<p>Another approach could be to monitor which classes are loaded how many times over the period of several hours or days on your production server, and compile a preload list based on those metrics
It's safe to say that preloading — even using the naive "preload everything" approach — has a positive performance impact, also on real-life projects built upon a full-blown framework.
How much exactly there is to be gained will depend on your code, your server and the framework you're using. I'd say go try it out!</p>
 ]]></summary>

                <updated>2020-01-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Upgrade to PHP 7.4 with Homebrew on Mac ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-74-upgrade-mac"/>

                <id>https://www.stitcher.io/blog/php-74-upgrade-mac</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="upgrading-with-homebrew"><a href="#upgrading-with-homebrew" class="heading-anchor">#</a> Upgrading with Homebrew</h2>
<p>Start by making sure brew is up-to-date:</p>
<pre>brew update
</pre>
<p>Next, upgrade PHP:</p>
<pre>brew upgrade php
</pre>
<p>Check the current version by running <code>php -v</code>:</p>
<pre>php -v
</pre>
<p>Restart Nginx or Apache:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<p>And make sure that your local web server also uses PHP 7.4 by visiting this script:</p>
<pre># index.php, accessible to your web server

<span class="hl-property">phpinfo</span>(); <span class="hl-keyword">die</span>();
</pre>
<p>The version should show <code>7.4.x</code>.</p>
<p>Note: if you're using Laravel Valet, please keep on reading,
you need some extra steps in order for the web server to properly work.</p>
<h2 id="valet"><a href="#valet" class="heading-anchor">#</a> Valet</h2>
<p>If you're using Laravel Valet, you should do the following steps to upgrade it:</p>
<pre>composer global update
</pre>
<p>Now run <code>valet install</code>:</p>
<pre>valet install
</pre>
<h2 id="extensions"><a href="#extensions" class="heading-anchor">#</a> Extensions</h2>
<p>Homebrew doesn't support the installation of PHP extensions anymore, you should use pecl instead.
I personally use Imagick, Redis and Xdebug.</p>
<p>They can be installed like so:</p>
<pre>pecl install imagick
pecl install redis
pecl install xdebug
</pre>
<p>You can run <code>pecl list</code> to see which extensions are installed:</p>
<pre>pecl list

# Installed packages, channel pecl.php.net:
# =========================================
# Package Version State
# imagick 3.4.4   stable
# redis   5.1.1   stable
# xdebug  2.8.0   stable
</pre>
<p>You can search for other extensions using <code>pecl search</code>:</p>
<pre>pecl search pdf

# Retrieving data...0%
# ..
# Matched packages, channel pecl.php.net:
# =======================================
# Package Stable/(Latest) Local
# pdflib  4.1.2 (stable)        Creating PDF on the fly with the PDFlib library
</pre>
<p>Make sure to restart your web server after installing new packages:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<p>If you're using Laravel Valet, you should restart it as well.</p>
<pre>valet restart
</pre>
<p>Make sure all extensions are correctly installed and loaded by checking both your PHP webserver and CLI installs:</p>
<pre>php -i | grep redis
</pre>
<pre><span class="hl-property">var_dump</span>(<span class="hl-property">extension_loaded</span>('<span class="hl-value">redis</span>'));
</pre>
<p>If extensions aren't properly loaded, there are two easy fixes.</p>
<p>First, make sure the extensions are added in the correct ini file. You can run <code>php --ini</code> to know which file is loaded:</p>
<pre>Configuration File (php.ini) Path: /usr/local/etc/php/7.4
Loaded Configuration File:         /usr/local/etc/php/7.4/php.ini
Scan for additional .ini files in: /usr/local/etc/php/7.4/conf.d
Additional .ini files parsed:      /usr/local/etc/php/7.4/conf.d/ext-opcache.ini,
/usr/local/etc/php/7.4/conf.d/php-memory-limits.ini
</pre>
<p>Now check the ini file:</p>
<pre>extension=&quot;redis.so&quot;
extension=&quot;imagick.so&quot;
extension=&quot;xdebug.so&quot;
</pre>
<p>Note that if you're testing installed extensions via the CLI, you don't need to restart nginx, apache or Valet.</p>
<p>The second thing you can do, if you're updating from an older PHP version which also used pecl to install extension; is to reinstall every extension individually.</p>
<pre>pecl uninstall imagick
pecl install imagick
</pre>
<h2 id="last-step"><a href="#last-step" class="heading-anchor">#</a> Last step</h2>
<p>Finally you should test and upgrade your projects for <a href="/blog/new-in-php-74">PHP 7.4 compatibility</a>.</p>
 ]]></summary>

                <updated>2019-11-28T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What&#039;s new in PHP 7.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-in-php-74"/>

                <id>https://www.stitcher.io/blog/new-in-php-74</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <h1 id="what's-new-in-php-7.4"><a href="#what's-new-in-php-7.4" class="heading-anchor">#</a> What's new in PHP 7.4</h1>
<p>PHP 7.4 is the latest stable version of PHP. It was released on November 28, 2019 and it's the last version before <a href="/blog/new-in-php-8">PHP 8</a>. It brings lots of new features, syntax additions and fixes. In this post you'll find a list with everything that's new and changed to help you prepare for the upgrade. Let's start though with a few highlights, included in PHP 7.4:</p>
<ul>
<li>
<a href="#arrow-functions-rfc">Arrow functions</a> for cleaner one-liner functions</li>
<li>
<a href="#preloading-rfc">Preloading</a> to improve performance</li>
<li>
<a href="#typed-properties-rfc">Typed properties</a> in classes</li>
<li>
<a href="#improved-type-variance-rfc">Improved type variance</a>
</li>
<li>The <a href="#null-coalescing-assignment-operator-rfc">null coalescing assignment operator</a> as a shorthand</li>
<li>
<a href="#foreign-function-interface-rfc">FFI</a> for better extension development in PHP</li>
<li>Underscores can be used to <a href="#numeric-literal-separator-rfc">format numeric values</a>
</li>
<li>Spread operator <a href="#array-spread-operator-rfc">in arrays</a>
</li>
<li>And more, you can read about it here</li>
</ul>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="new-features"><a href="#new-features" class="heading-anchor">#</a> New features</h2>
<p>PHP 7.4 comes with a remarkable amount of new features. We'll start with a list of all new features, and then look at changes and deprecations.</p>
<p>A note before we dive in though: if you're still on a lower version of PHP,
you'll also want to read what's <a href="/blog/new-in-php-73">new in PHP 7.3</a>.</p>
<hr />
<h3 id="arrow-functions-rfc"><a href="#arrow-functions-rfc" class="heading-anchor">#</a> Arrow functions <small><a target="_blank" href="https://wiki.php.net/rfc/arrow_functions_v2">rfc</a></small></h3>
<p>Arrow functions, also called "short closures", allow for less verbose one-liner functions.</p>
<p>While you'd previously write this:</p>
<pre><span class="hl-property">array_map</span>(<span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">User</span> $user</span>) { 
    <span class="hl-keyword">return</span> <span class="hl-variable">$user</span>-&gt;<span class="hl-property">id</span>; 
}, <span class="hl-variable">$users</span>)
</pre>
<p>You can now write this:</p>
<pre><span class="hl-property">array_map</span>(<span class="hl-keyword">fn</span> (<span class="hl-injection"><span class="hl-type">User</span> $user</span>) =&gt; <span class="hl-variable">$user</span>-&gt;<span class="hl-property">id</span>, <span class="hl-variable">$users</span>)
</pre>
<p>There are a few notes about arrow functions:</p>
<ul>
<li>They can always access the parent scope, there's no need for the <code>use</code> keyword.</li>
<li>
<code>$this</code> is available just like normal closures.</li>
<li>Arrow functions may only contain one expression, which is also the return statement.</li>
</ul>
<p>You can read about them in depth <a href="/blog/short-closures-in-php">here</a>.</p>
<hr />
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<hr />
<h3 id="typed-properties-rfc"><a href="#typed-properties-rfc" class="heading-anchor">#</a> Typed properties <small><a target="_blank" href="https://wiki.php.net/rfc/typed_properties_v2">rfc</a></small></h3>
<p>Class variables can be type hinted:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$name</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">?Foo</span> <span class="hl-property">$foo</span>;
}
</pre>
<p>There's lots to tell about this feature, so I wrote a <a href="/blog/typed-properties-in-php-74">dedicated post</a> about them.</p>
<hr />
<h3 id="improved-type-variance-rfc"><a href="#improved-type-variance-rfc" class="heading-anchor">#</a> Improved type variance <small><a target="_blank" href="https://wiki.php.net/rfc/covariant-returns-and-contravariant-parameters">rfc</a></small></h3>
<p>I also wrote about PHP's type system in <a href="/blog/what-php-can-be">the past</a>,
so it's good to see some improvements are actually arriving in PHP's core.</p>
<p>Type variance is another topic worth its <a href="/blog/liskov-and-type-safety">own blog post</a>,
but in short: you'll be able use covariant return types –</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ParentType</span> {}
<span class="hl-keyword">class</span> <span class="hl-type">ChildType</span> <span class="hl-keyword">extends</span> <span class="hl-type">ParentType</span> {}

<span class="hl-keyword">class</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">covariantReturnTypes</span>(): <span class="hl-type">ParentType</span>
    { <span class="hl-comment">/* … */</span> }
}

<span class="hl-keyword">class</span> <span class="hl-type">B</span> <span class="hl-keyword">extends</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">covariantReturnTypes</span>(): <span class="hl-type">ChildType</span>
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>– and contravariant arguments.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">contraVariantArguments</span>(<span class="hl-injection"><span class="hl-type">ChildType</span> $type</span>)
    { <span class="hl-comment">/* … */</span> }
}

<span class="hl-keyword">class</span> <span class="hl-type">B</span> <span class="hl-keyword">extends</span> <span class="hl-type">A</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">contraVariantArguments</span>(<span class="hl-injection"><span class="hl-type">ParentType</span> $type</span>)
    { <span class="hl-comment">/* … */</span> }
}
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h3 id="null-coalescing-assignment-operator-rfc"><a href="#null-coalescing-assignment-operator-rfc" class="heading-anchor">#</a> Null coalescing assignment operator <small><a target="_blank" href="https://wiki.php.net/rfc/null_coalesce_equal_operator">rfc</a></small></h3>
<p>Next is the null coalescing assignment operator, a shorthand for null coalescing operations. Instead of doing this:</p>
<pre><span class="hl-variable">$data</span>['<span class="hl-value">date</span>'] = <span class="hl-variable">$data</span>['<span class="hl-value">date</span>'] ?? <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>();
</pre>
<p>You can do this:</p>
<pre><span class="hl-variable">$data</span>['<span class="hl-value">date</span>'] ??= <span class="hl-keyword">new</span> <span class="hl-type">DateTime</span>();
</pre>
<p>You can read more about this operator in my post about <a href="/blog/shorthand-comparisons-in-php">PHP shorthands</a>.</p>
<hr />
<h3 id="array-spread-operator-rfc"><a href="#array-spread-operator-rfc" class="heading-anchor">#</a> Array spread operator <small><a target="_blank" href="https://wiki.php.net/rfc/spread_operator_for_array">rfc</a></small></h3>
<p>Next up, it's now possible to use the spread operator in arrays:</p>
<pre><span class="hl-variable">$arrayA</span> = [1, 2, 3];

<span class="hl-variable">$arrayB</span> = [4, 5];

<span class="hl-variable">$result</span> = [0, ...<span class="hl-variable">$arrayA</span>, ...<span class="hl-variable">$arrayB</span>, 6 ,7];

<span class="hl-comment">// [0, 1, 2, 3, 4, 5, 6, 7]</span>
</pre>
<p>Note that this only works with arrays with numerical keys, as of PHP 8.1 it's also possible to <a href="/blog/new-in-php-81#array-unpacking-with-string-keys-rfc">unpack arrays with string keys</a>.</p>
<hr />
<h3 id="numeric-literal-separator-rfc"><a href="#numeric-literal-separator-rfc" class="heading-anchor">#</a> Numeric Literal Separator <small><a target="_blank" href="https://wiki.php.net/rfc/numeric_literal_separator">rfc</a></small></h3>
<p>PHP 7.4 allows for underscores to be used to visually separate numeric values.
It looks like this:</p>
<pre><span class="hl-variable">$unformattedNumber</span> = 107925284.88;

<span class="hl-variable">$formattedNumber</span> = 107_925_284.88;
</pre>
<p>The underscores are simply ignored by the engine.</p>
<hr />
<h3 id="foreign-function-interface-rfc"><a href="#foreign-function-interface-rfc" class="heading-anchor">#</a> Foreign function interface <small><a target="_blank" href="https://wiki.php.net/rfc/ffi">rfc</a></small></h3>
<p>Moving on to some more core-level features: foreign function interface or "FFI" in short, allows us to call C code from userland.
This means that PHP extensions could be written in pure PHP and loaded via composer.</p>
<p>It should be noted though that this is a complex topic.
You still need C knowledge to be able to properly use this feature.</p>
<hr />
<h3 id="preloading-rfc"><a href="#preloading-rfc" class="heading-anchor">#</a> Preloading <small><a target="_blank" href="https://wiki.php.net/rfc/preload">rfc</a></small></h3>
<p>Another lower-level feature is preloading.
It's is an amazing addition to PHP's core,
which can result in some significant performance improvements.</p>
<p>In short: if you're using a framework,
its files have to be loaded and linked on every request.
Preloading allows the server to load PHP files in memory on startup,
and have them permanently available to all subsequent requests.</p>
<p>The performance gain comes of course with a cost:
if the source of preloaded files are changed, the server has to be restarted.</p>
<p>Do you want to know more? I wrote a dedicated post about <a href="/blog/preloading-in-php-74">setting up and using preloading</a> and have also done some <a href="/blog/php-preload-benchmarks">preloading benchmarks</a>.</p>
<hr />
<h3 id="custom-object-serialization-rfc"><a href="#custom-object-serialization-rfc" class="heading-anchor">#</a> Custom object serialization <small><a target="_blank" href="https://wiki.php.net/rfc/custom_object_serialization">rfc</a></small></h3>
<p>Two new magic methods have been added: <code>__serialize</code> and <code>__unserialize</code>.
The difference between these methods and <code>__sleep</code> and <code>__wakeup</code> is discussed in the RFC.</p>
<hr />
<h3 id="reflection-for-references-rfc"><a href="#reflection-for-references-rfc" class="heading-anchor">#</a> Reflection for references <small><a target="_blank" href="https://wiki.php.net/rfc/reference_reflection">rfc</a></small></h3>
<p>Libraries like Symfony's var dumper rely heavily on the reflection API to reliably dump a variable.
Previously it wasn't possible to properly reflect references,
resulting in these libraries relying on hacks to detect them.</p>
<p>PHP 7.4 adds the <code>ReflectionReference</code> class which solves this issue.</p>
<hr />
<h3 id="weak-references-rfc"><a href="#weak-references-rfc" class="heading-anchor">#</a> Weak references <small><a target="_blank" href="https://wiki.php.net/rfc/weakrefs">rfc</a></small></h3>
<p>Weak references are references to objects, which don't prevent them from being destroyed.</p>
<hr />
<h3 id="mb_str_split-added-rfc"><a href="#mb_str_split-added-rfc" class="heading-anchor">#</a> <code>mb_str_split</code> added <small><a target="_blank" href="https://wiki.php.net/rfc/mb_str_split">rfc</a></small></h3>
<p>This function provides the same functionality as <code>str_split</code>, but on multi-byte strings.</p>
<hr />
<h3 id="password-hashing-registry-rfc"><a href="#password-hashing-registry-rfc" class="heading-anchor">#</a> Password Hashing Registry <small><a target="_blank" href="https://wiki.php.net/rfc/password_registry">rfc</a></small></h3>
<p>Internal changes have been made to how hashing libraries are used, so that it's easier for userland to use them.</p>
<p>More specifically, a new function <code>password_algos</code> has been added which returns a list of all registered password algorithms.</p>
<p>The RFC was a little unclear about the benefits, luckily Sara was able to provide <a target="_blank" href="https://www.reddit.com/r/PHP/comments/e4uqha/whats_new_in_php_74/f9gafhv/">some more context</a>:</p>
<blockquote>
<p>It means that ext/sodium (or anyone really) can register password hashing algorithms dynamically. The upshot of which is that argon2i and argon2id will be more commonly available moving forward</p>
</blockquote>
<hr />
<h2 id="changes-and-deprecations"><a href="#changes-and-deprecations" class="heading-anchor">#</a> Changes and deprecations</h2>
<p>Besides new features, there are also lots of changes to the language. Most of these changes are non-breaking, though some might have an effect on your code bases.</p>
<p>Note that deprecation warnings aren't per definition "breaking", but merely a notice to the developer that functionality will be removed or changed in the future. It would be good not to ignore deprecation warnings, and to fix them right away; as it will make the upgrade path for PHP 8.0 more easy.</p>
<hr />
<h3 id="left-associative-ternary-operator-deprecation-rfc"><a href="#left-associative-ternary-operator-deprecation-rfc" class="heading-anchor">#</a> Left-associative ternary operator deprecation <small><a target="_blank" href="https://wiki.php.net/rfc/ternary_associativity">rfc</a></small></h3>
<p>The ternary operator has <a href="/blog/shorthand-comparisons-in-php#ternary-operator">some weird quirks</a> in PHP.
This RFC adds a deprecation warning for nested ternary statements.
In PHP 8, this deprecation will be converted to a compile time error.</p>
<pre>1 <span class="hl-operator">?</span> 2 : 3 <span class="hl-operator">?</span> 4 : 5;   <span class="hl-comment">// deprecated</span>
(1 <span class="hl-operator">?</span> 2 : 3) <span class="hl-operator">?</span> 4 : 5; <span class="hl-comment">// ok</span>
</pre>
<hr />
<h3 id="exceptions-allowed-in-__tostring-rfc"><a href="#exceptions-allowed-in-__tostring-rfc" class="heading-anchor">#</a> Exceptions allowed in <code>__toString</code> <small><a target="_blank" href="https://wiki.php.net/rfc/tostring_exceptions">rfc</a></small></h3>
<p>Previously, exceptions could not be thrown in <code>__toString</code>.
They were prohibited because of a workaround for some old core error handling mechanisms,
but Nikita pointed out that this "solution" didn't actually solve the problem it tried to address.</p>
<p>This behaviour is now changed, and exceptions can be thrown from <code>__toString</code>.</p>
<hr />
<h3 id="concatenation-precedence-rfc"><a href="#concatenation-precedence-rfc" class="heading-anchor">#</a> Concatenation precedence <small><a target="_blank" href="https://wiki.php.net/rfc/concatenation_precedence">rfc</a></small></h3>
<p>If you'd write something like this:</p>
<pre><span class="hl-keyword">echo</span> &quot;<span class="hl-value">sum: </span>&quot; . <span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>;
</pre>
<p>PHP would previously interpret it like this:</p>
<pre><span class="hl-keyword">echo</span> (&quot;<span class="hl-value">sum: </span>&quot; . <span class="hl-variable">$a</span>) + <span class="hl-variable">$b</span>;
</pre>
<p>PHP 8 will make it so that it's interpreted like this:</p>
<pre><span class="hl-keyword">echo</span> &quot;<span class="hl-value">sum: </span>&quot; . (<span class="hl-variable">$a</span> + <span class="hl-variable">$b</span>);
</pre>
<p>PHP 7.4 adds a deprecation warning when encountering an unparenthesized expression containing a <code>.</code> before a <code>+</code> or <code>-</code> sign.</p>
<hr />
<h3 id="array_merge-without-arguments-upgrading"><a href="#array_merge-without-arguments-upgrading" class="heading-anchor">#</a> <code>array_merge</code> without arguments <small><a target="_blank" href="https://github.com/php/php-src/blob/PHP-7.4/UPGRADING#L276">upgrading</a></small></h3>
<p>Since the addition of the spread operator, there might be cases where you'd want to use <code>array_merge</code> like so:</p>
<pre><span class="hl-variable">$merged</span> = <span class="hl-property">array_merge</span>(...<span class="hl-variable">$arrayOfArrays</span>);
</pre>
<p>To support the edge case where <code>$arrayOfArrays</code> would be empty, both <code>array_merge</code> and <code>array_merge_recursive</code> now allow an empty parameter list.
An empty array will be returned if no input was passed.</p>
<hr />
<h3 id="curly-brackets-for-array-and-string-access-rfc"><a href="#curly-brackets-for-array-and-string-access-rfc" class="heading-anchor">#</a> Curly brackets for array and string access <small><a target="_blank" href="https://wiki.php.net/rfc/deprecate_curly_braces_array_access">rfc</a></small></h3>
<p>It was possible to access arrays and string offsets using curly brackets:</p>
<pre><span class="hl-variable">$array</span>{1};
<span class="hl-variable">$string</span>{3};
</pre>
<p>This has been deprecated.</p>
<hr />
<h3 id="invalid-array-access-notices-rfc"><a href="#invalid-array-access-notices-rfc" class="heading-anchor">#</a> Invalid array access notices <small><a target="_blank" href="https://wiki.php.net/rfc/notice-for-non-valid-array-container">rfc</a></small></h3>
<p>If you were to use the array access syntax on, say, an integer; PHP would previously return <code>null</code>.
As of PHP 7.4, a notice will be emitted.</p>
<pre><span class="hl-variable">$i</span> = 1;

<span class="hl-variable">$i</span>[0]; <span class="hl-comment">// Notice</span>
</pre>
<hr />
<h3 id="proc_open-improvements-upgrading"><a href="#proc_open-improvements-upgrading" class="heading-anchor">#</a> <code>proc_open</code> improvements <small><a target="_blank" href="https://github.com/php/php-src/blob/PHP-7.4/UPGRADING#L319">upgrading</a></small></h3>
<p>Changes were made to <code>proc_open</code> so that it can execute programs without going through a shell. This is done by passing an array instead of a string for the command.</p>
<hr />
<h3 id="strip_tags-also-accepts-arrays-upgrading"><a href="#strip_tags-also-accepts-arrays-upgrading" class="heading-anchor">#</a> <code>strip_tags</code> also accepts arrays <small><a target="_blank" href="https://github.com/php/php-src/blob/PHP-7.4/UPGRADING#L259">upgrading</a></small></h3>
<p>You used to only be able to strip multiple tags like so:</p>
<pre><span class="hl-property">strip_tags</span>(<span class="hl-variable">$string</span>, '<span class="hl-value">&lt;a&gt;&lt;p&gt;</span>')
</pre>
<p>PHP 7.4 also allows the use of an array:</p>
<pre><span class="hl-property">strip_tags</span>(<span class="hl-variable">$string</span>, ['<span class="hl-value">a</span>', '<span class="hl-value">p</span>'])
</pre>
<hr />
<h3 id="ext-hash-always-enabled-rfc"><a href="#ext-hash-always-enabled-rfc" class="heading-anchor">#</a> <code>ext-hash</code> always enabled <small><a target="_blank" href="https://wiki.php.net/rfc/permanent_hash_ext">rfc</a></small></h3>
<p>This extension is now permanently available in all PHP installations.</p>
<hr />
<h3 id="pear-not-enabled-by-default-externals"><a href="#pear-not-enabled-by-default-externals" class="heading-anchor">#</a> PEAR not enabled by default <small><a target="_blank" href="https://externals.io/message/103977">externals</a></small></h3>
<p>Because PEAR isn't actively maintained anymore, the core team decided to remove its default installation with PHP 7.4.</p>
<hr />
<h3 id="several-small-deprecations-rfc"><a href="#several-small-deprecations-rfc" class="heading-anchor">#</a> Several small deprecations <small><a target="_blank" href="https://wiki.php.net/rfc/deprecations_php_7_4">rfc</a></small></h3>
<p>This RFC bundles lots of small deprecations, each with their own vote.
Be sure to read a more detailed explanation on the RFC page, though here's a list of deprecated things:</p>
<ul>
<li>The <code>real</code> type</li>
<li>Magic quotes legacy</li>
<li>
<code>array_key_exists()</code> with objects</li>
<li>
<code>FILTER_SANITIZE_MAGIC_QUOTES</code> filter</li>
<li>Reflection <code>export()</code> methods</li>
<li>
<code>mb_strrpos()</code> with encoding as 3rd argument</li>
<li>
<code>implode()</code> parameter order mix</li>
<li>Unbinding <code>$this</code> from non-static closures</li>
<li>
<code>hebrevc()</code> function</li>
<li>
<code>convert_cyr_string()</code> function</li>
<li>
<code>money_format()</code> function</li>
<li>
<code>ezmlm_hash()</code> function</li>
<li>
<code>restore_include_path()</code> function</li>
<li>
<code>allow_url_include</code> ini directive</li>
</ul>
<hr />
<h3 id="other-changes-upgrading"><a href="#other-changes-upgrading" class="heading-anchor">#</a> Other changes <small><a target="_blank" href="https://github.com/php/php-src/blob/PHP-7.4/UPGRADING">upgrading</a></small></h3>
<p>You should always take a look at the full <a target="_blank" href="https://github.com/php/php-src/blob/PHP-7.4/UPGRADING">UPGRADING document</a>
when upgrading PHP versions.</p>
<hr />
<p>Here are some changes highlighted:</p>
<ul>
<li>Calling <code>parent::</code> in a class without a parent is deprecated.</li>
<li>Calling <code>var_dump</code> on a <code>DateTime</code> or <code>DateTimeImmutable</code> instance will no longer
leave behind accessible properties on the object.</li>
<li>
<code>openssl_random_pseudo_bytes</code> will throw an exception in error situations.</li>
<li>Attempting to serialise a <code>PDO</code> or <code>PDOStatement</code> instance will generate
an <code>Exception</code> instead of a <code>PDOException</code>.</li>
<li>Calling <code>get_object_vars()</code> on an <code>ArrayObject</code> instance will return
the properties of the <code>ArrayObject</code> itself, and not the values of the wrapped array or object.
Note that <code>(array)</code> casts are not affected.</li>
<li>
<code>ext/wwdx</code> has been deprecated.</li>
</ul>
<hr />
<h3 id="rfc-voting-process-improvements"><a href="#rfc-voting-process-improvements" class="heading-anchor">#</a> RFC voting process improvements</h3>
<p>This is technically not an update related to PHP 7.4, though it's worth mentioning:
the voting rules for RFC's have been changed.</p>
<ul>
<li>They always need a <a target="_blank" href="https://wiki.php.net/rfc/abolish-narrow-margins">2/3 majority</a> in order to pass.</li>
<li>There are not more short voting periods, all RFCs must be open for at least <a target="_blank" href="https://wiki.php.net/rfc/abolish-short-votes">2 weeks</a>.</li>
</ul>
<hr />
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
 ]]></summary>

                <updated>2019-11-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Preloading in PHP 7.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/preloading-in-php-74"/>

                <id>https://www.stitcher.io/blog/preloading-in-php-74</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>With PHP 7.4, support for preloading was added, a feature that could improve the performance of your code significantly.</p>
<p>In a nutshell, this is how it works:</p>
<ul>
<li>In order to preload files, you need to write a custom PHP script</li>
<li>This script is executed once on server startup</li>
<li>All preloaded files are available in memory for all requests</li>
<li>Changes made to preloaded files won't have any effect, until the server is restarted</li>
</ul>
<p>Let's look at it in depth.</p>
<h2 id="opcache,-but-more"><a href="#opcache,-but-more" class="heading-anchor">#</a> Opcache, but more</h2>
<p>While preloading is built on top of opcache, it's not exactly the same.
Opcache will take your PHP source files, compile it to "opcodes", and store those compiled files on disk.</p>
<p>You can think of opcodes as a low-level representation of your code, that can be easily interpreted at runtime.
So opcache skips the translation step between your source files and what the PHP interpreter actually needs at runtime. A huge win!</p>
<p>But there's more to be gained. Opcached files don't know about other files. If you've got a class <code>A</code> extending from class <code>B</code>, you'd still need to link them together at runtime. Furthermore, opcache performs checks to see whether the source files were modified, and will invalidate its caches based on that.</p>
<p>So this is where preloading comes into play: it will not only compile source files to opcodes, but also link related classes, traits and interfaces together. It will then keep this "compiled" blob of runnable code — that is: code usable by the PHP interpreter — in memory.</p>
<p>When a request arrives at the server, it can now use parts of the codebase that were already loaded in memory, without any overhead.</p>
<p>So, what "parts of the codebase" are we talking about?</p>
<h2 id="preloading-in-practice"><a href="#preloading-in-practice" class="heading-anchor">#</a> Preloading in practice</h2>
<p>For preloading to work, you — developers — have to tell the server which files to load. This is done with a simple PHP script, there really isn't anything difficult to it.</p>
<p>The rules are simple:</p>
<ul>
<li>You provide a preload script and link to it in your php.ini file using <code>opcache.preload</code>
</li>
<li>Every PHP file you want to be preloaded should be passed to <code>opcache_compile_file()</code> or be required once, from within the preload script</li>
</ul>
<p>Say you want to preload a framework, Laravel for example. Your script will have to loop over all PHP files in the <code>vendor/laravel</code> directory, and include them one by one.</p>
<p>Here's how you'd link to this script in php.ini:</p>
<pre>opcache.preload=/path/to/project/preload.php
</pre>
<p>And here's a dummy implementation:</p>
<pre><span class="hl-variable">$files</span> = <span class="hl-comment">/* An array of files you want to preload */</span>;

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$files</span> <span class="hl-keyword">as</span> <span class="hl-variable">$file</span>) {
    <span class="hl-property">opcache_compile_file</span>(<span class="hl-variable">$file</span>);
}
</pre>
<h3 id="warning:-can't-preload-unlinked-class"><a href="#warning:-can't-preload-unlinked-class" class="heading-anchor">#</a> Warning: Can't preload unlinked class</h3>
<p>Hang on though, there's a caveat! In order for files to be preloaded, their dependencies — interfaces, traits and parent classes — must also be preloaded.</p>
<p>If there are any problems with the class dependencies, you'll be notified of it on server start up:</p>
<pre>Can't preload unlinked class 
Illuminate\Database\Query\JoinClause: 
Unknown parent 
Illuminate\Database\Query\Builder
</pre>
<p>See, <code>opcache_compile_file()</code> will parse a file, but not execute it. This means that if a class has dependencies that aren't preloaded, itself can also not be preloaded.</p>
<p>This isn't a fatal problem, your server will work just fine; but you won't have all the preloaded files you actually wanted.</p>
<p>Luckily, there's a way to ensure linked files are loaded as well: instead of using <code>opcache_compile_file</code> you can use <code>require_once</code>, and let the registered autoloader (probably composer's) take care of the rest.</p>
<pre><span class="hl-variable">$files</span> = <span class="hl-comment">/* All files in eg. vendor/laravel */</span>;

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$files</span> <span class="hl-keyword">as</span> <span class="hl-variable">$file</span>) {
    <span class="hl-keyword">require_once</span>(<span class="hl-variable">$file</span>);
}
</pre>
<p>There are some caveats still. If you're trying to preload Laravel for example, there are some classes within the framework that have dependencies on other classes that don't exist yet. For example, the filesystem cache class <code>\Illuminate\Filesystem\Cache</code> has a dependency on <code>\League\Flysystem\Cached\Storage\AbstractCache</code>, which might not be installed in your project if you're never using filesystem caches.</p>
<p>You might run into "class not found" errors trying to preload everything. Luckily, in a default Laravel installation, there's only a handful of these classes, which can easily be ignored.
For convenience, I wrote a little <a target="_blank" href="https://github.com/brendt/laravel-preload/blob/master/preload.php">preloader class</a> to make ignoring files more easy, here's what it looks like:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Preloader</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$ignores</span> = [];

    <span class="hl-keyword">private</span> <span class="hl-keyword">static</span> int <span class="hl-property">$count</span> = 0;

    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$paths</span>;

    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$fileMap</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">string ...$paths</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">paths</span> = <span class="hl-variable">$paths</span>;

        <span class="hl-comment">// We'll use composer's classmap</span>
        <span class="hl-comment">// to easily find which classes to autoload,</span>
        <span class="hl-comment">// based on their filename</span>
        <span class="hl-variable">$classMap</span> = <span class="hl-keyword">require</span> <span class="hl-property">__DIR__</span> . '<span class="hl-value">/vendor/composer/autoload_classmap.php</span>';

        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">fileMap</span> = <span class="hl-property">array_flip</span>(<span class="hl-variable">$classMap</span>);
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">paths</span>(<span class="hl-injection">string ...$paths</span>): <span class="hl-type">Preloader</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">paths</span> = <span class="hl-property">array_merge</span>(
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">paths</span>,
            <span class="hl-variable">$paths</span>
        );

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">ignore</span>(<span class="hl-injection">string ...$names</span>): <span class="hl-type">Preloader</span>
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">ignores</span> = <span class="hl-property">array_merge</span>(
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">ignores</span>,
            <span class="hl-variable">$names</span>
        );

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">load</span>(): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// We'll loop over all registered paths</span>
        <span class="hl-comment">// and load them one by one</span>
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">paths</span> <span class="hl-keyword">as</span> <span class="hl-variable">$path</span>) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">loadPath</span>(<span class="hl-property">rtrim</span>(<span class="hl-variable">$path</span>, '<span class="hl-value">/</span>'));
        }

        <span class="hl-variable">$count</span> = <span class="hl-type">self</span>::<span class="hl-property">$count</span>;

        <span class="hl-keyword">echo</span> &quot;<span class="hl-value">[Preloader] Preloaded {$count} classes</span>&quot; . <span class="hl-property">PHP_EOL</span>;
    }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">loadPath</span>(<span class="hl-injection"><span class="hl-type">string</span> $path</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// If the current path is a directory,</span>
        <span class="hl-comment">// we'll load all files in it </span>
        <span class="hl-keyword">if</span> (<span class="hl-property">is_dir</span>(<span class="hl-variable">$path</span>)) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">loadDir</span>(<span class="hl-variable">$path</span>);

            <span class="hl-keyword">return</span>;
        }

        <span class="hl-comment">// Otherwise we'll just load this one file</span>
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">loadFile</span>(<span class="hl-variable">$path</span>);
    }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">loadDir</span>(<span class="hl-injection"><span class="hl-type">string</span> $path</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$handle</span> = <span class="hl-property">opendir</span>(<span class="hl-variable">$path</span>);

        <span class="hl-comment">// We'll loop over all files and directories</span>
        <span class="hl-comment">// in the current path,</span>
        <span class="hl-comment">// and load them one by one</span>
        <span class="hl-keyword">while</span> (<span class="hl-variable">$file</span> = <span class="hl-property">readdir</span>(<span class="hl-variable">$handle</span>)) {
            <span class="hl-keyword">if</span> (<span class="hl-property">in_array</span>(<span class="hl-variable">$file</span>, ['<span class="hl-value">.</span>', '<span class="hl-value">..</span>'])) {
                <span class="hl-keyword">continue</span>;
            }

            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">loadPath</span>(&quot;<span class="hl-value">{$path}/{$file}</span>&quot;);
        }

        <span class="hl-property">closedir</span>(<span class="hl-variable">$handle</span>);
    }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">loadFile</span>(<span class="hl-injection"><span class="hl-type">string</span> $path</span>): <span class="hl-type">void</span>
    {
        <span class="hl-comment">// We resolve the classname from composer's autoload mapping</span>
        <span class="hl-variable">$class</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">fileMap</span>[<span class="hl-variable">$path</span>] ?? <span class="hl-keyword">null</span>;

        <span class="hl-comment">// And use it to make sure the class shouldn't be ignored</span>
        <span class="hl-keyword">if</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">shouldIgnore</span>(<span class="hl-variable">$class</span>)) {
            <span class="hl-keyword">return</span>;
        }

        <span class="hl-comment">// Finally we require the path,</span>
        <span class="hl-comment">// causing all its dependencies to be loaded as well</span>
        <span class="hl-keyword">require_once</span>(<span class="hl-variable">$path</span>);

        <span class="hl-type">self</span>::<span class="hl-property">$count</span>++;

        <span class="hl-keyword">echo</span> &quot;<span class="hl-value">[Preloader] Preloaded `{$class}`</span>&quot; . <span class="hl-property">PHP_EOL</span>;
    }

    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">shouldIgnore</span>(<span class="hl-injection"><span class="hl-type">?string</span> $name</span>): <span class="hl-type">bool</span>
    {
        <span class="hl-keyword">if</span> (<span class="hl-variable">$name</span> === <span class="hl-keyword">null</span>) {
            <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>;
        }

        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$this</span>-&gt;<span class="hl-property">ignores</span> <span class="hl-keyword">as</span> <span class="hl-variable">$ignore</span>) {
            <span class="hl-keyword">if</span> (<span class="hl-property">strpos</span>(<span class="hl-variable">$name</span>, <span class="hl-variable">$ignore</span>) === 0) {
                <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>;
            }
        }

        <span class="hl-keyword">return</span> <span class="hl-keyword">false</span>;
    }
}
</pre>
<p>By adding this class in the same preload script, we're now able to load the whole Laravel framework like so:</p>
<pre><span class="hl-comment">// …</span>

(<span class="hl-keyword">new</span> <span class="hl-type">Preloader</span>())
    -&gt;<span class="hl-property">paths</span>(<span class="hl-property">__DIR__</span> . '<span class="hl-value">/vendor/laravel</span>')
    -&gt;<span class="hl-property">ignore</span>(
        <span class="hl-type">\Illuminate\Filesystem\Cache</span>::<span class="hl-keyword">class</span>,
        <span class="hl-type">\Illuminate\Log\LogManager</span>::<span class="hl-keyword">class</span>,
        <span class="hl-type">\Illuminate\Http\Testing\File</span>::<span class="hl-keyword">class</span>,
        <span class="hl-type">\Illuminate\Http\UploadedFile</span>::<span class="hl-keyword">class</span>,
        <span class="hl-type">\Illuminate\Support\Carbon</span>::<span class="hl-keyword">class</span>,
    )
    -&gt;<span class="hl-property">load</span>();
</pre>
<h2 id="does-it-work?"><a href="#does-it-work?" class="heading-anchor">#</a> Does it work?</h2>
<p>That's of course the most important question: were all files correctly loaded? You can simply test it by restarting the server, and dump the output of <code>opcache_get_status()</code> in a PHP script. You'll see it has a key called <code>preload_statistics</code>, which will list all preloaded functions, classes and scripts; as well as the memory consumed by the preloaded files.</p>
<h2 id="composer-support"><a href="#composer-support" class="heading-anchor">#</a> Composer support</h2>
<p>One promising feature is probably an automated preloading solution based on composer, which is used by most modern day PHP projects already.
People are working to add a preload configuration option in <code>composer.json</code>, which in turn will generate the preload file for you! At the moment, this feature is still a work in progress, but you can follow it <a target="_blank" href="https://github.com/composer/composer/issues/7777">here</a>.</p>
<p><strong>Update 2019-11-29</strong>: composer support has stopped, as can be read by <a target="_blank" href="https://github.com/composer/composer/issues/7777#issuecomment-559725760">Jordi's</a> answer.</p>
<h2 id="server-requirements"><a href="#server-requirements" class="heading-anchor">#</a> Server requirements</h2>
<p>There's two more important things to mention about the devops side when using preloading.</p>
<p>You already know that you need to specify an entry in php.ini in order for preloading to work. This means that if you're using shared hosting, you won't be able to freely configure PHP however you want.
In practice, you'll need a dedicated (virtual) server to be able to optimise the preloaded files for a single project. So keep that in mind.</p>
<p>Also remember you'll need to restart the server (<code>php-fpm</code> is sufficient if you're using it) every time you want to reload the in-memory files. This might seem obvious for most, but still worth the mention.</p>
<h2 id="performance"><a href="#performance" class="heading-anchor">#</a> Performance</h2>
<p>Now to the most important question: does preloading actually improve performance?</p>
<p>The answer is yes, of course: Ben Morel shared some benchmarks, which can be found in the same <a target="_blank" href="https://github.com/composer/composer/issues/7777#issuecomment-440268416">composer issue</a> linked to earlier.
I also did my own benchmarks within a real-life Laravel project. You can read about them <a href="/blog/php-preload-benchmarks">here</a>.</p>
<p>Interestingly enough, you could decide to only preload "hot classes" — classes that are used often in your codebase. Ben's benchmarks shows that only loading around 100 hot classes, actually yields better performance gains than preloading everything. It's a difference of a 13% and 17% performance increase.</p>
<p>Which classes should be preloaded relies of course on your specific project. It would be wise to simply preload as much as possible at the start. If you really need the few percentage increases, you would have to monitor your code while running.</p>
<p>All of this can of course also be automated, and will probably be done in the future.</p>
<p>For now, most important to remember is that composer will add support, so that you don't have to make preload files yourself, and that this feature is very easy to setup on your server, given that you've got full control over it.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<p>Will you be using preloading once PHP 7.4 arrives? Any remarks or thoughts after reading this post? Let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2019-07-05T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Arrow functions in PHP 7.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/short-closures-in-php"/>

                <id>https://www.stitcher.io/blog/short-closures-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Short closures, also called arrow functions, are a way of writing shorter functions in PHP.
This notation is useful when passing closures to functions like <code>array_map</code> or <code>array_filter</code>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>This is what they look like:</p>
<pre><span class="hl-comment">// A collection of Post objects</span>
<span class="hl-variable">$posts</span> = [<span class="hl-comment">/* … */</span>];

<span class="hl-variable">$ids</span> = <span class="hl-property">array_map</span>(<span class="hl-keyword">fn</span>(<span class="hl-injection">$post</span>) =&gt; <span class="hl-variable">$post</span>-&gt;<span class="hl-property">id</span>, <span class="hl-variable">$posts</span>);
</pre>
<p>Previously, you'd had to write this:</p>
<pre><span class="hl-variable">$ids</span> = <span class="hl-property">array_map</span>(<span class="hl-keyword">function</span> (<span class="hl-injection">$post</span>) {
    <span class="hl-keyword">return</span> <span class="hl-variable">$post</span>-&gt;<span class="hl-property">id</span>;
}, <span class="hl-variable">$posts</span>);
</pre>
<p>Let's summarize how short closures can be used.</p>
<ul>
<li>They are available as of PHP 7.4</li>
<li>They start with the <code>fn</code> keyword</li>
<li>They can only have <em>one</em> expression, which is the return statement</li>
<li>No <code>return</code> keyword allowed</li>
<li>Arguments and return types can be type hinted</li>
</ul>
<p>A more strictly typed way of writing the example above could be this:</p>
<pre><span class="hl-variable">$ids</span> = <span class="hl-property">array_map</span>(<span class="hl-keyword">fn</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>): <span class="hl-type">int</span> =&gt; <span class="hl-variable">$post</span>-&gt;<span class="hl-property">id</span>, <span class="hl-variable">$posts</span>);
</pre>
<p>Two more things to mention:</p>
<ul>
<li>The spread operator is also allowed</li>
<li>References are allowed, both for the arguments as the return values</li>
</ul>
<p>If you want to return a value by reference, the following syntax should be used:</p>
<pre><span class="hl-keyword">fn</span>&amp;(<span class="hl-variable">$x</span>) =&gt; <span class="hl-variable">$x</span>
</pre>
<p>In short, short closures allow the same functionality you'd expect from normal closures,
with the exception of only allowing one expression.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="no-multi-line"><a href="#no-multi-line" class="heading-anchor">#</a> No multi-line</h2>
<p>You read it right: short closures can only have <em>one</em> expression; that one expression may be spread over multiple lines for formatting, but it must always be one expression.</p>
<p>The reasoning is as follows: the goal of short closures is to reduce verbosity.
<code>fn</code> is of course shorter than <code>function</code> in all cases.
Nikita Popov, the creator of the RFC, however argued that if you're dealing with multi-line functions,
there is less to be gained by using short closures.</p>
<p>After all, multi-line closures are by definition already more verbose;
so being able to skip two keywords (<code>function</code> and <code>return</code>) wouldn't make much of a difference.</p>
<p>Whether you agree with this sentiment is up to you.
While I can think of many one-line closures in my projects,
there are also plenty of multi-line ones, and I'll personally miss the short syntax in those cases.</p>
<p>There's hope though: it is possible to add multi-line short closures in the future,
but that's an RFC on its own.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="values-from-outer-scope"><a href="#values-from-outer-scope" class="heading-anchor">#</a> Values from outer scope</h2>
<p>Another significant difference between short and normal closures is that the short ones don't
require the <code>use</code> keyword to be able to access data from the outer scope.</p>
<pre><span class="hl-variable">$modifier</span> = 5;

<span class="hl-property">array_map</span>(<span class="hl-keyword">fn</span>(<span class="hl-injection">$x</span>) =&gt; <span class="hl-variable">$x</span> * <span class="hl-variable">$modifier</span>, <span class="hl-variable">$numbers</span>);
</pre>
<p>It's important to note that you're not allowed to modify variables from the outer scope.
Values are bound by value and not by reference.
This means that you <em>could</em> change <code>$modifier</code> within the short closure,
though it wouldn't have effect on the <code>$modifier</code> variable in the outer scope.</p>
<p>One exception is of course the <code>$this</code> keyword, which acts exactly the same as normal closures:</p>
<pre><span class="hl-property">array_map</span>(<span class="hl-keyword">fn</span>(<span class="hl-injection">$x</span>) =&gt; <span class="hl-variable">$x</span> * <span class="hl-variable">$this</span>-&gt;<span class="hl-property">modifier</span>, <span class="hl-variable">$numbers</span>);
</pre>
<h2 id="future-possibilities"><a href="#future-possibilities" class="heading-anchor">#</a> Future possibilities</h2>
<p>I already mentioned multi-line short closures, which is still a future possibility.
Another idea floating around is allowing the short closure syntax in classes, for example for getters and setters:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span> {
    <span class="hl-keyword">private</span> <span class="hl-property">$title</span>;
 
    <span class="hl-keyword">fn</span> <span class="hl-property">getTitle</span>() =&gt; <span class="hl-variable">$this</span>-&gt;<span class="hl-property">title</span>;
}
</pre>
<p>All in all, short closures are a welcome feature, though there is still room for improvement.
The biggest one probably being multi-line short closures.</p>
<p>Do you have any thoughts you'd like to share?
Feel free to send a <a target="_blank" href="https://twitter.com/brendt_gd">tweet</a> or an <a href="mailto:brendt@stitcher.io">email</a> my way!</p>
 ]]></summary>

                <updated>2019-05-02T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Typed properties in PHP 7.4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/typed-properties-in-php-74"/>

                <id>https://www.stitcher.io/blog/typed-properties-in-php-74</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Typed class properties have been added in PHP 7.4 and provide a major improvement to PHP's type system.
These changes are fully opt-in and non breaking to previous versions.</p>
<p>In this post we'll look at the feature in-depth, but first let's start by summarising the most important points:</p>
<ul>
<li>They are available as of PHP 7.4, which is scheduled to be released in November of 2019</li>
<li>They are only available in classes and require an access modifier: <code>public</code>, <code>protected</code> or <code>private</code>; or <code>var</code>
</li>
<li>All types are allowed, except <code>void</code> and <code>callable</code>
</li>
</ul>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>This is what they look like in action:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$a</span>;

    <span class="hl-keyword">public</span> <span class="hl-type">?string</span> <span class="hl-property">$b</span> = '<span class="hl-value">foo</span>';

    <span class="hl-keyword">private</span> <span class="hl-type">Foo</span> <span class="hl-property">$prop</span>;

    <span class="hl-keyword">protected</span> <span class="hl-keyword">static</span> string <span class="hl-property">$static</span> = '<span class="hl-value">default</span>';
}
</pre>
<p>If you're unsure about the added benefit of types, I'd recommend you reading <a href="/blog/tests-and-types">this post</a> first.</p>
<h2 id="uninitialized"><a href="#uninitialized" class="heading-anchor">#</a> Uninitialized</h2>
<p>Before looking at the fun stuff, there's an important aspect about typed properties that's essential to talk about first.</p>
<p>Despite what you might think on first sight, the following code is valid:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$bar</span>;
}

<span class="hl-variable">$foo</span> = <span class="hl-keyword">new</span> <span class="hl-type">Foo</span>;
</pre>
<p>Even though the value of <code>$bar</code> isn't an integer after making an object of <code>Foo</code>, PHP will only throw an error when <code>$bar</code> is accessed:</p>
<pre><span class="hl-property">var_dump</span>(<span class="hl-variable">$foo</span>-&gt;<span class="hl-property">bar</span>);

<span class="hl-type">Fatal</span> <span class="hl-property">error</span>: Uncaught <span class="hl-property">Error</span>: Typed property <span class="hl-type">Foo</span>::<span class="hl-property">$bar</span> 
must not be accessed before initialization
</pre>
<p>As you can read from the error message,
there's a new kind of "variable state": uninitialized.</p>
<p>If <code>$bar</code> didn't have a type, its value would simply be <code>null</code>.
Types can be nullable though, so it's not possible to determine whether a typed nullable property was set, or simply forgotten.
That's why "uninitialized" was added.</p>
<p>There are four important things to remember about uninitialized:</p>
<ul>
<li>You cannot read from uninitialized properties, doing so will result in a fatal error.</li>
<li>Because uninitialized state is checked when accessing a property, you're able to create an object with an uninitialized property, even though its type is non-nullable.</li>
<li>You can write to an uninitialized property before reading from it.</li>
<li>Using <code>unset</code> on a typed property will make it uninitialized, while unsetting an untyped property will make it <code>null</code>.</li>
</ul>
<p>Especially note that the following code, where an uninitialised, non-nullable property is set after constructing the object, is valid</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$a</span>;
}

<span class="hl-variable">$foo</span> = <span class="hl-keyword">new</span> <span class="hl-type">Foo</span>;

<span class="hl-variable">$foo</span>-&gt;<span class="hl-property">a</span> = 1;
</pre>
<p>While uninitialized state is only checked when reading the value of a property, type validation is done when writing to it.
This means that you can be sure that no invalid type will ever end up as a property's value.</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="defaults-and-constructors"><a href="#defaults-and-constructors" class="heading-anchor">#</a> Defaults and constructors</h2>
<p>Let's take a closer look at how typed values can be initialized.
In case of scalar types, it's possible to provide a default value:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$bar</span> = 4;
    
    <span class="hl-keyword">public</span> <span class="hl-type">?string</span> <span class="hl-property">$baz</span> = <span class="hl-keyword">null</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-type">array</span> <span class="hl-property">$list</span> = [1, 2, 3];
}
</pre>
<p>Note that you can only use <code>null</code> as a default if the type is actually nullable.
This might seem obvious, but there's some legacy behaviour with parameter defaults where the following is allowed:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">passNull</span>(<span class="hl-injection"><span class="hl-type">int</span> $i = <span class="hl-keyword">null</span></span>)
{ <span class="hl-comment">/* … */</span> }

<span class="hl-property">passNull</span>(<span class="hl-keyword">null</span>);
</pre>
<p>Luckily this confusing behaviour is not allowed with typed properties.</p>
<p>Also note that it's impossible to have default values with <code>object</code> or class types.
You should use the constructor to set their defaults.</p>
<p>The obvious place to initialize typed values would of course be the constructor:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">int</span> <span class="hl-property">$a</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">int</span> $a</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">a</span> = <span class="hl-variable">$a</span>;
    }
}
</pre>
<p>But also remember what I mentioned before: it's valid to write to an uninitialized property, outside of the constructor. As long as there are nothing is reading from a property, the uninitialized check is not performed.</p>
<h2 id="types-of-types"><a href="#types-of-types" class="heading-anchor">#</a> Types of types</h2>
<p>So what exactly can be typed and how? I already mentioned that typed properties will only work in classes (for now),
and that they need an access modifier or the <code>var</code> key word in front of them.</p>
<p>As of available types, almost all types can be used, except <code>void</code> and <code>callable</code>.</p>
<p>Because <code>void</code> means the absence of a value, it makes sense that it cannot be used to type a value.
<code>callable</code> however is a little more nuanced.</p>
<p>See, a "callable" in PHP can be written like so:</p>
<pre><span class="hl-variable">$callable</span> = [<span class="hl-variable">$this</span>, '<span class="hl-value">method</span>'];
</pre>
<p>Say you'd have the following (broken) code:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">callable</span> <span class="hl-property">$callable</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">callable</span> $callable</span>)
    { <span class="hl-comment">/* … */</span> }
}

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">Foo</span> <span class="hl-property">$foo</span>;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">foo</span> = <span class="hl-keyword">new</span> <span class="hl-type">Foo</span>([<span class="hl-variable">$this</span>, '<span class="hl-value">method</span>'])
    }
    
    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">method</span>()
    { <span class="hl-comment">/* … */</span> }
}

<span class="hl-variable">$bar</span> = <span class="hl-keyword">new</span> <span class="hl-type">Bar</span>;

(<span class="hl-variable">$bar</span>-&gt;<span class="hl-property">foo</span>-&gt;<span class="hl-property">callable</span>)();
</pre>
<p>In this example, <code>$callable</code> refers to the private <code>Bar::method</code>, but is called within the context of <code>Foo</code>.
Because of this problem, it was decided not to add <code>callable</code> support.</p>
<p>It's no big deal though, because <code>Closure</code> is a valid type, which will remember the <code>$this</code> context where it was constructed.</p>
<p>With that out of the way, here's a list of all available types:</p>
<ul>
<li>bool</li>
<li>int</li>
<li>float</li>
<li>string</li>
<li>array</li>
<li>iterable</li>
<li>object</li>
<li>? (nullable)</li>
<li>self & parent</li>
<li>Classes & interfaces</li>
</ul>
<h2 id="coercion-and-strict-types"><a href="#coercion-and-strict-types" class="heading-anchor">#</a> Coercion and strict types</h2>
<p>PHP, being the dynamic language we love and hate, will try to coerce or convert types whenever possible.
Say you pass a string where you expect an integer, PHP will try and convert that string automatically:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">coerce</span>(<span class="hl-injection"><span class="hl-type">int</span> $i</span>)
{ <span class="hl-comment">/* … */</span> }

<span class="hl-property">coerce</span>('<span class="hl-value">1</span>'); <span class="hl-comment">// 1</span>
</pre>
<p>The same principles apply to typed properties. The following code is valid and will convert <code>'1'</code> to <code>1</code>.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Bar</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$i</span>;
}

<span class="hl-variable">$bar</span> = <span class="hl-keyword">new</span> <span class="hl-type">Bar</span>;

<span class="hl-variable">$bar</span>-&gt;<span class="hl-property">i</span> = '<span class="hl-value">1</span>'; <span class="hl-comment">// 1</span>
</pre>
<p>If you don't like this behaviour you can disabled it by declaring strict types:</p>
<pre><span class="hl-keyword">declare</span>(strict_types=1);

<span class="hl-variable">$bar</span> = <span class="hl-keyword">new</span> <span class="hl-type">Bar</span>;

<span class="hl-variable">$bar</span>-&gt;<span class="hl-property">i</span> = '<span class="hl-value">1</span>'; <span class="hl-comment">// 1</span>

<span class="hl-type">Fatal</span> <span class="hl-property">error</span>: Uncaught <span class="hl-property">TypeError</span>: 
<span class="hl-type">Typed</span> property <span class="hl-type">Bar</span>::<span class="hl-property">$i</span> must be int, string used
</pre>
<h2 id="type-variance-and-inheritance"><a href="#type-variance-and-inheritance" class="heading-anchor">#</a> Type variance and inheritance</h2>
<p>Even though PHP 7.4 introduced <a href="/blog/new-in-php-74#improved-type-variance-rfc">improved type variance</a>, typed properties are still invariant. This means that the following is not valid:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">A</span> {}
<span class="hl-keyword">class</span> <span class="hl-type">B</span> <span class="hl-keyword">extends</span> <span class="hl-type">A</span> {}

<span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">A</span> <span class="hl-property">$prop</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">B</span> <span class="hl-property">$prop</span>;
}

<span class="hl-type">Fatal</span> <span class="hl-property">error</span>: Type of <span class="hl-type">Bar</span>::<span class="hl-property">$prop</span> must be <span class="hl-property">A</span> (<span class="hl-keyword">as</span> in <span class="hl-keyword">class</span> <span class="hl-type">Foo</span>)
</pre>
<p>If the above example doesn't seem significant, you should take a look at the following:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">self</span> <span class="hl-property">$prop</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">self</span> <span class="hl-property">$prop</span>;
}
</pre>
<p>PHP will replace <code>self</code> behind the scenes with the concrete class it refers to, before running the code.
This means that the same error will be thrown in this example.
The only way to handle it, is by doing the following:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">Foo</span> <span class="hl-property">$prop</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">Foo</span> <span class="hl-property">$prop</span>;
}
</pre>
<p>Speaking of inheritance, you might find it hard to come up with any good use cases to overwrite the types of inherited properties.</p>
<p>While I agree with that sentiment, it's worth noting that it is possible to change the type of an inherited property, but only if the access modifier also changes from <code>private</code> to <code>protected</code> or <code>public</code>.</p>
<p>The following code is valid:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">private</span> <span class="hl-type">int</span> <span class="hl-property">$prop</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$prop</span>;
}
</pre>
<p>However, changing a type from nullable to non-nullable or reverse, is not allowed.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$a</span>;
    <span class="hl-keyword">public</span> <span class="hl-type">?int</span> <span class="hl-property">$b</span>;
}

<span class="hl-keyword">class</span> <span class="hl-type">Bar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Foo</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">?int</span> <span class="hl-property">$a</span>;
    <span class="hl-keyword">public</span> <span class="hl-type">int</span> <span class="hl-property">$b</span>;
}

<span class="hl-type">Fatal</span> <span class="hl-property">error</span>: Type of <span class="hl-type">Bar</span>::<span class="hl-property">$a</span> must be int (<span class="hl-keyword">as</span> in <span class="hl-keyword">class</span> <span class="hl-type">Foo</span>)
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="there's-more!"><a href="#there's-more!" class="heading-anchor">#</a> There's more!</h2>
<p>Like I said at the start of this post, typed properties are a <em>major</em> addition to PHP.
There's lots more to say about them. I'd suggest you reading through the <a target="_blank" href="https://wiki.php.net/rfc/typed_properties_v2">RFC</a> to know all the neat little details.</p>
<p>If you're new to PHP 7.4, you probably want to read the <a href="/blog/new-in-php-74">full list</a> of changes made and features added. To be honest, it's one of the best releases in a long time, and worth your time!</p>
<p>Finally, if you have any thoughts you want to share on the topic, I'd love to hear from you!
You can reach me via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
<p>Until next time!</p>
 ]]></summary>

                <updated>2019-06-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Relationship issues ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/laravel-custom-relation-classes"/>

                <id>https://www.stitcher.io/blog/laravel-custom-relation-classes</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <blockquote>
<p>Or in other words, dealing with complex database relations and Laravel models.</p>
</blockquote>
<p>Recently I had to deal with a complex performance issue in one of our larger Laravel projects. Let me quickly set the scene.</p>
<p>We want an admin user to see an overview of all people in the system in a table, and we want a column in that table to list which contracts are active at that moment for each person.</p>
<p>The relation between <code>Contract</code> and <code>Person</code> is as follows:</p>
<pre>Contract &gt; HabitantContract &gt; Habitant &gt; Person
</pre>
<p>I don't want to spend too much time going into details as to how we came to this relationship hierarchy. It's important for you to know that, yes, this hierarchy is important for our use cases: a <code>Contract</code> can have several <code>Habitants</code>, which are linked via a pivot model <code>HabitantContract</code>; and each <code>Habitant</code> has a relation to one <code>Person</code>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Since we're showing an overview of all people, we'd like to do something like this in our controller:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PeopleController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>() 
    {
        <span class="hl-variable">$people</span> = <span class="hl-type">PersonResource</span>::<span class="hl-property">collection</span>(<span class="hl-type">Person</span>::<span class="hl-property">paginate</span>());

        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">people.index</span>', <span class="hl-property">compact</span>('<span class="hl-value">people</span>'));
    }
}
</pre>
<p>Let's make clear that this is an oversimplified example, though I hope you get the gist. Ideally, we'd want our resource class to look something like this:</p>
<pre><span class="hl-comment">/** <span class="hl-value">@mixin</span> \App\Domain\People\Models\Person */</span>
<span class="hl-keyword">class</span> <span class="hl-type">PersonResource</span> <span class="hl-keyword">extends</span> <span class="hl-type">JsonResource</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">toArray</span>(<span class="hl-injection">$request</span>): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> [
            '<span class="hl-value">name</span>' =&gt; <span class="hl-variable">$this</span>-&gt;<span class="hl-property">name</span>,

            '<span class="hl-value">active_contracts</span>' =&gt; <span class="hl-variable">$this</span>-&gt;<span class="hl-property">activeContracts</span>
                -&gt;<span class="hl-property">map</span>(<span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">Contract</span> $contract</span>) {
                    <span class="hl-keyword">return</span> <span class="hl-variable">$contract</span>-&gt;<span class="hl-property">contract_number</span>;
                })
                -&gt;<span class="hl-property">implode</span>('<span class="hl-value">, </span>'),

            <span class="hl-comment">// …</span>
        ];
    }
}
</pre>
<p>Notice especially the <code>Person::activeContracts</code> relation. How could we make this work?</p>
<p>A first thought might be by using a <code>HasManyThrough</code> relation, but remember that we're 4 levels deep in our relation hierarchy. Besides that, I find <code>HasManyThrough</code> to be <a href="/blog/laravel-has-many-through">very confusing</a>.</p>
<p>We could query the contracts on the fly, one-by-one per person. The issue with that is that we're introducing an n+1 issue since there'll be an extra query <em>per</em> person. Imagine the performance impact if you're dealing with more than just a few models.</p>
<p>One last solution that came to mind was to load all people, all contracts, and map them together manually. In the end that's exactly what I ended up doing, though I did it in the cleanest possible way: using custom relations.</p>
<p>Let's dive in.</p>
<h2 id="configuring-the-person-model"><a href="#configuring-the-person-model" class="heading-anchor">#</a> Configuring the Person model</h2>
<p>Since we want our <code>$person-&gt;activeContracts</code> to work exactly like any other relation, there's little work to be done here: let's add a relation method to our model, just like any other.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Person</span> <span class="hl-keyword">extends</span> <span class="hl-type">Model</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">activeContracts</span>(): <span class="hl-type">ActiveContractsRelation</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">ActiveContractsRelation</span>(<span class="hl-variable">$this</span>);
    }
}
</pre>
<p>There's nothing more to do here. Of course we're only starting, since we haven't actually implemented <code>ActiveContractsRelation</code>!</p>
<h2 id="the-custom-relation-class"><a href="#the-custom-relation-class" class="heading-anchor">#</a> The custom relation class</h2>
<p>Unfortunately there's no documentation on making your own relation classes. Luckily you don't need much to learn about them: some code-diving skills and a little bit of time gets you pretty far. Oh an IDE also helps.</p>
<p>Looking at the existing relation classes provided by Laravel, we learn that there's one base relation that rules them all: <code>Illuminate\Database\Eloquent\Relations\Relation</code>. Extending it means you need to implement some abstract methods.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">/**
     * Set the base constraints on the relation query.
     *
     * <span class="hl-value">@return</span> <span class="hl-type">void</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addConstraints</span>() { <span class="hl-comment">/* … */</span> }

    <span class="hl-comment">/**
     * Set the constraints for an eager load of the relation.
     *
     * <span class="hl-value">@param</span> <span class="hl-type">array</span> <span class="hl-variable">$models</span>
     *
     * <span class="hl-value">@return</span> <span class="hl-type">void</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addEagerConstraints</span>(<span class="hl-injection"><span class="hl-type">array</span> $models</span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-comment">/**
     * Initialize the relation on a set of models.
     *
     * <span class="hl-value">@param</span> <span class="hl-type">array</span> <span class="hl-variable">$models</span>
     * <span class="hl-value">@param</span> <span class="hl-type">string</span> <span class="hl-variable">$relation</span>
     *
     * <span class="hl-value">@return</span> <span class="hl-type">array</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">initRelation</span>(<span class="hl-injection"><span class="hl-type">array</span> $models, $relation</span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-comment">/**
     * Match the eagerly loaded results to their parents.
     *
     * <span class="hl-value">@param</span> <span class="hl-type">array</span> <span class="hl-variable">$models</span>
     * <span class="hl-value">@param</span> <span class="hl-type">\Illuminate\Database\Eloquent\Collection</span> <span class="hl-variable">$results</span>
     * <span class="hl-value">@param</span> <span class="hl-type">string</span> <span class="hl-variable">$relation</span>
     *
     * <span class="hl-value">@return</span> <span class="hl-type">array</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-keyword">match</span>(<span class="hl-injection"><span class="hl-type">array</span> $models, <span class="hl-type">Collection</span> $results, $relation</span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-comment">/**
     * Get the results of the relationship.
     *
     * <span class="hl-value">@return</span> <span class="hl-type">mixed</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getResults</span>() { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>The doc blocks get us on the way, though it's not always entirely clear what needs to happen. Again we're in luck, Laravel still has some existing relation classes where we can look to.</p>
<p>Let's go through building our custom relation class step by step. We'll start by overriding the constructor and adding some type hints to the existing properties. Just to make sure, the type system will prevent us from making stupid mistakes.</p>
<p>The abstract <code>Relation</code> constructor requires both specifically for  an eloquent <code>Builder</code> class, as well as the parent model the relationship belongs to. The <code>Builder</code> is meant to be the base query object for our related model, <code>Contract</code>, in our case.</p>
<p>Since we're building a relation class specifically for our use case, there's no need to make the builder configurable. Here's what the constructor looks like:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\App\Domain\Contract\Models\Contract|Illuminate\Database\Eloquent\Builder </span>*/</span>
    <span class="hl-keyword">protected</span> <span class="hl-property">$query</span>;

    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\App\Domain\People\Models\Person </span>*/</span>
    <span class="hl-keyword">protected</span> <span class="hl-property">$parent</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">Person</span> $parent</span>)
    {
        <span class="hl-keyword">parent</span>::<span class="hl-property">__construct</span>(<span class="hl-type">Contract</span>::<span class="hl-property">query</span>(), <span class="hl-variable">$parent</span>);
    }

    <span class="hl-comment">// …</span>
}
</pre>
<p>Note that we type hint <code>$query</code> both with the <code>Contract</code> model as well as the <code>Builder</code> class. This allows IDEs to provide better autocompletion, such as custom scopes defined on the model class.</p>
<p>We've got our relation constructed: it will query <code>Contract</code> models, and use a <code>Person</code> model as its parent. Moving on to building our query.</p>
<p>This is where the <code>addConstraints</code> method come in. It will be used to configure the base query. It will set up our relation query specifically to our needs. This is the place where most business rules will be contained:</p>
<ul>
<li>We only want active contracts to show up</li>
<li>We only want to load active contracts that belong to a specified person (the <code>$parent</code> of our relation)</li>
<li>We might want to eagerly load some other relations, but more on that later.</li>
</ul>
<p>Here's what <code>addConstraints</code> looks like, for now:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addConstraints</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">query</span>
            -&gt;<span class="hl-property">whereActive</span>() <span class="hl-comment">// A query scope on our `Contract` model</span>
            -&gt;<span class="hl-property">join</span>(
                '<span class="hl-value">contract_habitants</span>', 
                '<span class="hl-value">contract_habitants.contract_id</span>', 
                '<span class="hl-value">=</span>', 
                '<span class="hl-value">contracts.id</span>'
            )
            -&gt;<span class="hl-property">join</span>(
                '<span class="hl-value">habitants</span>', 
                '<span class="hl-value">habitants.id</span>', 
                '<span class="hl-value">=</span>', 
                '<span class="hl-value">contract_habitants.habitant_id</span>'
            );
    }
}
</pre>
<p>Now I do assume that you know how basic joins work. Though I will summarize what's happening here: we're building a query that will load all <code>contracts</code> and their <code>habitants</code>, via the <code>contract_habitants</code> pivot table, hence the two joins.</p>
<p>One other constraint is that we only want active contracts to show up; for this we can simply use an existing query scope provided by the <code>Contract</code> model.</p>
<p>With our base query in place, it's time to add the real magic: supporting eager loads. This is where the performance wins are: instead of doing one query per person to load its contracts, we're doing one query to load all contracts, and link these contracts to the correct people afterwards.</p>
<p>This is what <code>addEagerConstraints</code>, <code>initRelation</code> and <code>match</code> are used for. Let's look at them one by one.</p>
<p>First the <code>addEagerConstraints</code> method. This one allows us to modify the query to load in all contracts related to a set of people. Remember we only want two queries, and link the results together afterwards.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addEagerConstraints</span>(<span class="hl-injection"><span class="hl-type">array</span> $people</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">query</span>-&gt;<span class="hl-property">whereIn</span>(
            '<span class="hl-value">habitants.contact_id</span>', 
            <span class="hl-property">collect</span>(<span class="hl-variable">$people</span>)-&gt;<span class="hl-property">pluck</span>('<span class="hl-value">id</span>')
        );
    }
}
</pre>
<p>Since we joined the <code>habitants</code> table before, this method is fairly easy: we'll only load contracts that belong to the set of people provided.</p>
<p>Next the <code>initRelation</code>. Again this one is rather easy: its goal is to initialise the empty <code>activeContract</code> relationship on every <code>Person</code> model, so that it can be filled afterwards.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">initRelation</span>(<span class="hl-injection"><span class="hl-type">array</span> $people, $relation</span>)
    {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$people</span> <span class="hl-keyword">as</span> <span class="hl-variable">$person</span>) {
            <span class="hl-variable">$person</span>-&gt;<span class="hl-property">setRelation</span>(
                <span class="hl-variable">$relation</span>, 
                <span class="hl-variable">$this</span>-&gt;<span class="hl-property">related</span>-&gt;<span class="hl-property">newCollection</span>()
            );
        }

        <span class="hl-keyword">return</span> <span class="hl-variable">$people</span>;
    }
}
</pre>
<p>Note that the <code>$this-&gt;related</code> property is set by the parent <code>Relation</code> class and it's a clean model instance of our base query so in other words, an empty <code>Contract</code> model:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Relation</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">Builder</span> $query, <span class="hl-type">Model</span> $parent</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">related</span> = <span class="hl-variable">$query</span>-&gt;<span class="hl-property">getModel</span>();
    
        <span class="hl-comment">// …</span>
    }
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>Finally we arrive at the core function that will solve our problem: linking all people and contracts together.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-keyword">match</span>(<span class="hl-injection"><span class="hl-type">array</span> $people, <span class="hl-type">Collection</span> $contracts, $relation</span>)
    {
        <span class="hl-keyword">if</span> (<span class="hl-variable">$contracts</span>-&gt;<span class="hl-property">isEmpty</span>()) {
            <span class="hl-keyword">return</span> <span class="hl-variable">$people</span>;
        }

        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$people</span> <span class="hl-keyword">as</span> <span class="hl-variable">$person</span>) {
            <span class="hl-variable">$person</span>-&gt;<span class="hl-property">setRelation</span>(
                <span class="hl-variable">$relation</span>, 
                <span class="hl-variable">$contracts</span>-&gt;<span class="hl-property">filter</span>(<span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">Contract</span> $contract) use ($person</span>) {
                    <span class="hl-keyword">return</span> <span class="hl-variable">$contract</span>-&gt;<span class="hl-property">habitants</span>-&gt;<span class="hl-property">pluck</span>('<span class="hl-value">person_id</span>')-&gt;<span class="hl-property">contains</span>(<span class="hl-variable">$person</span>-&gt;<span class="hl-property">id</span>);
                })
            );    
        }

        <span class="hl-keyword">return</span> <span class="hl-variable">$people</span>;
    }
}
</pre>
<p>Let's walk through what's happening here: on the one hand we've got an array of parent models, the people; on the other hand we've got a collection of contracts, the result of the query executed by our relation class. The goal of the <code>match</code> function is to link them together.</p>
<p>How to do this? It's not that difficult: loop over all people, and search all contracts that belong to each one of them, based on the habitants linked to that contract.</p>
<p>Almost done? Well… there's one more issue. Since we're using the <code>$contract-&gt;habitants</code> relation, we need to make sure it is also eagerly loaded, otherwise we just moved the n+1 issue instead of solving it. So it's back to the <code>addEagerConstraints</code> method for a moment.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">addEagerConstraints</span>(<span class="hl-injection"><span class="hl-type">array</span> $people</span>)
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">query</span>
            -&gt;<span class="hl-property">whereIn</span>(
                '<span class="hl-value">habitants.contact_id</span>', 
                <span class="hl-property">collect</span>(<span class="hl-variable">$people</span>)-&gt;<span class="hl-property">pluck</span>('<span class="hl-value">id</span>')
            )
            -&gt;<span class="hl-property">with</span>('<span class="hl-value">habitants</span>')
            -&gt;<span class="hl-property">select</span>('<span class="hl-value">contracts.*</span>');
    }
}
</pre>
<p>We're adding the <code>with</code> call to eagerly load all habitants, but also note the specific <code>select</code> statement. We need to tell Laravel's query builder to only select the data from the <code>contracts</code> table, because otherwise the related habitant data will be merged on the <code>Contract</code> model, causing it to have the wrong ids and what not.</p>
<p>Finally we need to implement the <code>getResults</code> method, which simply executes the query:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ActiveContractsRelation</span> <span class="hl-keyword">extends</span> <span class="hl-type">Relation</span>
{
    <span class="hl-comment">// …</span>

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getResults</span>()
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">query</span>-&gt;<span class="hl-property">get</span>();
    }
}
</pre>
<hr />
<p>And that's it! Our custom relation can now be used like any other Laravel relation. It's an elegant solution to solving a complex problem the Laravel way.</p>
 ]]></summary>

                <updated>2019-11-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Laravel&#039;s HasManyThrough cheatsheet ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/laravel-has-many-through"/>

                <id>https://www.stitcher.io/blog/laravel-has-many-through</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <pre>- The current model Country has a relation to Post via User
- The intermediate model is linked to the current model via users.country_id
- The target model is linked to the intermediate model via posts.user_id
- users.country_id maps to countries.id
- posts.user_id maps to users.id
</pre>
<pre>countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string
</pre>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Country</span> <span class="hl-keyword">extends</span> <span class="hl-type">Model</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">posts</span>()
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">hasManyThrough</span>(
            '<span class="hl-value">App\Post</span>',
            '<span class="hl-value">App\User</span>',
            '<span class="hl-value">country_id</span>', <span class="hl-comment">// Foreign key on users table...</span>
            '<span class="hl-value">user_id</span>', <span class="hl-comment">// Foreign key on posts table...</span>
            '<span class="hl-value">id</span>', <span class="hl-comment">// Local key on countries table...</span>
            '<span class="hl-value">id</span>' <span class="hl-comment">// Local key on users table...</span>
        );
    }
}
</pre>
 ]]></summary>

                <updated>2019-11-08T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Can I translate your blog? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/can-i-translate-your-blog"/>

                <id>https://www.stitcher.io/blog/can-i-translate-your-blog</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Yes. Yes you can. I do ask you to keep a few rules in mind.</p>
<h2 id="host-on-your-own"><a href="#host-on-your-own" class="heading-anchor">#</a> Host on your own</h2>
<p>Your translations should be hosted on your own blog. Maybe it's helpful for you to have access to the markdown source files, they can be found <a target="_blank" href="https://github.com/brendt/stitcher.io/tree/master/src/content/blog">here</a>.</p>
<h2 id="proper-attribution"><a href="#proper-attribution" class="heading-anchor">#</a> Proper attribution</h2>
<p>You're required to add a link to the original post at the start of your translation. Furthermore, please add a link tag in the <code>&lt;head&gt;</code> of your page to also point to the original post.</p>
<pre>&lt;<span class="hl-keyword">head</span>&gt;
    <span class="hl-comment">&lt;!-- … --&gt;</span>

    &lt;<span class="hl-keyword">link</span> 
        <span class="hl-property">rel</span>=&quot;alternate&quot; 
        <span class="hl-property">hreflang</span>=&quot;en&quot;
        <span class="hl-property">href</span>=&quot;https://stitcher.io/blog/can-i-translate-your-blog&quot; /&gt;
&lt;/<span class="hl-keyword">head</span>&gt;
</pre>
<h2 id="notify-me-about-translations"><a href="#notify-me-about-translations" class="heading-anchor">#</a> Notify me about translations</h2>
<p>I'd like to know about when you put a translation online. I plan on listing all translations on my blog somewhere at some point in the future, so it'd be handy if I could add yours.</p>
<p>You can notify me via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a>, <a href="mailto:brendt@stitcher.io">e-mail</a> or by making a <a target="_blank" href="https://github.com/brendt/stitcher.io">GitHub issue</a></p>
<h2 id="translate,-don't-interpret"><a href="#translate,-don't-interpret" class="heading-anchor">#</a> Translate, don't interpret</h2>
<p>I expect translations to be as close as possible to the original. You can add your own thoughts, but only if properly addressed. For example you can add a final section with additions to the original post, as long as you make it clear that it's not part of the original.</p>
<hr />
<p>One final remark: I appreciate it very much when people want to translate my content, so thank you very much!</p>
 ]]></summary>

                <updated>2019-11-07T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Guest posts ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/guest-posts"/>

                <id>https://www.stitcher.io/blog/guest-posts</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been thinking about the idea of allowing other people to write on my blog for a while now. Guest posting is popular in the broader blogging community, and I wanted to give it some careful thought.</p>
<p>I regularly get requests from people to write a guest post on this blog, but these requests often involve low-quality content just to boost SEO stats. This is something I want to stay far away from.</p>
<p>I realised though that there might be people out there who have a great idea for a blog post, but don't want to spend time maintaining a blog, and don't want to post to a network like Medium. Quality content might never be written because of this, and I realised that independent blogs like mine can offer a solution.</p>
<p>I think of it as a win-win: content creators get an outlet for their ideas, my audience gets more quality content to read, and this blog can keep on growing.</p>
<h2 id="quality-assurance"><a href="#quality-assurance" class="heading-anchor">#</a> Quality assurance</h2>
<p>Regular readers of my blog know that I try my best to only write quality content. I don't keep a schedule which forces me to write every week or month, I only write when I feel like I've got something to say that's worth sharing.</p>
<p>I want guest posts on this blog to be the same. That's why I will personally review every one of them, and will only post them when I think they meet a quality level my audience would appreciate.</p>
<p>I believe a set of rules and agreements is in place. If you're thinking about pitching a guest post, please read these carefully.</p>
<h3 id="your-content,-not-mine"><a href="#your-content,-not-mine" class="heading-anchor">#</a> Your content, not mine</h3>
<p>Guest posts will always stay your property, not mine. This means that if you ever want to move your content to your own blog, you're free to do so.</p>
<p>This of course also means that you're responsible for writing quality content. I'll be happy to review and help improve your content, but you'll be the one who has to do it.</p>
<p>This also means that guest posts will always be properly attributed. You'll be able to provide links to your social media or personal website.</p>
<p>Lastly, every one of my own blogposts has one ad in it, which helps keep this blog going. You're free to ask me to remove it in your content.</p>
<h3 id="what-to-expect-from-me?"><a href="#what-to-expect-from-me?" class="heading-anchor">#</a> What to expect from me?</h3>
<p>I will help you in reviewing your content and provide feedback to improve it. I'm by no means an expert writer or copy editor myself, but I have been doing this for a few years now, so I might be able to help you if you're a beginning writer.</p>
<p>Reviewing your content will either happen via mail or directly on GitHub, whichever you prefer. I will make sure to always discuss any changes I want to be made to the post, and will never alter your content without you knowing it.</p>
<p>Finally, I will also help promote your content once it's launched, and provide feedback regarding traffic afterwards. I cannot guarantee any hard numbers on what kind of traffic your post will get, but I can give you some numbers on the monthly traffic on my blog:</p>
<ul>
<li>Between 40k and 60k users per month, with 60k-80k sessions per month</li>
<li>My blog posts have on average between 1k and 6k sessions per month</li>
</ul>
<h2 id="now-what?"><a href="#now-what?" class="heading-anchor">#</a> Now what?</h2>
<p>Since this is new for me too, I've got no idea where it'll go from here on out. If you're interested in the idea and would like to talk about something concrete, feel free to <a href="mailto:brent@stitcher.io">send me an email</a> and we'll see whether we're a good match. Make sure to provide the following information:</p>
<ul>
<li>If you're a blogger, links to your existing content</li>
<li>Your motivation about why you want to write a guest post</li>
<li>An abstract about what you want to write about</li>
</ul>
 ]]></summary>

                <updated>2019-09-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ re: re: A letter to the PHP team ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-letter-to-the-php-team-reply-to-joe"/>

                <id>https://www.stitcher.io/blog/a-letter-to-the-php-team-reply-to-joe</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Thanks you Joe for taking the time to <a target="_blank" href="https://blog.krakjoe.ninja/2019/08/bearings.html">reply</a> to <a href="/blog/a-letter-to-the-php-team">my letter</a>, I really appreciate it! I'll be happy to reply here.</p>
<p>Your reply started by addressing the P++ shenanigans:</p>
<blockquote>
<p>A lot of the discussion is based on an assertion made during the P++ discussion that there are two camps of developers</p>
</blockquote>
<p>As a matter of fact, I <a target="_blank" href="https://github.com/brendt/stitcher.io/commit/26fc4de353ca6beaff1cfd7b5f4b0c86f4f739b6">started writing</a> my letter before the whole P++ galaxy discussion. Life got in the way though (my son was born at the beginning of August), which is why it took almost a month to publish it.</p>
<p>I just wanted to make clear that I already had many thoughts on the topic before P++ was ever mentioned.</p>
<blockquote>
<p>You can tell by looking at the history of RFCs that these factions do not in fact exist</p>
</blockquote>
<p>Whether we call it factions or not, if you take a look at recent RFCs, they have almost always gone off topic for to discuss the future of PHP on a broader scale. Sure there might only a few people, but loud voices are heard nevertheless.</p>
<p>A few examples:</p>
<ul>
<li>
<a target="_blank" href="https://externals.io/message/106713">Reclassifying engine warnings</a>
</li>
<li>
<a target="_blank" href="https://externals.io/message/106384">Short open tags</a>
</li>
<li>
<a target="_blank" href="https://externals.io/message/101323">Namespace-scoped declares</a>
</li>
<li>
<a target="_blank" href="https://externals.io/message/101254">Explicit call-site send-by-ref syntax</a>
</li>
<li>
<a target="_blank" href="https://externals.io/message/106012">Deprecations for 7.4</a>
</li>
</ul>
<p>This is how most of these discussion go:</p>
<ul>
<li>Nikita tries to move the language forward</li>
<li>Zeev and/or Stas advocate for backwards compatibility, resulting in the same long conversation over and over again</li>
<li>Sara tries to keep the middle ground</li>
<li>Dmitry is working on PHP 8 somewhere in the background, and steers away from these discussions</li>
</ul>
<blockquote>
<p>The rules were written many years ago - arguably for a totally different, pre social coding world - we mostly do a good job of following the rules as they are written.</p>
</blockquote>
<p>I think you addressed the essence of the problem: the way PHP internals work is outdated and inefficient in these modern times.</p>
<blockquote>
<p>It's important to point out that the rules are not exhaustive, a lot of how we behave is determined by convention. You can argue against this and say that we should try to exhaustively enumerate every possible action</p>
</blockquote>
<p>I'd argue we need a sensible and modern day rule set, which can be flexible.</p>
<blockquote>
<p>Recently an RFC was conducted to deprecate and remove short PHP tag syntax</p>
</blockquote>
<p>While I do have my opinions on maintaining backwards compatibility — which I addressed in the first part of my letter — I think the most important thing to take away from the short syntax RFC is that the process is clearly broken, and needs fixing.</p>
<blockquote>
<p>What we have here is a failing of our processes and nothing more. I and likely others are considering how we might avoid this very same failure in the future. It seems desirable at this time to introduce a formal deprecation policy, this both achieves the goal of avoiding this very same failure, and can potentially increase confidence when it comes to adopting new versions of PHP.</p>
</blockquote>
<p>Glad we're on the same page on this one, and I know from your comments on internals that you're also looking for a balanced solution. My question is whether this is possible within the current system. It feels like we're going around in circles and very little progress is made.</p>
<blockquote>
<p>First, for the sake of clarity. You must be careful how you determine something to be controversial. Loud, is not the same as controversial</p>
</blockquote>
<p>That's true, though a few loud voices can impact the development of PHP significantly. There aren't many core contributors, and they have to spend a lot of time reading and replying through the same discussions. I try to keep up-to-date with the internals list myself, so I know this is an exhaustive task.</p>
<blockquote>
<p>The time and effort it takes to change our processes is considerable, and only becomes a priority when it's obvious that our processes are failing, or have the potential to fail and do damage.</p>
</blockquote>
<p>I think PHP is only slowly evolving because there's so much needless discussions happening over and over again, I'd call that a failing process.</p>
<blockquote>
<p>I'm sure that you have a sample of data that shows you this, or you surely wouldn't have made this claim.</p>
</blockquote>
<p>Yes, I linked some recent examples previously.</p>
<blockquote>
<p>It's a matter of fact that some people can't seem to behave themselves on the internet, while I'm sure (read: must believe) they are reasonable people in real life. These people make themselves obvious very quickly and prove they have nothing much to say.</p>
</blockquote>
<p>I think some kind of moderation would be in place, as these people keep coming back, and there's no way to stop them. This is where a mailing list just doesn't suffice.</p>
<blockquote>
<p>I can't argue that mailing lists are a good way to communicate, but it's what we have.
However, it's not all we have:</p>
</blockquote>
<p>True, though the channels you list still don't seem to bridge the gap between core- and userland developers. This is evident by the amount of userland developers voicing their opinions on all kinds of social media. I think a public forum is the way to go here.</p>
<blockquote>
<p>This is regularly mentioned, and I think I'll be the first one to point out that to the extent which that is true, it is the communities fault.</p>
</blockquote>
<p>There are two groups here:</p>
<ul>
<li>People who are very much invested in PHP, but don't want anything to do with the internal discussions, because of offtopic and exhausting conversations</li>
<li>People who would actually want to contribute in the form of votes and input, but don't know how.</li>
</ul>
<p>The wiki isn't very clear on this:</p>
<blockquote>
<p>People with php.net VCS accounts that have contributed code to PHP</p>
<p>Representatives from the PHP community, that will be chosen by those with php.net VCS accounts
Lead developers of PHP based projects (frameworks, cms, tools, etc.)
regular participant of internals discussions</p>
</blockquote>
<p>Personally, I think of myself in this second group, though it's unclear to me whether my perception is correct. And I can think of several other developers who would be an accurate representation of the PHP community.</p>
<p>Should I ask? As a matter of fact, I did ask a core member personally, but didn't get a reply. Should I ask this question on the internals list? I'm unsure.</p>
<p>This is again an example of failing communication between core- and userland developers. There's a barrier that's perceived as uncrossable.</p>
<p>Now I'm not saying there is an actual barrier, I just say that it's perceived by many userland developers this way, myself included.</p>
<hr />
<p>Once again, thank you very much for your reply Joe. I highly appreciate it and am looking forward to read your comments on mine.</p>
<p>Kind regards
<br>
Brent</p>
 ]]></summary>

                <updated>2019-08-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ A letter to the PHP team ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-letter-to-the-php-team"/>

                <id>https://www.stitcher.io/blog/a-letter-to-the-php-team</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>To whomever contributes to PHP, from a userland developer.</p>
<p>Let me start by thanking those who actively work on the PHP project. Those who contribute to the core, extensions, maintain the docs or vote on RFCs: thank you for a language that I can use every day both in my professional and personal life. PHP has been a very useful tool to me for many years, and it's good to see lots of contributors help making it better every day.</p>
<p>I also want to mention that I, as everyone, am subject to confirmation bias. When I address one or two thoughts in this letter, I'll try my best to be as objective as possible, though I realise I'm looking through my lens, and not someone else's.</p>
<p>Since the goal of this letter is to start a conversation, I'm open to hear your thoughts. Also if they don't align with mine, please feel free to disagree.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<hr />
<p>I could continue by listing lots of good things — there are many. Though because I want to keep this letter on topic, I won't be doing that. Don't take this as me being a disgruntled developer, I simply want to be efficient in conveying what I want to say.</p>
<p>I want to write about how PHP is shaped and developed these days. I feel that I, as a userland developer, know a thing or two about using PHP in real projects. I believe I have an informed and relevant opinion on the matter.</p>
<p>Recently we've seen several discussions regarding the RFC voting process. Besides <a target="_blank" href="https://wiki.php.net/rfc/abolish-narrow-margins">recent</a> <a target="_blank" href="https://wiki.php.net/rfc/abolish-short-votes">changes</a> to the voting rules, there have also been a few controversial RFCs which passed the vote, and caused some — in some cases, lots of — controversy.</p>
<p>Two recent RFCs come to mind: the <a target="_blank" href="https://wiki.php.net/rfc/deprecate_php_short_tags">deprecation of the short open tags</a>, as well as <a target="_blank" href="https://wiki.php.net/rfc/deprecations_php_7_4">several small deprecations</a> for PHP 7.4.</p>
<p>Both RFCs caused discussion on whether these changes are actually beneficial to the language, whether they should be allowed with only a 2/3 majority vote, and whether they should be considered harmful to the PHP community.</p>
<p>The basis for most of these discussions is the fact that PHP tries to maintain backwards compatibility as much as possible. One of the main thoughts behind this is that we want users to stay up-to-date with modern PHP versions, so we should give them as little problems as possible to upgrade.</p>
<p>Lessons were, rightfully, learned from the 5.* era. I too share the opinion that all PHP developers and ecosystems should strive to stay up-to-date. It's a message that companies and developers should tell their clients at the start of every project: keeping it secure and up-to-date will take time, cost money, and there's no responsible way to avoid it.</p>
<p>It's a characteristic of professionalism.</p>
<p>On the other hand: if we want to achieve this professionalism with our clients, we are also allowed to spend reasonable amounts of time on upgrades. It is not the end of the world if there's a backwards incompatible change. We can deal with it.</p>
<p>As a day-by-day user of PHP, I have also had my share of legacy projects that needed updating. Let me tell you this: I much more prefer PHP to move forward and mature, rather than me spending less time on upgrades.</p>
<p>In a maturing language, it's evident that some old legacy stuff is cleaned up. It means that the language sometimes removes two ways to do the same thing. It means that, for example, short open tags are deprecated and removed. It means that sometimes my code will break. And as long as the language evolves in a good and healthy way, I don't mind.</p>
<p>If you're one of the enthusiastic guards of backwards compatibility: I know you mean well. But I don't think it's that big a deal you make out of it. The world will not end because there's a breaking change. We, userland developers, will manage.</p>
<p>Let's not waste too much time with seemingly endless discussion over and over again. Let's move forward in balanced way.</p>
<hr />
<p>Speaking of how we spend time. Internals have been discussing voting mechanics and what to do with controversial RFCs for months now.</p>
<p>Shouldn't we start looking at how other communities do this? For sure PHP can't be the only open source language out there?</p>
<p>Let's call the current way of PHP's development for what it really is: the same discussions happen over and over again on a weekly or monthly basis without any progress; people are personally attacking others regularly; an insignificant RFC takes months of discussion and requires a re-vote after being accepted; there aren't any good ways to share constructive feedback apart from the big mailing list; the group of voters doesn't seem to be an accurate representation the actual PHP community.</p>
<p>Am I fair to call this system, at least partially, broken?</p>
<p>I believe our system should be thoroughly evaluated, and I think we <em>should</em> look at how open source communities outside of PHP manage to keep moving their project forward in a healthy way.</p>
<p>One example is TC39, the committee that manages ECMAScript, aka JavaScript. Dr. Axel Rauschmayer wrote <a target="_blank" href="https://2ality.com/2015/11/tc39-process.html">a great post</a> about how the TC39 process works. Now, you might love or hate JavaScript, but it's clear that they are doing something right over there, given the lasting success of the language over the years.</p>
<p>One of the things they get right is an open communication channel with their community. Communication that is transparent and accessible between contributors and users via <a target="_blank" href="https://github.com/tc39/ecma262">GitHub</a>. Another language that does this is Rust, which provides <a target="_blank" href="https://internals.rust-lang.org">an open forum</a> to discuss how the language is shaped.</p>
<p>An open place like GitHub or a forum diminishes the barrier most userland developers experience with the internals mailing list. Many of us read it, though very little userland developers actually feel they can voice their opinion on it. I think there's two reasons for this:</p>
<ul>
<li>The mailing list is difficult to navigate compared to forums and threads</li>
<li>It's often a hostile place, lacking basic decency and proper moderation</li>
</ul>
<p>Better communication will close the current disconnect between the two groups, it will allow PHP to become what the actual majority of PHP users want it to be.</p>
<p>Besides communication, there's the matter of what features should be added to the language. TC39 provides a clear framework on how the language can evolve; it's a system that's superior to and less confusing than PHP's current RFC process.</p>
<p>I already mentioned that the RFC process has been an on-and-off hot debate for the past months; it's at the point where many RFC proposals on the mailing list spark the same discussion over and over again, with no results. Let's again look at committees like TC39, and fix it once and for all.</p>
<hr />
<p>There's more things to do to fix the current broken process of PHP's development, but I can't possibly list everything here today. So I think it'd be good to keep the conversation going. My suggestion would be to go over to <a target="_blank" href="https://www.reddit.com/r/PHP/comments/cwueyd/a_letter_to_the_php_team/">Reddit</a> where we can discuss it further, or send me an <a href="mailto:brendt@stitcher.io">email</a>.</p>
<p>Kind regards
<br>
Brent</p>
<hr />
<p>Update August 29: Joe Watkins was kind enough to write a reply. You can read it <a target="_blank" href="https://blog.krakjoe.ninja/2019/08/bearings.html">here</a>.</p>
<p>You can read my reply to Joe's <a href="/blog/a-letter-to-the-php-team-reply-to-joe">here</a>.</p>
 ]]></summary>

                <updated>2019-08-28T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Things dependency injection is not about ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/things-dependency-injection-is-not-about"/>

                <id>https://www.stitcher.io/blog/things-dependency-injection-is-not-about</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>If you're using any modern framework, chances are you're heavily relying on dependency injection. But do you know what dependency injection <em>actually</em> is about — or better: what it's <em>not</em>?</p>
<h2 id="the-dependency-container"><a href="#the-dependency-container" class="heading-anchor">#</a> The dependency container</h2>
<p>While every modern framework ships with a dependency container — a big box that knows how to construct objects for you — it doesn't guarantee you'll actually be using the dependency injection pattern the way it's supposed to be.</p>
<p>The container <em>can</em> make it much easier to have dependencies injected into a class, but it can also be abused quite a lot.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="service-location"><a href="#service-location" class="heading-anchor">#</a> Service location</h2>
<p>One way to (ab)use the container is to <em>pull</em> objects from it, instead of having them injected into the current context. This pattern is called "service location", and is the opposite of dependency injection. It looks like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">indexAction</span>()
    {
        <span class="hl-variable">$service</span> = <span class="hl-property">app</span>(<span class="hl-type">Service</span>::<span class="hl-keyword">class</span>);

        <span class="hl-comment">// …        </span>
    }
}
</pre>
<p>Service location will ask the container for a specific object. This makes the context you're pulling this service from a difficult point to test, as well as a black box to the outside: you're unable to know what kind of external dependencies <code>MyController</code> uses, without looking at all of the code.</p>
<p>Some frameworks promote this use of the container, because it can be simple and fast at the start of a project. In projects with hundreds, maybe even thousands of classes registered in the container, the use of service location can and will become a mess; one that proper use of dependency injection would solve.</p>
<p>I also recommend you to read my post on <a href="/blog/service-locator-anti-pattern">why service location is an anti-pattern</a>.</p>
<h2 id="shared-dependencies"><a href="#shared-dependencies" class="heading-anchor">#</a> Shared dependencies</h2>
<p>Moving on to some more positive vibes: making use of the container in a good way.</p>
<p>When dependency injection is properly used, the outside context — in many cases the container — has control over the concrete dependency that it's injecting into a class. This means that the same object can be injected into several other contexts, without those contexts having to know anything about them being "singletons" or "shared dependencies".</p>
<p>Even though sharing dependencies can be a good and powerful thing to do, it is still <em>not</em> what dependency injection is about, but rather a beneficial side effect.</p>
<h2 id="auto-wiring"><a href="#auto-wiring" class="heading-anchor">#</a> Auto wiring</h2>
<p>Finally, another useful feature that, again, isn't what dependency injection is about: autowiring.</p>
<p>To give developers more flexibility, some containers allow
for smart, automatically determined, class definitions.
This means you don't have to manually describe how every class should be constructed.
These containers will scan your code, and determine which dependencies are needed
by looking at type hints and doc blocks.</p>
<p>A lot of magic happens here, but auto wiring can be a useful tool for rapid application development.</p>
<hr />
<p>If by now, you want a refresher on the basics of what dependency injection <em>is</em> about. You can go read up on it <a href="/blog/dependency-injection-for-beginners">here</a>.</p>
 ]]></summary>

                <updated>2019-07-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Tests and types ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/tests-and-types"/>

                <id>https://www.stitcher.io/blog/tests-and-types</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Imagine a simple function: <code>rgbToHex</code>.
It takes three arguments, integers between 0 and 255; and converts it to a hexadecimal string.</p>
<p>Here's what this function's definition might look like in a dynamic, weakly typed language:</p>
<pre>rgbToHex(red, green, blue) {
    // …
}
</pre>
<p>I think we all agree that "program correctness" is essential.
We don't want any bugs, so we write tests.</p>
<pre>assert(rgbToHex(0, 0, 0) == '000000')

assert(rgbToHex(255, 255, 255) == 'ffffff')

assert(rgbToHex(238, 66, 244) == 'ee42f4')
</pre>
<p>Because of our tests, we can be sure our implementation works as expected. Right?</p>
<p>Well… We're actually only testing three out of the 16,777,216 possible colour combinations.
But human reasoning tells us that if these three cases work, all probably do.</p>
<p>What happens though if we pass doubles instead of integers?</p>
<pre>rgbToHex(1.5, 20.2, 100.1)
</pre>
<p>Or numbers outside of the allowed range?</p>
<pre>rgbToHex(-504, 305, -59)
</pre>
<p>What about <code>null</code>?</p>
<pre>rgbToHex(null, null, null)
</pre>
<p>Or strings?</p>
<pre>rgbToHex(&quot;red&quot;, &quot;green&quot;, &quot;blue&quot;)
</pre>
<p>Or the wrong amount of arguments?</p>
<pre>rgbToHex()

rgbToHex(1, 2)

rgbToHex(1, 2, 3, 4)
</pre>
<p>Or a combination of the above?</p>
<p><a name="read-on"></a></p>
<p>I can easily think of five edge-cases we need to test,
before there's relative certainty our program does what it needs to do.
That's at least eight tests we need to write — and I'm sure you can come up with a few others given the time.</p>
<p>These are the kind of problems a type system aims to <em>partially</em> solve.
And note that word <em>partially</em>, we'll come back to it.</p>
<p>If we filter input by a type — you can think of it as a subcategory of all available input — many of the tests become obsolete.</p>
<p>Say we'd only allow integers:</p>
<pre>rgbToHex(Int red, Int green, Int blue) 
{
    // …
}
</pre>
<p>Let's take a look at the tests that aren't necessary anymore thanks to the <code>Int</code> type:</p>
<ul>
<li>Whether the input is numeric</li>
<li>Whether the input is a whole number</li>
<li>Whether the input isn't null</li>
</ul>
<p>To be honest, we can do better than this:
we still need to check whether the input number is between 0 and 255.</p>
<p>Unfortunately at this point, we run against the limitations of many type systems.
Sure we can use <code>Int</code>, though in many cases (as with ours)
the category described by this type is still too large for our business logic.
Some languages have a <code>UInt</code> or "unsigned integer" type;
yet this still too large a subset of "numeric data".</p>
<p>Luckily, there are ways to address this issue.</p>
<p>One approach could be to use "configurable" or generic types, for example <code>Int&lt;min, max&gt;</code>.
The concept of generics is known in many programming languages,
though I'm unaware of any language that let's you configure scalar types such as integers.</p>
<p>Edit: one of my readers let me know this <em>is</em> possible in Ada. Thanks, Adam!</p>
<p>Nevertheless in theory, a type could be preconfigured in such a way that it's smart enough to know about your business logic.</p>
<p>Languages that lack these kinds of generic types, often need to build custom types.
Being an OO programmer myself, I would use classes to do this.</p>
<pre>class MinMaxInt
{
    public MinMaxInt(Int min, Int max, Int value)
    {
        assert(min &lt;= value &lt;= max)
        
        this.value = value
    }
}
</pre>
<p>If we're using an instance of <code>MinMaxInt</code>, we can be sure its value is constrained within a subset of integers.</p>
<p>Still, this <code>MinMaxInt</code> class is too generic for our case.
If we were to type <code>rgbToHex</code> with it, we're still not sure what the exact boundaries are:</p>
<pre>rgbToHex(MinMaxInt red, MinMaxInt green, MinMaxInt blue) 
{
    // …
}
</pre>
<p>We need a more specific type: <code>RgbValue</code>.
Adding it depends, again, on the programming language and personal preference.
I would extend <code>MinMaxInt</code>, but feel free to do whatever fits you best.</p>
<pre>class RgbValue extends MinMaxInt
{
    public RgbValue(Int value)
    {
        parent(0, 255, value)
    }
}
</pre>
<p>Now we've arrived at a working solution.
By using the <code>RgbValue</code> type, most of our tests become redundant.</p>
<pre>rgbToHex(RgbValue red, RgbValue green, RgbValue blue) 
{
    // …
}
</pre>
<p>We can now have one test to test the business logic: "given three ((RGB))-valid colors,
does this function return the correct HEX value?" — a great improvement!</p>
<h2 id="caveats"><a href="#caveats" class="heading-anchor">#</a> Caveats</h2>
<p>Close readers can already think of one or two counter arguments.
Let's address them.</p>
<h3 id="tests-are-just-moved"><a href="#tests-are-just-moved" class="heading-anchor">#</a> Tests are just moved</h3>
<p>If we're building custom types, we still have to test those.
That's true in my example, which is influenced by the languages I work in.</p>
<p>It depends on the capabilities of the language though.
Given a language that allows this:</p>
<pre>rgbToHex(
    Int&lt;0, 255&gt; red, 
    Int&lt;0, 255&gt; green, 
    Int&lt;0, 255&gt; blue
) {
    // …
}
</pre>
<p>You'd need zero extra tests, as the features are baked into the language itself.</p>
<p>But even if we're stuck with having to build custom types and testing them:
don't forget they are reusable throughout the code base.</p>
<p>Chances are you'll be able to re-use most of the types you're making;
as these custom categories most likely apply to your business, and are used throughout it.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h3 id="verbosity"><a href="#verbosity" class="heading-anchor">#</a> Verbosity</h3>
<p>Next, many would consider my solution too verbose when actually using it:</p>
<pre>rgbToHex(
    new RgbValue(60),
    new RgbValue(102),
    new RgbValue(79)
);
</pre>
<p>While I personally don't mind this verbosity — I know the benefits of a stronger type system — I'd like to ask you to think out of your box for a moment.
This argument isn't against stronger types, it's one against your programming language.</p>
<p>The verbosity is caused by the lack of proper syntax provided by the language.
Fortunately I can think of ways the problem could be solved.</p>
<p>One solution is type juggling.
Dynamic languages are actually pretty good at it.
Say you'd pass a simple integer as the input,
the compiler can try and cast that integer to an object of <code>RgbValue</code>.
It could even be aware of possible types which could be cast to <code>RgbValue</code>,
so you'd still have compile-time error detection.</p>
<h3 id="example-in-isolation"><a href="#example-in-isolation" class="heading-anchor">#</a> Example in isolation</h3>
<p>Another objection might be that your real-life code base obviously differs from a simple <code>rgbToHex</code> function.</p>
<p>I want to argue the opposite though: the reasoning behind this example can be applied to any part of your code.
The actual difficulty lies in the languages and frameworks used:
if strong types aren't built in from the ground up,
you're gonna have a hard time getting the most use out of them.</p>
<p>This is where I should recommend you to watch <a target="_blank" href="https://www.destroyallsoftware.com/talks/ideology">this talk</a> by Gary Bernhardt,
it's less than 30 minutes long.
In it, he takes the topic of type systems and confronts us with our own prejudices and ideologies about them.</p>
<p>Afterwards you can apply this thinking on the current frameworks and languages you're using.</p>
<p>While my example is an example in isolation, the underlying problems solved by stronger types can easily be scaled,
<em>if</em> the infrastructure supports it.</p>
<p>So am I suggesting you should ditch your whole stack, or that you're a bad programmer for using a weakly typed language?
Definitely not!</p>
<p>I myself program in PHP every day, it's <a href="/blog/php-in-2019">not as bad as it used to be</a>.
PHP introduced an opt-in type system, so it's possible to write fairly strongly typed code,
even though the language wasn't originally built for it.
Another example coming to mind is JavaScript with TypeScript.</p>
<p>So it is possible to leverage a type system, even in many languages that weren't originally built for it.
But it will require a mind shift from your side.
In my experience, it's worth the effort.</p>
<h3 id="limitations"><a href="#limitations" class="heading-anchor">#</a> Limitations</h3>
<p>Finally, let's address the elephant in the room when it comes to type systems.
I hope it's clear that, while many tests may be omitted thanks to a strong type system, some still need to be written.</p>
<p>People claiming you don't have to write tests in strongly typed languages are wrong.</p>
<p>Remember the <em>partially</em> I mentioned earlier?</p>
<p>In an ideal world, the perfect type system would be able to account for all specific categories required by your business.
This is impossible to do though, as computers and programming languages only have limited resources to work with.</p>
<p>So while strong types can help us to ensure program correctness,
some tests will always be a necessity to ensure business correctness.
It's a matter of "both and", not "either or".</p>
<h2 id="closing-remarks"><a href="#closing-remarks" class="heading-anchor">#</a> Closing Remarks</h2>
<p>I mentioned several concepts in this posts,
but I also mentioned I didn't know of programming languages using some of the concepts I described.
I'd love to give some concrete examples though.</p>
<p>So if you're working in a language that should be mentioned in this post,
please let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a>, <a href="mailto:brendt@stitcher.io">e-mail</a>, or wherever you read this post on social media.</p>
<p>You can of course also reach out to share other thoughts on this topic, I'd love to hear from you!</p>
 ]]></summary>

                <updated>2019-06-07T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What are objects anyway? - Rant With Brent 02 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/what-are-objects-anyway-rant-with-brent"/>

                <id>https://www.stitcher.io/blog/what-are-objects-anyway-rant-with-brent</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In this second episode, I take a look at the original definition of "Object Oriented Programming",
and compare it to what we call OOP today.</p>
<p><audio
controls
src="http://feeds.soundcloud.com/stream/629614707-brent-roose-826312539-what-are-objects-anyway-rant-with-brent-2.mp3">
</audio></p>
<p>You can download the episode <a target="_blank" href="http://feeds.soundcloud.com/stream/629614707-brent-roose-826312539-what-are-objects-anyway-rant-with-brent-2.mp3">here</a>
or listen on <a target="_blank" href="https://podcasts.apple.com/be/podcast/rant-with-brent/id1462956030">Apple Podcasts</a>, <a target="_blank" href="https://www.stitcher.com/s?fid=403581&amp;refid=stpr.">Stitcher Radio</a> and <a target="_blank" href="https://open.spotify.com/show/43sF0kY3BWepaO9CkLvVdJ?si=R-MIXaMHQbegQyq3gQm7Yw">Spotify</a></p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
 ]]></summary>

                <updated>2019-06-05T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ A project at Spatie ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-project-at-spatie"/>

                <id>https://www.stitcher.io/blog/a-project-at-spatie</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>The month of May marks the first year anniversary of a client project I've been working on at Spatie.
I thought it useful to share some statistics with the community,
and give you a feeling of what a "real life web project" might look like.</p>
<p>Let's start with a general overview.
The project, a web application, features an admin interface to manage inventories, contacts and contracts;
bookings, automatic invoicing and about ten third party integrations.</p>
<p>In the future we'll be exposing several of these features to the outside via an API,
its main goal to power a mobile app for clients of the platform.
The admin panel is already in use in production.</p>
<p>The project is built in Laravel, a PHP framework.
We use Blade as a templating engine in combination with many VueJS components.
Tailwind is the CSS framework used.</p>
<h2 id="some-numbers"><a href="#some-numbers" class="heading-anchor">#</a> Some numbers</h2>
<p>So, how much code have we written the past year? Here's a summary,
gathered with the <a target="_blank" href="https://github.com/sebastianbergmann/phploc">phploc</a> package:</p>
<ul>
<li>2,062 files</li>
<li>126,736 lines of code</li>
<li>97,423 logical lines of code</li>
</ul>
<p>Let's zoom into statistics about the backend code, my area:</p>
<ul>
<li>1,086 classes; 32 interfaces; 28 traits</li>
<li>Average LLOC per class: 8</li>
<li>Maximum LLOC per class: 139</li>
<li>3,245 public methods</li>
</ul>
<p>The amount of lines split per file type looks like this:</p>
<p><img src="/resources/img/blog/project-stats/loc.png" srcset="/resources/img/blog/project-stats/loc-756x467.png 756w, /resources/img/blog/project-stats/loc-1069x661.png 1069w, /resources/img/blog/project-stats/loc-534x330.png 534w, /resources/img/blog/project-stats/loc-926x572.png 926w, /resources/img/blog/project-stats/loc-1196x740.png 1196w" sizes="" alt=""></img></p>
<p>Let's further dive into how the backend code is structured,
by using Stefan's <a target="_blank" href="https://github.com/stefanzweifel/laravel-stats">laravel-stats</a> package.</p>
<p>To start with, I should explain something about our big Laravel projects.
Instead of using the default Laravel project structure, our code is split into two namespaces:
"application code" and "domain code".</p>
<p>Domain code holds all business logic and is used by the application layer.
If you want to dive further into this topic, you can read about it <a href="/blog/organise-by-domain">here</a>.</p>
<p>The following graph shows how application and domain code relate to each other:</p>
<p><img src="/resources/img/blog/project-stats/domain-v-application.png" srcset="/resources/img/blog/project-stats/domain-v-application-1073x738.png 1073w, /resources/img/blog/project-stats/domain-v-application-1200x826.png 1200w, /resources/img/blog/project-stats/domain-v-application-758x521.png 758w, /resources/img/blog/project-stats/domain-v-application-536x368.png 536w, /resources/img/blog/project-stats/domain-v-application-929x639.png 929w" sizes="" alt=""></img></p>
<p>By splitting business and application code,
we're able to provide a flexible, maintainable and highly testable core.
Application code makes use of this core and looks very much like your average Laravel project.</p>
<p>The bulk of our domain code consists of three types of classes:</p>
<ul>
<li>Models — 80 classes</li>
<li>Actions — 205 classes</li>
<li>DTOs — 63 classes</li>
</ul>
<p>While the application layer mostly consists of:</p>
<ul>
<li>Controllers — 130 classes and 309 routes</li>
<li>ViewModels — 82 classes</li>
<li>Blade views — 313 files; these are not included in the chart above</li>
</ul>
<p>Because of the lifecycle of the project, there's room for improvement.
For example, we're not using <a target="_blank" href="https://stitcher.io/blog/structuring-unstructured-data">DTOs</a> everywhere,
as they were added at a later time.</p>
<p>As with all things: we learn as we go.
After a year, it's normal that some parts of the code can be considered "old".
We have a rule that states that when we work in these old parts of the codebase, we refactor them.</p>
<p>A big advantage of moving code into domains is testability.
While our domain code is heavily unit tested, our application code is mostly only integration tested.
In our experience, it's a workable balance between highly tested code and being able to meet deadlines.</p>
<p>At the moment we have 840 tests doing 1,728 assertions.
Our test suite could always be improved,
but I am very confident deploying new features and refactors without the fear of breaking stuff — thanks to our test suite.</p>
<h2 id="code-structure"><a href="#code-structure" class="heading-anchor">#</a> Code structure</h2>
<p>I'm a big proponent of clean code.
We try to keep our code clean and maintainable, by setting a few rules of thumb:</p>
<ul>
<li>Classes should be small, 50 lines of code should be the maximum</li>
<li>Methods should also be small and easy to reason about</li>
<li>We prefer clear names over short and cryptic names</li>
</ul>
<p>You probably noticed that we don't always keep these rules.
There are some classes that are longer and more complex.</p>
<p>These classes are the result of making choices:
sometimes some technical debt is allowed to meet deadlines — as long as we're aware of it.</p>
<p>I've made a <a target="_blank" href="https://github.com/spatie/code-outliner">little tool</a> in the past which I use to generate "heat maps" of the codebase.
It will take all code in a folder, and generate an image by overlaying the code structure on top of it.</p>
<p>I can use this tool to locate large files, and refactor them when there's time.
We have done this in the past, and it works very well.</p>
<p>Here's part of this image of a subdomain in our project:</p>
<p><img src="/resources/img/blog/project-stats/outline.png" srcset="/resources/img/blog/project-stats/outline-715x1286.png 715w, /resources/img/blog/project-stats/outline-800x1439.png 800w, /resources/img/blog/project-stats/outline-357x642.png 357w, /resources/img/blog/project-stats/outline-619x1113.png 619w, /resources/img/blog/project-stats/outline-505x908.png 505w" sizes="" alt=""></img></p>
<p>The darker the image, the more code across all files in that position.
You can see that while some files are longer, most of the code lives in the upper 50 lines,
something we strive for.</p>
<p>We ensure these short classes and consistent code by using a few tools and methods:</p>
<ul>
<li>Internal PRs and code reviews; despite what you might think, this saves time</li>
<li>We use static analysis, more specifically <a target="_blank" href="https://github.com/phpstan/phpstan">PhpStan</a>;
to prevent subtle bugs</li>
<li>We use <a target="_blank" href="https://github.com/FriendsOfPHP/PHP-CS-Fixer">PHP CS fixer</a> to ensure consistent code style</li>
</ul>
<p>Like I said before: I'm a firm proponent of clean code.
When you're working with several people in the same codebase,
it's a must to keep your code clean and clear, to secure its future.</p>
<hr />
<p>So what about your projects? Are you able to share your own stats?
Feel free to send me a <a target="_blank" href="https://twitter.com/brendt_gd">tweet</a> or an <a href="mailto:brendt@stitcher.io">email</a>!</p>
 ]]></summary>

                <updated>2019-05-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ A programmer&#039;s cognitive load ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/a-programmers-cognitive-load"/>

                <id>https://www.stitcher.io/blog/a-programmers-cognitive-load</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>As a professional programmer, I'm reading and writing code on a daily basis.
I'm working on new projects, doing code reviews, working with legacy code, reading through documentation etc.
Based on my own experience and that of colleagues, being a programmer often involves a lot more reading than actually writing code.</p>
<p>Whether it's your own code or that of others, when you open a file you have to take it all in.
You need to wrap your head around what's going on, before you're able to write your code, do your thing.</p>
<p>Having to deal with code almost every day, it's important to find ways to make this process easy.
To try and reduce the cognitive load it puts on your brain as much as possible.</p>
<p>Making code easier to read will allow you to work faster and better, and also improve your mental state and mood.</p>
<blockquote>
<p>In cognitive psychology, cognitive load refers to the total amount of mental effort being used in the working memory - <a target="_blank" href="https://en.wikipedia.org/wiki/Cognitive_load">wikipedia</a></p>
</blockquote>
<p>Today I want to share some techniques that can help you reduce cognitive load while coding.
In contrast to some recent advocates of "visual debt", I won't talk about stripping away pieces of your codebase.
We'll look purely into the visual aspect: what makes code hard to read and reason about, and how to make it easier.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="fonts-and-spacing"><a href="#fonts-and-spacing" class="heading-anchor">#</a> Fonts and spacing</h2>
<p>Fonts have an influence on our mood.
The <a target="_blank" href="https://crew.co/blog/the-psychology-of-fonts/">people at Crew</a> wrote an interesting piece about how fonts make us feel.
The font you choose has a big impact on how much load is put on your brain to process the text on your screen.
It's not just the font by the way, but also its size, line height and letter spacing plays a role.</p>
<p>Typography itself is a topic books are written about.
I encourage you to think about your current font choice, and how it influences the way you read code.</p>
<p>Here's a comparison between a not-so-good and better font configuration, in my experience.</p>
<p><img src="/resources/img/blog/cognitive-load/aestetics-1.png" srcset="/resources/img/blog/cognitive-load/aestetics-1-1161x1249.png 1161w, /resources/img/blog/cognitive-load/aestetics-1-948x1020.png 948w, /resources/img/blog/cognitive-load/aestetics-1-670x720.png 670w, /resources/img/blog/cognitive-load/aestetics-1-1341x1442.png 1341w, /resources/img/blog/cognitive-load/aestetics-1-1500x1614.png 1500w" sizes="" alt=""></img></p>
<p><img src="/resources/img/blog/cognitive-load/aestetics-2.png" srcset="/resources/img/blog/cognitive-load/aestetics-2-1161x1258.png 1161w, /resources/img/blog/cognitive-load/aestetics-2-670x726.png 670w, /resources/img/blog/cognitive-load/aestetics-2-1500x1626.png 1500w, /resources/img/blog/cognitive-load/aestetics-2-1341x1453.png 1341w, /resources/img/blog/cognitive-load/aestetics-2-948x1027.png 948w" sizes="" alt=""></img></p>
<h2 id="folding"><a href="#folding" class="heading-anchor">#</a> Folding</h2>
<p>Ever worked with a controller providing some CRUD actions?
A class with a few methods?
Folding your method bodies by default gives you a much clearer overview of the class when opening a file.
It makes it easier to decide where you want to go to, instead of scrolling and searching.
Take a look at the following example.</p>
<p><img src="/resources/img/blog/cognitive-load/aestetics-3.png" srcset="/resources/img/blog/cognitive-load/aestetics-3-1500x1291.png 1500w, /resources/img/blog/cognitive-load/aestetics-3-948x815.png 948w, /resources/img/blog/cognitive-load/aestetics-3-1161x999.png 1161w, /resources/img/blog/cognitive-load/aestetics-3-1341x1154.png 1341w, /resources/img/blog/cognitive-load/aestetics-3-670x576.png 670w" sizes="" alt=""></img></p>
<p>IDEs like IntelliJ can fold code by default: <code>Settings &gt; Editor &gt; General &gt; Code Folding</code>.
I was a bit hesitant to enable it by default, but I can assure you this is an amazing feature once you're used to it.</p>
<p>It's also more convenient compared to the file structure navigator many IDEs and editors provide.
This approach allows you to see the visual structure, color and indentation of the class.</p>
<p>You'll probably want to learn the keybinds associated with folding too. On Mac with IntelliJ, these are the defaults: <code>⌘⇧+</code>, <code>⌘⇧-</code>, <code>⌘+</code> and <code>⌘-</code>.</p>
<h2 id="documentation"><a href="#documentation" class="heading-anchor">#</a> Documentation</h2>
<p>Documentation and comments are good tool to clarify what code actually does.
Furthermore, some languages and IDEs rely on comment meta data to provide proper static analysis.
We shouldn't overdo it though: docblocks and comments often state the obvious things, which are already known by reading the code.</p>
<p>After several years of programming, I can safely say that about 80-90% of comments are redundant.
They should be removed to clear visual overload, but you also need to provide something in their place:</p>
<ul>
<li>Clear naming of methods, variables, constants, etc.</li>
<li>Use proper type annotations and definitions</li>
</ul>
<p>Self documented code is better than relying on comments.
My rule of thumb when adding a comment is asking the following question:
"Does this comment actually add more information than already available through the code?".
If the answer is no, the comment shouldn't be there.</p>
<p>Removing these comment frees up your code, giving you visual "space to breath".</p>
<h2 id="naming-things"><a href="#naming-things" class="heading-anchor">#</a> Naming things</h2>
<p>Another important thing to keep in mind: how to name things?
It's better to give a variable a longer, descriptive name; rather than make them as short as possible.</p>
<p>Short, cryptic names make sense at the moment of writing the code;
but even a few days after you've written them, they already become vague and meaningless.</p>
<p>Better to write a little more, than to read ten times as much to understand what you've written in the past.</p>
<p>Here are a few examples from an project of mine:</p>
<ul>
<li>I renamed <code>createPage()</code> to <code>createPaginatedPage()</code>.</li>
<li>
<code>$process</code> became <code>$pageRenderProcess</code>.</li>
<li>
<code>testStitcher()</code> changed to multiple methods, one of which called <code>test_stitch_multiple_routes()</code>.</li>
</ul>
<h2 id="colours"><a href="#colours" class="heading-anchor">#</a> Colours</h2>
<p>This might be a sensitive topic for many people;
though I want to ask you to give me the benefit of the doubt for a minute.
We all like our dark, cool looking colour schemes, but there's a problem with them.</p>
<p>Research shows that the human eye is better equipped to read dark text on light backgrounds,
than the other way around. Back in the 80's, when personal computing was growing in popularity,
a guy called Etienne Grandjean did an <a target="_blank" href="https://dl.acm.org/citation.cfm?id=578434">extensive study</a>
on how text is best read on screens.</p>
<p>It turned out that light colour schemes are, for almost all people, the better choice.</p>
<p>Now your first thought might be that light colour schemes actually hurt your eyes,
but this has more to do with the brightness of your screen, than the colour scheme itself.</p>
<p>It's true that a light colour scheme can cause headaches and painful eyes if you don't turn down the brightness of your screen.
On the other hand, a less bright screen in combination with a light colour scheme will put less load on your eyes,
which makes reading code for long periods of time less exhaustive.</p>
<p>I can say what I want of course,
but the best thing I could do is challenge you to a one-week tryout.
I've challenged many programmers before, and most of them were actually convinced of a light theme after a few days.</p>
<p>It's up to you! Here's how my code looks like these days:</p>
<p><img src="/resources/img/blog/cognitive-load/aestetics-4.png" srcset="/resources/img/blog/cognitive-load/aestetics-4-670x590.png 670w, /resources/img/blog/cognitive-load/aestetics-4-1341x1180.png 1341w, /resources/img/blog/cognitive-load/aestetics-4-948x834.png 948w, /resources/img/blog/cognitive-load/aestetics-4-1161x1022.png 1161w, /resources/img/blog/cognitive-load/aestetics-4-1499x1320.png 1499w" sizes="" alt=""></img></p>
<p>Be sure to let me know how the challenge went!
You can reach me on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
<hr />
<p>The points I listed today have almost nothing to do with how you write real code (programming logic, patterns used, etc.).
But they have an impact on the cognitive load put on your brain day by day.</p>
<p>They take away some of the pain points when writing code.
They allow you to enjoy programming more.</p>
 ]]></summary>

                <updated>2017-06-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ I&#039;m starting a podcast ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/starting-a-podcast"/>

                <id>https://www.stitcher.io/blog/starting-a-podcast</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>It's only been two weeks since I announced I'm <a href="/blog/starting-a-newsletter">starting a newsletter</a>,
and here I am again with something new: a podcast.</p>
<p>People who know me IRL know I listen to <em>lots</em> of podcasts every day.
I did some internet radio a few years ago, and since then always wanted to pick it up again.</p>
<p>Ever since my wife and I bought our house, I've slowly been working on my amateur "studio",
and I've come to the point where I feel comfortable recording in it.
Here's my view when recording:</p>
<p><img src="/resources/img/blog/podcast/podcast.jpg" srcset="/resources/img/blog/podcast/podcast-2197x1520.jpg 2197w, /resources/img/blog/podcast/podcast-3474x2404.jpg 3474w, /resources/img/blog/podcast/podcast-1553x1074.jpg 1553w, /resources/img/blog/podcast/podcast-2690x1861.jpg 2690w, /resources/img/blog/podcast/podcast-3107x2150.jpg 3107w" sizes="" alt=""></img></p>
<p>Anyway, I just wanted to let you know that I'm starting this thing.
Just like the newsletter it'll be sporadic.
I prefer quality over quantity, so don't expect anything weekly.</p>
<p>I called it "Rant With Brent", and if you'd ask me to summarize,
I'd say it's a no-nonsense, straight to the point podcast about programming.
I don't want to waste 30 minutes of your time, when the same could be said in 10.</p>
<p>I do my best to make an episode highly informative and worth your time.
If you want to give it a chance,
you can find the podcast on <a target="_blank" href="https://podcasts.apple.com/be/podcast/rant-with-brent/id1462956030">iTunes</a>, <a target="_blank" href="https://www.stitcher.com/s?fid=403581&amp;refid=stpr.">Stitcher</a> and <a target="_blank" href="https://open.spotify.com/show/43sF0kY3BWepaO9CkLvVdJ?si=R-MIXaMHQbegQyq3gQm7Yw">Spotify</a>.</p>
 ]]></summary>

                <updated>2019-05-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP in 2019 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-in-2019"/>

                <id>https://www.stitcher.io/blog/php-in-2019</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Do you remember the popular "<a target="_blank" href="https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/">PHP: a fractal of bad design</a>" blog post?
The first time I read it, I was working in a crappy place with lots of legacy PHP projects.
This article got me wondering whether I should just quit and go do something entirely different than programming.</p>
<p>Luckily for me I was able to switch jobs shortly thereafter and,
more importantly, PHP managed to evolve quite a bit since the 5.* days.
Today I'm addressing the people who are either not programming in PHP anymore,
or are stuck in legacy projects.</p>
<p>Spoiler: some things still suck today, just like almost every programming language has its quirks.
Many core functions still have their inconsistent method signatures,
there are still confusing configuration settings,
there are still many developers out there writing crappy code — because they have to, or because they don't know better.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Today I want to look at the bright side:
let's focus on the things that have changed and ways to write clean and maintainable PHP code.
I want to ask you to set aside any prejudice for just a few minutes.</p>
<p>Afterwards you're free to think exactly the same about PHP as you did before.
Though chances are you will be surprised by some of the improvements made to PHP in the last few years.</p>
<h2 id="tl;dr"><a href="#tl;dr" class="heading-anchor">#</a> TL;DR</h2>
<ul>
<li>PHP is actively developed with a new release each year</li>
<li>PHP 7.4 is one of the <a href="/blog/new-in-php-74">most feature-packed</a> releases ever</li>
<li>Performance since the PHP 5 era has doubled, if not tripled</li>
<li>There's a extremely active eco system of frameworks, packages and platforms</li>
<li>PHP has had lots of new features added to it over the past few years, and the language keeps evolving</li>
<li>Tooling like static analysers has matured over the past years, and only keeps growing</li>
</ul>
<p>Update: people asked me to show some actual code.
I'm happy to say that's possible! Here's the <a target="_blank" href="https://github.com/brendt/aggregate.stitcher.io">source code</a>
of one of my hobby projects, written in PHP and Laravel;
and <a target="_blank" href="https://spatie.be/open-source/packages">here</a> is a list of a few hundred OSS packages we maintain at our office.
Both are good examples of what modern PHP projects look like.</p>
<p>Let's start.</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="history-summarized"><a href="#history-summarized" class="heading-anchor">#</a> History summarized</h2>
<p>For good measure, let's quickly review PHP's release cycle today.
We're at PHP 7.4 now, and PHP 8.0 will be the next version after that.</p>
<p>Ever since the late 5.* era, the core team tries to keep a yearly release cycle,
and have succeeded in doing so for the past four years.</p>
<p>In general, every new release is actively supported for two years,
and gets one more year of "security fixes only".
The goal is to motivate PHP developers to stay up-to-date as much as possible:
small upgrades every year are way more easy than making the jump between 5.4 to 7.0, for example.</p>
<p>An active overview of PHP's timeline can be found <a target="_blank" href="https://www.php.net/supported-versions.php">here</a>.</p>
<p>Lastly, PHP 5.6 was the latest 5.* release, with 7.0 being the next one.
If you want to know what happened to PHP 6, you can listen to the <a target="_blank" href="https://www.phproundtable.com/episode/what-happened-to-php-6">PHP Roundtable podcast</a>.</p>
<p>With that out of the way, let's debunk some common misconceptions about modern PHP.</p>
<h2 id="php's-performance"><a href="#php's-performance" class="heading-anchor">#</a> PHP's performance</h2>
<p>Back in the 5.* days, PHP's performance was… average at best.
With 7.0 though, large parts of PHP's core were rewritten from the ground up,
resulting in two or three times performance increases.</p>
<p>Words don't suffice though. Let's look at benchmarks.
Luckily other people have spent lots of time in benchmarking PHP performance.
I find that <a target="_blank" href="https://kinsta.com/blog/php-benchmarks/">Kinsta</a> has a good updated list.</p>
<p>Ever since the 7.0 upgrade, performance only increased.
So much that PHP web applications have comparable — in some cases better — performance than web frameworks in other languages.
Take a look at this <a target="_blank" href="https://github.com/the-benchmarker/web-frameworks">extensive benchmark suite</a>.</p>
<p>Sure PHP frameworks won't outperform C and Rust, but they are equally performant as Django, Rails or Express.</p>
<h2 id="frameworks-and-ecosystem"><a href="#frameworks-and-ecosystem" class="heading-anchor">#</a> Frameworks and ecosystem</h2>
<p>Speaking of frameworks: PHP isn't just WordPress anymore.
Let me tell you something as a professional PHP developer:
WordPress isn't in any way representative of the contemporary ecosystem.</p>
<p>In general there are two major web application frameworks, and a few smaller ones: <a target="_blank" href="https://symfony.com/">Symfony</a> and <a target="_blank" href="https://laravel.com/">Laravel</a>.
Sure there's also Zend, now called Laminas; Yii, Cake, Code Igniter etc.
— but if you want to know what modern PHP development looks like, you're good with one of the first two.</p>
<p>Both frameworks have a large ecosystem of packages and products.
Ranging from admin panels and CRMs to standalone packages, CI to profilers,
numerous services like web sockets servers, queuing managers, payment integrations;
honestly there's too much to list.</p>
<p>These frameworks are meant for actual development though.
If you're in need of pure content management,
platforms like WordPress and CraftCMS are only improving more and more.</p>
<p>One way to measure the current state of PHP's ecosystem is to look at Packagist, the main package repository for PHP.
It has seen exponential growth.
With ±25 million downloads a day, it's fair to say that the PHP ecosystem isn't the small underdog it used to be.</p>
<p>Take a look at this graph, listing the amount of packages and versions over time.
It can also be found on <a target="_blank" href="https://packagist.org/statistics">the Packagist website</a>.</p>
<p><img src="/resources/img/blog/php-in-2019/packagist.png" srcset="/resources/img/blog/php-in-2019/packagist-1954x766.png 1954w, /resources/img/blog/php-in-2019/packagist-1513x593.png 1513w, /resources/img/blog/php-in-2019/packagist-873x342.png 873w, /resources/img/blog/php-in-2019/packagist-1747x684.png 1747w, /resources/img/blog/php-in-2019/packagist-1235x484.png 1235w" sizes="" alt=""></img></p>
<p>Besides application frameworks and CMSs, we've also seen the rise of asynchronous frameworks the past years.
These are frameworks and servers, written in PHP or other languages,
that allow users to run truly asynchronous PHP.
A few examples include <a target="_blank" href="https://www.swoole.co.uk/">Swoole</a>, <a target="_blank" href="https://amphp.org/">Amp</a> and <a target="_blank" href="https://reactphp.org/">ReactPHP</a>.</p>
<p>Since we've ventured into the async world,
stuff like web sockets and applications with lots of IO have become actually relevant in the PHP world.</p>
<p>There has also been talk on the internals mailing list — the place where core developers discuss the development of the language —
to <a target="_blank" href="https://externals.io/message/102415#102415">add libuv to the core</a>.
For those unaware of libuv: it's the same library Node.js uses to allow all its asynchronicity.</p>
<h2 id="the-language-itself"><a href="#the-language-itself" class="heading-anchor">#</a> The language itself</h2>
<p>While <code>async</code> and <code>await</code> are not available yet, lots of improvements to the language itself have been made over the past years.
Here's a non-exhaustive list of new features in PHP:</p>
<ul>
<li>
<a href="/blog/short-closures-in-php">Short closures</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/union_types_v2">Union types</a> (PHP 8.0)</li>
<li>
<a href="/blog/shorthand-comparisons-in-php#null-coalescing-operator">Null coalescing operator</a>
</li>
<li>
<a target="_blank" href="https://www.php.net/manual/en/language.oop5.traits.php">Traits</a>
</li>
<li>
<a href="/blog/new-in-php-74#typed-properties-rfc">Typed properties</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/argument_unpacking">Spread operator</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/jit">JIT compiler</a> (PHP 8.0)</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/ffi">FFI</a>
</li>
<li>
<a target="_blank" href="https://www.php.net/manual/en/language.oop5.anonymous.php">Anonymous classes</a>
</li>
<li>
<a target="_blank" href="https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration">Return type declarations</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/libsodium">Contemporary cryptography</a>
</li>
<li>
<a target="_blank" href="https://wiki.php.net/rfc/generators">Generators</a>
</li>
<li>
<a href="/blog/new-in-php-74">Lots more</a>
</li>
</ul>
<p>While we're on the topic of language features, let's also talk about the process of how the language is developed today.
There's an active core team of volunteers who move the language forward,
though the community is allowed to propose RFCs.</p>
<p>Next, these RFCs are discussed on the "internals" mailing list, which can also be <a target="_blank" href="https://externals.io/">read online</a>.
Before a new language feature is added, there must be a vote.
Only RFC with at least a 2/3 majority are allowed in the core.</p>
<p>Recently there has been an effort to move RFC discussions to GitHub, where the code actually lives. It seems like the small group of developers who's actively invested in PHP, are on board. You can read about the process <a target="_blank" href="https://externals.io/message/107747">here</a>.
It's still a work in progress because some people don't like GitHub. It's clear though that the most active contributors are on board with the decision, so it's fair to say the RFC discussion process will be moved to GitHub entirely within the next year or so.</p>
<p>Once an RFC is discussed, it goes into the voting phase. There are probably around 100 people allowed to vote, though you're not required to vote on each RFC.
Members of the core team are of course allowed to vote, they have to maintain the code base.
Besides them, there's a group of people who have been individually picked from the PHP community.
These people include maintainers of the PHP docs, contributors to the PHP project as a whole,
and prominent developers in the PHP community.</p>
<p>While most of core development is done on a voluntary basis, one of the core PHP developers,
Nikita Popov, has recently been <a target="_blank" href="https://blog.jetbrains.com/phpstorm/2019/01/nikita-popov-joins-phpstorm-team/">employed by JetBrains</a>
to work on the language full time.
Another example is the Linux foundation who recently decided to <a target="_blank" href="https://getlaminas.org/">invest into Zend framework</a>, now called Laminas.
Employments and acquisitions like these ensure stability for the future development of PHP.</p>
<h2 id="tooling"><a href="#tooling" class="heading-anchor">#</a> Tooling</h2>
<p>Besides lots of features and improvements added to PHP's core, we've seen an increase in tools around it the past few years.
What comes to mind are static analysers like <a target="_blank" href="https://github.com/vimeo/psalm">Psalm</a>, created by Vimeo;
<a target="_blank" href="https://github.com/phan/phan">Phan</a> and <a target="_blank" href="https://github.com/phpstan/phpstan">PHPStan</a>.</p>
<p>These tools will statically analyse your PHP code and report any type errors,
possible bugs etc.
In some way, the functionality they provide can be compared to TypeScript,
though for now the language isn't transpiled, so no custom syntax is allowed.</p>
<p>Even though that means we need to rely on docblocks, Rasmus Lerdorf, the original creator of PHP,
did mention the idea of <a target="_blank" href="https://externals.io/message/101477#101592">adding a static analysis engine</a> to the core.
While there would be lots of potential, it is a huge undertaking.</p>
<p>Speaking of transpiling, and inspired by the JavaScript community;
there have been efforts to extend PHPs syntax in user land.
A project called <a target="_blank" href="https://web.archive.org/web/20190828000023/https://preprocess.io/#/">Pre</a> does exactly that:
allow new PHP syntax which is transpiled to normal PHP code.
While the idea has proven itself in the JavaScript world,
it could only work in PHP if proper IDE- and static analysis support was provided.
It's a very interesting idea, but has to grow before being able to call it "mainstream".</p>
<h2 id="in-closing"><a href="#in-closing" class="heading-anchor">#</a> In closing</h2>
<p>All of that being said, feel free to still think of PHP as a crappy language.
While the language definitely has its drawbacks and 20 years of legacy to carry with it;
I can say in confidence that I enjoy working with it.</p>
<p>In my experience, I'm able to create reliable, maintainable and quality software.
The clients I work for are happy with the end result, as am I.
While it's still possible to do lots of messed up things with PHP,
I'd say it's a great choice for web development if used wise and correct.</p>
<p>Don't you agree? Let me know why!
You can reach me via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2019-05-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ SOLID, interfaces and final - Rant With Brent 01 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/solid-interfaces-and-final-rant-with-brent"/>

                <id>https://www.stitcher.io/blog/solid-interfaces-and-final-rant-with-brent</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm giving podcasting a try. Let me know what you think of it via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
<p>In this episode I talk about why I think final helps you write better maintainable code.</p>
<p><audio
controls
src="http://feeds.soundcloud.com/stream/617976093-brent-roose-826312539-01-solid-interfaces-and-final-rant-with-brent.mp3">
</audio></p>
<p>You can download the episode <a target="_blank" href="http://feeds.soundcloud.com/stream/617976093-brent-roose-826312539-01-solid-interfaces-and-final-rant-with-brent.mp3">here</a>
or listen in <a target="_blank" href="https://podcasts.apple.com/be/podcast/rant-with-brent/id1462956030">iTunes</a>, <a target="_blank" href="https://www.stitcher.com/s?fid=403581&amp;refid=stpr.">Stitcher</a> and <a target="_blank" href="https://open.spotify.com/show/43sF0kY3BWepaO9CkLvVdJ?si=R-MIXaMHQbegQyq3gQm7Yw">Spotify</a></p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
 ]]></summary>

                <updated>2019-05-07T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ I&#039;m starting a newsletter ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/starting-a-newsletter"/>

                <id>https://www.stitcher.io/blog/starting-a-newsletter</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I'm going to give it a try: newsletters.
I'm always on the lookout for connecting more with my audience,
and feel like newsletters are a more personalised way of communication:
people can hit reply to engage in a one-on-one conversation.
For me, email is the perfect platform to do that.</p>
<h2 id="the-concept"><a href="#the-concept" class="heading-anchor">#</a> The concept</h2>
<p>What to expect if you subscribe?
First of all I'll try to send out one newsletter every month, more or less.
I won't spam you every day or week.
This also gives me ample time to write, review and rewrite the mail.
That's the same way I write my blog posts, and works very well for me.</p>
<p>My goal is to write a mini-blog post for every mail,
about a topic I've encountered the past month.
Next I'll also give some useful php-related tips and tricks.
Finally I'll share one or two, maybe three; links to interesting reads on the web.</p>
<p>That's what I envision the newsletter to look like, at least for now.</p>
<p>So, if you're interested, here's the signup link: <a href="https://stitcher.io/signup">https://stitcher.io/signup</a>.
The first edition will be sent sometime in the next two weeks.</p>
 ]]></summary>

                <updated>2019-04-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Unsafe SQL functions in Laravel ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/unsafe-sql-functions-in-laravel"/>

                <id>https://www.stitcher.io/blog/unsafe-sql-functions-in-laravel</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I recently learned that not all query builder functionality in Laravel is "safe".
This means that user input shouldn't be passed directly to it,
as it might expose your application to SQL injection vulnerabilities.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>The past few days it became clear that there is little community knowledge about these unsafe functions.
Many developers assume, as did I, that the Laravel query builder completely prevents SQL injection attacks.</p>
<p>This blog post aims to raise awareness about what's safe, and what's not.</p>
<h2 id="an-sql-injection-vulnerability?"><a href="#an-sql-injection-vulnerability?" class="heading-anchor">#</a> An SQL injection vulnerability?</h2>
<p>Let's start by mentioning that this vulnerability has been fixed as of <a target="_blank" href="https://github.com/laravel/framework/commits/v5.8.11">Laravel 5.8.11</a>.
While technically we could call this a "vulnerability",
Laravel developers should know that they also play a role in preventing these kinds of issues.</p>
<p>Let's examine the issue.</p>
<p>Laravel has the ability to manually specify which columns to select on a query.
It also offers the shorthand notation to query JSON data:</p>
<pre>Blog::query()
    -&gt;addSelect('title-&gt;en');
</pre>
<pre>SELECT json_extract(`title`, '$.&quot;en&quot;') FROM blogs;
</pre>
<p>Instead of manually writing <code>json_extract</code>, we can use the simplified <code>-&gt;</code> syntax,
which Laravel will convert to the correct SQL statement.</p>
<p>Be careful though: Laravel won't do any escaping during this conversion.
Consider the following example:</p>
<pre>Blog::query()
    -&gt;addSelect('title-&gt;en'#');
</pre>
<p>By inserting <code>'#</code> in our input, we can manually close the <code>json_extract</code> function,
and ignore the rest of the query:</p>
<pre>SELECT json_extract(`title`, '$.&quot;en'#&quot;') FROM blogs;
</pre>
<p>This query will fail because of syntax errors, but what about the next one?</p>
<pre>SELECT json_extract(
    `title`, 
    '$.&quot;en&quot;')) 
FROM blogs RIGHT OUTER JOIN users ON users.id &lt;&gt; null
#
    &quot;') FROM blogs;
</pre>
<p>We're adding an outer join on the <code>users</code> table.
Essentially selecting all data in it.</p>
<p>For reference, this is the URL encoded version of the malicious code:</p>
<pre>%22%27%29%29+FROM+blogs+RIGHT+OUTER+JOIN+users+ON+users.id+%3C%3E+null%23
</pre>
<p>Say we have the following endpoint in our application, to query blog posts from a public API:</p>
<pre><span class="hl-type">Route</span>::<span class="hl-property">get</span>('<span class="hl-value">/posts</span>', <span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">Request</span> $request</span>) {
    <span class="hl-variable">$fields</span> = <span class="hl-variable">$request</span>-&gt;<span class="hl-property">get</span>('<span class="hl-value">fields</span>', []);

    <span class="hl-variable">$users</span> = <span class="hl-type">Blog</span>::<span class="hl-property">query</span>()-&gt;<span class="hl-property">addSelect</span>(<span class="hl-variable">$fields</span>)-&gt;<span class="hl-property">get</span>();

    <span class="hl-keyword">return</span> <span class="hl-property">response</span>()-&gt;<span class="hl-property">json</span>(<span class="hl-variable">$users</span>);
});
</pre>
<p>Consumers of this API might only be interested in a few fields,
that's why we added a <code>fields</code> filter.
Something similar to <a target="_blank" href="https://jsonapi.org/format/#fetching-sparse-fieldsets">sparse fieldsets</a> from the JSON api spec.</p>
<p>The endpoint can now be used like this:</p>
<pre>/blog?fields[]=url&amp;fields[]=title
</pre>
<p>Now we insert our malicious code instead:</p>
<pre>/blog?fields[]=%22%27%29%29+FROM+blogs+RIGHT+OUTER+JOIN+users+ON+users.id+%3C%3E+null%23
</pre>
<p>It will be added to the query. And by returning the query result as JSON,
we'll see the full contents of the users table.</p>
<pre><span class="hl-type">Blog</span>::<span class="hl-property">query</span>()-&gt;<span class="hl-property">addSelect</span>([
    '<span class="hl-value">%22%27%29%29+FROM+blogs+RIGHT+OUTER+JOIN+users+ON+users.id+%3C%3E+null%23</span>'
])-&gt;<span class="hl-property">get</span>();
</pre>
<p>Two things need to be in place for this attack to be possible:</p>
<ul>
<li>An accessible API endpoint, which allows an attacker to pass his malicious code to <code>select</code> or <code>addSelect</code>.
Chances are you're not doing this manually in your project.
Though there are popular packages which provide this functionality for easy API endpoints and URL filtering.</li>
<li>The entry point table must have a column with JSON data.
Otherwise the <code>json_extract</code> function will fail, stopping our query.
From the entry point though, you can access all data.</li>
</ul>
<h2 id="prevention?"><a href="#prevention?" class="heading-anchor">#</a> Prevention?</h2>
<p>As mentioned before, this particular vulnerability has been fixed as of <a target="_blank" href="https://github.com/laravel/framework/commits/v5.8.11">Laravel 5.8.11</a>.
It's always good to keep up to date with the latest Laravel version.</p>
<p>More importantly though, developers should never allow user input directly to specify columns, without a whitelist.
In our previous example, you could prevent this attack by only allowing certain fields to be requested,
this would prevent the issue completely.</p>
<p>Next, one of our widely-used packages, <code>spatie/laravel-querybuilder</code>,
opened up <code>addSelect</code> by design.
This meant that websites using our package, were vulnerable to the underlying issue.
We immediately fixed it and Freek <a target="_blank" href="https://murze.be/an-important-security-release-for-laravel-query-builder">wrote about it</a> in depth.
If you're using our package and unable to update to the latest Laravel version,
you should immediately update the package.</p>
<p>Finally, the <a target="_blank" href="https://laravel.com/docs/5.8/queries">Laravel docs</a> have also been updated
to warn developers not to pass user input directly to columns when using the query builder.</p>
 ]]></summary>

                <updated>2019-04-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Array destructuring in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/array-destructuring-with-list-in-php"/>

                <id>https://www.stitcher.io/blog/array-destructuring-with-list-in-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <h2 id="list-or-[]"><a href="#list-or-[]" class="heading-anchor">#</a> List or []</h2>
<p>In PHP, <code>list</code> or <code>[]</code> is a so called "language construct", just like <code>array()</code>.
This language construct is used to "pull" variables out of an array.
In other words: it will "destructure" the array into separate variables.</p>
<p>Note that the word is "destructure", not "destruction" — that's something different 😉</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Here's what that looks like:</p>
<pre><span class="hl-variable">$array</span> = [1, 2, 3]; 

<span class="hl-comment">// Using the list syntax:</span>
<span class="hl-keyword">list</span>(<span class="hl-variable">$a</span>, <span class="hl-variable">$b</span>, <span class="hl-variable">$c</span>) = <span class="hl-variable">$array</span>;

<span class="hl-comment">// Or the shorthand syntax:</span>
[<span class="hl-variable">$a</span>, <span class="hl-variable">$b</span>, <span class="hl-variable">$c</span>] = <span class="hl-variable">$array</span>;

<span class="hl-comment">// $a = 1</span>
<span class="hl-comment">// $b = 2</span>
<span class="hl-comment">// $c = 3</span>
</pre>
<p>Whether you prefer <code>list</code> or its shorthand <code>[]</code> is up to you.
People might argue that <code>[]</code> is ambiguous with the shorthand array syntax,
and therefor prefer <code>list</code>.
I'll be using the shorthand version in code samples though.</p>
<p>So what more can <code>list</code> do?</p>
<h2 id="skip-elements"><a href="#skip-elements" class="heading-anchor">#</a> Skip elements</h2>
<p>Say you only need the third element of an array,
the first two can be skipped by simply not providing a variable.</p>
<pre>[, , <span class="hl-variable">$c</span>] = <span class="hl-variable">$array</span>;

<span class="hl-comment">// $c = 3</span>
</pre>
<p>Also note that <code>list</code> will always start at index 0.
Take for example the following array:</p>
<pre><span class="hl-variable">$array</span> = [
    1 =&gt; '<span class="hl-value">a</span>',
    2 =&gt; '<span class="hl-value">b</span>',
    3 =&gt; '<span class="hl-value">c</span>',
];
</pre>
<p>The first variable pulled out with <code>list</code> would be <code>null</code>,
because there's no element with index <code>0</code>.
This might seem like a shortcoming, but luckily there are more possibilities.</p>
<h2 id="non-numerical-keys"><a href="#non-numerical-keys" class="heading-anchor">#</a> Non-numerical keys</h2>
<p>PHP 7.1 allows <code>list</code> to be used with arrays that have non-numerical keys.
This opens a world of possibilities.</p>
<pre><span class="hl-variable">$array</span> = [
    '<span class="hl-value">a</span>' =&gt; 1,
    '<span class="hl-value">b</span>' =&gt; 2,
    '<span class="hl-value">c</span>' =&gt; 3,
];
</pre>
<pre>['<span class="hl-value">c</span>' =&gt; <span class="hl-variable">$c</span>, '<span class="hl-value">a</span>' =&gt; <span class="hl-variable">$a</span>] = <span class="hl-variable">$array</span>;
</pre>
<p>As you can see, you can change the order however you want, and also skip elements entirely.</p>
<h2 id="in-practice"><a href="#in-practice" class="heading-anchor">#</a> In practice</h2>
<p>One of the uses of <code>list</code> are functions like <code>parse_url</code> and <code>pathinfo</code>.
Because these functions return an array with named parameters,
we can use <code>list</code> to pull out the information we'd like:</p>
<pre>[
    '<span class="hl-value">basename</span>' =&gt; <span class="hl-variable">$file</span>,
    '<span class="hl-value">dirname</span>' =&gt; <span class="hl-variable">$directory</span>,
] = <span class="hl-property">pathinfo</span>('<span class="hl-value">/users/test/file.png</span>');
</pre>
<p>As you can see, the variables don't need the same name as the key.
Also note that destructuring an array with an unknown key will trigger a notice:</p>
<pre>[
    '<span class="hl-value">path</span>' =&gt; <span class="hl-variable">$path</span>, 
    '<span class="hl-value">query</span>' =&gt; <span class="hl-variable">$query</span>,
] = <span class="hl-property">parse_url</span>('<span class="hl-value">https://stitcher.io/blog</span>');

<span class="hl-comment">// PHP Notice:  Undefined index: query</span>
</pre>
<p>In this case, <code>$query</code> would be <code>null</code>.</p>
<p>One last detail: trailing commas are allowed with named destructs,
just like you're used to with arrays.</p>
<h2 id="in-loops"><a href="#in-loops" class="heading-anchor">#</a> In loops</h2>
<p>You can also use the list construct in loops:</p>
<pre><span class="hl-variable">$array</span> = [
    [
        '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">a</span>',
        '<span class="hl-value">id</span>' =&gt; 1
    ],
    [
        '<span class="hl-value">name</span>' =&gt; '<span class="hl-value">b</span>',
        '<span class="hl-value">id</span>' =&gt; 2
    ],
];

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$array</span> <span class="hl-keyword">as</span> ['<span class="hl-value">id</span>' =&gt; <span class="hl-variable">$id</span>, '<span class="hl-value">name</span>' =&gt; <span class="hl-variable">$name</span>]) {
    <span class="hl-comment">// …</span>
}
</pre>
<p>This could be useful when parsing for example a JSON or CSV file.
Be careful though that undefined keys will still trigger a notice.</p>
<p>In summary, there are some pretty good cases in which <code>list</code> can be of help!</p>
 ]]></summary>

                <updated>2019-04-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Upgrade to PHP 7.3 with Homebrew on Mac ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-73-upgrade-mac"/>

                <id>https://www.stitcher.io/blog/php-73-upgrade-mac</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="upgrading-with-homebrew"><a href="#upgrading-with-homebrew" class="heading-anchor">#</a> Upgrading with Homebrew</h2>
<p>Start by making sure brew is up-to-date:</p>
<pre>brew update
</pre>
<p>Next, upgrade PHP:</p>
<pre>brew upgrade php
</pre>
<p>Check the current version by running <code>php -v</code>:</p>
<pre>php -v

# PHP 7.3.3 (cli) (built: Mar  8 2019 16:42:07) ( NTS )
# Copyright (c) 1997-2018 The PHP Group
# Zend Engine v3.3.3, Copyright (c) 1998-2018 Zend Technologies
#     with Zend OPcache v7.3.3, Copyright (c) 1999-2018, by Zend Technologies
</pre>
<p>Restart Nginx or Apache:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<p>And make sure that your local web server also uses PHP 7.3 by visiting this script:</p>
<pre># index.php, accessible to your web server

<span class="hl-property">phpinfo</span>(); <span class="hl-keyword">die</span>();
</pre>
<p>The version should show <code>7.3.x</code>.</p>
<p>Note: if you're using Laravel Valet, please keep on reading,
you need some extra steps in order for the web server to properly work.</p>
<h2 id="jit-compilation-failed-error"><a href="#jit-compilation-failed-error" class="heading-anchor">#</a> <code>JIT compilation failed</code> error</h2>
<p>You might notice this error showing up when running PHP scripts, for example: <code>composer global update</code>.</p>
<pre>PHP Warning: preg_match(): JIT compilation failed
</pre>
<p>This is due to a <a target="_blank" href="https://bugs.php.net/bug.php?id=77260">PHP 7.3 bug</a>,
and can easily be solved by making a change in your PHP ini file.</p>
<p>If you don't know which ini file is used, you can run the following:</p>
<pre>php --ini

# Configuration File (php.ini) Path: /usr/local/etc/php/7.3
# Loaded Configuration File:         /usr/local/etc/php/7.3/php.ini
# Scan for additional .ini files in: /usr/local/etc/php/7.3/conf.d
# Additional .ini files parsed:      /usr/local/etc/php/7.3/conf.d/ext-opcache.ini,
# /usr/local/etc/php/7.3/conf.d/php-memory-limits.ini
</pre>
<p>Solving the above error can be done by manually disabling the <code>pcre.jit</code> option in our ini file.</p>
<pre># /usr/local/etc/php/7.3/php.ini

<span class="hl-deletion">-  ;pcre.jit=1</span>
<span class="hl-addition">+  pcre.jit=0</span>
</pre>
<h2 id="extensions"><a href="#extensions" class="heading-anchor">#</a> Extensions</h2>
<p>You may have heard of Homebrew dropping support for PHP extensions,
this should now be done with PECL.
I personally use Imagick, Redis and Xdebug.</p>
<p>They can be installed like so:</p>
<pre>pecl install imagick
pecl install redis
pecl install xdebug
</pre>
<p>You can run <code>pecl list</code> to see which extensions are installed:</p>
<pre>pecl list

# Installed packages, channel pecl.php.net:
# =========================================
# Package Version State
# imagick 3.4.3   stable
# redis   4.3.0   stable
# xdebug  2.7.0   stable
</pre>
<p>You can search for other extensions using <code>pecl search</code>:</p>
<pre>pecl search pdf

# Retrieving data...0%
# ..
# Matched packages, channel pecl.php.net:
# =======================================
# Package Stable/(Latest) Local
# pdflib  4.1.2 (stable)        Creating PDF on the fly with the PDFlib library
</pre>
<p>Make sure to restart your web server after installing new packages:</p>
<pre>sudo nginx -s reload
</pre>
<pre>sudo apachectl restart
</pre>
<h2 id="valet"><a href="#valet" class="heading-anchor">#</a> Valet</h2>
<p>If you're using Laravel Valet, you should do the following steps to upgrade it:</p>
<pre>composer global update
</pre>
<p>Now run <code>valet install</code>:</p>
<pre>valet install
</pre>
<p>Note that if you're upgrading Valet from 2.0 to 2.1, your Valet config folder will automatically be moved from
<code>~/.valet</code> to <code>~/.config/valet</code>.</p>
<p>If you have any paths pointing to this folder, you'll have to update them.
I, for example, have a custom Nginx config file for one of my local sites.
This config file contained absolute paths to the Valet socket.
These had to be manually changed.</p>
<p>If you're running into problems with Nginx, you can check out the errors in the logs:</p>
<pre>cat /usr/local/var/log/nginx/error.log
</pre>
<p>If any changes were made to your Valet config, you should restart it:</p>
<pre>valet restart
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="last-step"><a href="#last-step" class="heading-anchor">#</a> Last step</h2>
<p>Finally you should test and upgrade your projects for <a href="/blog/new-in-php-73">PHP 7.3 compatibility</a>.</p>
 ]]></summary>

                <updated>2019-03-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Queueable actions in Laravel ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/laravel-queueable-actions"/>

                <id>https://www.stitcher.io/blog/laravel-queueable-actions</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>People who follow my work or Spatie's, might have come across a pattern we use in some of our projects.
We call them "actions", and simply put they are classes to encapsulate business logic.</p>
<p>You can read up on how we structure projects by domains and actions <a href="/blog/organise-by-domain">here</a>,
and find examples of actions in the <a target="_blank" href="https://github.com/brendt/aggregate.stitcher.io/blob/master/app/Domain/Post/Actions/AddViewAction.php">code of my aggregate project</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's give one example using actions: creating a contract.
A contract creation not only saves a model in the database, but also generates a PDF of that contract.</p>
<p>Here's how we'd program this action:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreateContractAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">GeneratePdfAction</span> $generatePdfAction
    </span>) { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">execute</span>(<span class="hl-injection">
        <span class="hl-type">ContractData</span> $contractData
    </span>): <span class="hl-type">Contract</span> {
        <span class="hl-variable">$contract</span> = <span class="hl-type">Contract</span>::<span class="hl-property">createFromDTO</span>(<span class="hl-variable">$contractData</span>);
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">generatePdfAction</span>-&gt;<span class="hl-property">execute</span>(<span class="hl-variable">$contract</span>);
        
        <span class="hl-keyword">return</span> <span class="hl-variable">$contract</span>-&gt;<span class="hl-property">refresh</span>();
    }
}
</pre>
<p>If you know DDD, actions can be thought of as a command and its handler combined.
There are projects where this approach doesn't suffice, but there are also cases where they are very helpful.</p>
<p>We use this pattern a lot, because of the three benefits it offers:</p>
<ul>
<li>It's very easy to unit test individual action classes.</li>
<li>Actions can be composed out of other actions via the dependency container.</li>
<li>Actions allow us to think in well-defined context, they reduce cognitive load and decrease maintenance cost.</li>
</ul>
<p>One detail: there are some cases where we want actions to be executed asynchronously.</p>
<p>In the case of our example: we want to create the contract immediately,
but we don't want our users to wait until the PDF is generated.
This should be done asynchronously.</p>
<p>In the past, we used to wrap actions into jobs. It would look something like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">GeneratePdfJob</span> <span class="hl-keyword">implements</span><span class="hl-type"> ShouldQueue
</span>{
    <span class="hl-keyword">use</span> <span class="hl-type">Dispatchable</span>, 
        <span class="hl-type">InteractsWithQueue</span>, 
        <span class="hl-type">Queueable</span>, 
        <span class="hl-type">SerializesModels</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">Contract</span> $contract 
    </span>) { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">handle</span>(<span class="hl-injection">
        <span class="hl-type">GeneratePdfAction</span> $generatePdfAction
    </span>) {
        <span class="hl-variable">$generatePdfAction</span>
            -&gt;<span class="hl-property">execute</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">contract</span>);
    }
}
</pre>
<p>Instead of directly calling the action within another action, we dispatch a new job.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreateContractAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">execute</span>(<span class="hl-injection">
        <span class="hl-type">ContractData</span> $contractData
    </span>): <span class="hl-type">Contract</span> {
        <span class="hl-comment">// …</span>
        
        <span class="hl-property">dispatch</span>(<span class="hl-keyword">new</span> <span class="hl-type">GeneratePdfJob</span>(<span class="hl-variable">$contract</span>));
        
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>This works fine, but manually wrapping an action in a job started to be kind of tedious in our larger projects.</p>
<p>That's why we started looking into ways of automating this.
And sure thing: we can!</p>
<p>Here's what the <code>GeneratePdfAction</code> would look like, using our package:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Spatie\QueueableAction\QueueableAction</span>;

<span class="hl-keyword">class</span> <span class="hl-type">GeneratePdfAction</span>
{
    <span class="hl-keyword">use</span> <span class="hl-type">QueueableAction</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">Renderer</span> $renderer,
        <span class="hl-type">Browsershot</span> $browsershot
    </span>) { <span class="hl-comment">/* … */</span> }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">execute</span>(<span class="hl-injection"><span class="hl-type">Pdfable</span> $pdfable</span>): <span class="hl-type">void</span>
    {
        <span class="hl-variable">$html</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">renderer</span>-&gt;<span class="hl-property">render</span>(<span class="hl-variable">$pdfable</span>);
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">browsershot</span>
            -&gt;<span class="hl-property">html</span>(<span class="hl-variable">$html</span>)
            -&gt;<span class="hl-property">save</span>(<span class="hl-variable">$pdfable</span>-&gt;<span class="hl-property">getPath</span>());
    }
}
</pre>
<p>By using <code>QueueableAction</code>, this action can now be executed asynchronously.
Here's how it's used:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreateContractAction</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">execute</span>(<span class="hl-injection">
        <span class="hl-type">ContractData</span> $contractData
    </span>): <span class="hl-type">Contract</span> {
        <span class="hl-comment">// …</span>
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">generatePdfAction</span>
            -&gt;<span class="hl-property">onQueue</span>()
            -&gt;<span class="hl-property">execute</span>(<span class="hl-variable">$contract</span>);
            
        <span class="hl-comment">// …</span>
    }
}
</pre>
<p>It's important to note that the above will still have auto completion of the <code>execute</code> method,
as well as DI support; just like normal actions:</p>
<p><img src="/resources/img/blog/queueable/autocompletion.png" srcset="/resources/img/blog/queueable/autocompletion-1340x208.png 1340w, /resources/img/blog/queueable/autocompletion-1198x185.png 1198w, /resources/img/blog/queueable/autocompletion-1037x160.png 1037w, /resources/img/blog/queueable/autocompletion-599x92.png 599w, /resources/img/blog/queueable/autocompletion-847x131.png 847w" sizes="" alt=""></img></p>
<h2 id="what's-the-difference-with-jobs?!?"><a href="#what's-the-difference-with-jobs?!?" class="heading-anchor">#</a> What's the difference with Jobs?!?</h2>
<p>Actions allow for constructor injection, which means you can use actions within actions within actions, and so forth.</p>
<p>Jobs on the other hand get container injection in their <code>handle</code> method.
This means you cannot compose jobs of of other jobs via the dependency container.</p>
<p>It's obvious why Laravel cannot provide constructor injection in jobs:
job-specific data, like our contract, needs to be serialised on order for jobs to be queueable,
and the constructor is required to ensure the job has valid data.</p>
<p>By introducing the concept of actions, we're able to separate responsibilities between classes better:
jobs are used for data serialisation and executing tasks asynchronously;
but they are not concerned with business logic anymore.</p>
<p>If you're concerned with difficult to debug actions when they're queued,
you can put your mind at ease.
<code>ActionJob</code> classes that are dispatched to for example, Horizon,
have their name changed to the action class they wrap:</p>
<p><img src="/resources/img/blog/queueable/horizon.png" srcset="/resources/img/blog/queueable/horizon-1130x73.png 1130w, /resources/img/blog/queueable/horizon-1599x103.png 1599w, /resources/img/blog/queueable/horizon-1788x115.png 1788w, /resources/img/blog/queueable/horizon-799x51.png 799w, /resources/img/blog/queueable/horizon-1384x89.png 1384w" sizes="" alt=""></img></p>
<p>The underlying details of making actions queueable are hidden to the developer using them,
making it very easy to work with them, even in an asynchronous context.</p>
<p>Like I said: we made this into a small package.
It consists of a simple trait and an <code>ActionJob</code>.
If you want to give it a try, you can check it out here: <a target="_blank" href="https://github.com/spatie/laravel-queueable-action">spatie/laravel-queueable-action</a>.</p>
 ]]></summary>

                <updated>2019-03-11T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Craftsmen know their tools ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/craftsmen-know-their-tools"/>

                <id>https://www.stitcher.io/blog/craftsmen-know-their-tools</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>When programmers call themselves craftsmen or artisans,
I can agree that we are.
At the same time though, some of these programmers underestimate what craftsmanship actually means.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's make a comparison.</p>
<p>My younger brother is an apprentice wood worker,
here's a picture of his shop:</p>
<p><img src="/resources/img/blog/craftsmen/3.jpeg" srcset="/resources/img/blog/craftsmen/3-1600x900.jpeg 1600w, /resources/img/blog/craftsmen/3-1239x696.jpeg 1239w, /resources/img/blog/craftsmen/3-715x402.jpeg 715w, /resources/img/blog/craftsmen/3-1431x804.jpeg 1431w, /resources/img/blog/craftsmen/3-1011x568.jpeg 1011w" sizes="" alt=""></img></p>
<p>To me this looks like chaos,
but my brother manages to find his way around.
Even better: he actually makes pretty and useful things.</p>
<p>Granted, he is still an apprentice,
but I've been happily surprised by the things he has crafted up until now.
I can imagine his skills will improve only more and more over time.</p>
<p>For example, take a look at this display thingy he made:</p>
<p><img src="/resources/img/blog/craftsmen/6.jpeg" srcset="/resources/img/blog/craftsmen/6-1000x1000.jpeg 1000w, /resources/img/blog/craftsmen/6-447x447.jpeg 447w, /resources/img/blog/craftsmen/6-774x774.jpeg 774w, /resources/img/blog/craftsmen/6-894x894.jpeg 894w, /resources/img/blog/craftsmen/6-632x632.jpeg 632w" sizes="" alt=""></img></p>
<p>Or this clock:</p>
<p><img src="/resources/img/blog/craftsmen/4.jpeg" srcset="/resources/img/blog/craftsmen/4-1000x563.jpeg 1000w, /resources/img/blog/craftsmen/4-632x355.jpeg 632w, /resources/img/blog/craftsmen/4-447x251.jpeg 447w, /resources/img/blog/craftsmen/4-894x503.jpeg 894w, /resources/img/blog/craftsmen/4-774x435.jpeg 774w" sizes="" alt=""></img></p>
<p>He also made me some nice sound absorbing panels for my podcast studio at home:</p>
<p><img src="/resources/img/blog/craftsmen/5.jpeg" srcset="/resources/img/blog/craftsmen/5-632x398.jpeg 632w, /resources/img/blog/craftsmen/5-894x564.jpeg 894w, /resources/img/blog/craftsmen/5-447x282.jpeg 447w, /resources/img/blog/craftsmen/5-1000x631.jpeg 1000w, /resources/img/blog/craftsmen/5-774x488.jpeg 774w" sizes="" alt=""></img></p>
<p>The same way my brother is crafting things with wood,
we are building websites and programs with code.
I wonder if we have mastered our toolset like he has.</p>
<p>See, he isn't building all this stuff with his bare hands.
He's using the right tools for the job.
Have a look at some of the machines he's working with:</p>
<p><img src="/resources/img/blog/craftsmen/2.jpeg" srcset="/resources/img/blog/craftsmen/2-447x251.jpeg 447w, /resources/img/blog/craftsmen/2-774x435.jpeg 774w, /resources/img/blog/craftsmen/2-632x355.jpeg 632w, /resources/img/blog/craftsmen/2-894x503.jpeg 894w, /resources/img/blog/craftsmen/2-1000x563.jpeg 1000w" sizes="" alt=""></img></p>
<p>Or this one:</p>
<p><img src="/resources/img/blog/craftsmen/1.jpeg" srcset="/resources/img/blog/craftsmen/1-1000x563.jpeg 1000w, /resources/img/blog/craftsmen/1-632x355.jpeg 632w, /resources/img/blog/craftsmen/1-774x435.jpeg 774w, /resources/img/blog/craftsmen/1-447x251.jpeg 447w, /resources/img/blog/craftsmen/1-894x503.jpeg 894w" sizes="" alt=""></img></p>
<p>I've got no clue what these monstrosities do
or how to use them — but my brother does.</p>
<p>He had to <em>learn</em> to work these tools.
Not only did he need to know which button does what;
he had learn how to apply specific techniques to these machines
in order to cut and saw the wood as he wants.</p>
<p>He has a mentor and spends a considerate amount of time learning and improving his tools and techniques.
It takes patience:
he couldn't just dive in at the beginning,
there is a learning curve to creating quality.</p>
<p>What is a programmer's equivalent?
As we call ourselves craftsmen and artisans,
can I assume we also know our tools inside and out?</p>
<p>Can I assume we dedicate time to properly learn how to work with those tools,
how to improve our skillset on a day-by-day basis?</p>
<p>Does it seem like a detail to us?
Do we think a simple saw gets us equally far as the big monster machine my brother is using?</p>
<p>Can I assume we know the value of our tools?
Do we realise they help us be efficient;
they simplify mundane tasks so that we can focus on core problems;
they are a safeguard when we tend to make stupid mistakes?</p>
<p>Are those fair assumptions when we call ourselves craftsmen?</p>
<p>All these questions pop into my head
when I hear people complain about how learning to use an IDE,
setting up your local environment, properly learning version control or learning a framework;
takes too much time.</p>
<p>What did you expect?
In order to write good code, maintainable code, code you can be proud of;
in order to do that, you need to master the right tools.</p>
<p>There are no shortcuts to this, you need to spend time learning.</p>
<p>I want to challenge you to think about how you use your tools.
There might be opportunities, areas you can improve on.
Be willing to spend time improving your skillset.</p>
<p>It's time well invested.</p>
<p>PS: if you're into wood working,
be sure to check out my brother's <a target="_blank" href="https://www.instagram.com/t_werkhuis/">Instagram</a>!</p>
 ]]></summary>

                <updated>2019-02-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP 8: The JIT ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-jit"/>

                <id>https://www.stitcher.io/blog/php-jit</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="sidenote">
    <p>Heads up! I've done some <a href="/blog/jit-in-real-life-web-applications">benchmarks on the JIT</a> in real-life web applications. Be sure to check them out.</p>
</div>
<p>Dmitry Stogov recently opened an <a target="_blank" href="https://wiki.php.net/rfc/jit">RFC</a> to add a JIT compiler to PHP.
So, what is that about? Does "JIT" mean "instantly better PHP",
or is this a more nuanced topic?
Today we'll briefly look at what the "JIT" actually does,
and more importantly: the difficulties <em>and</em> opportunities it brings to the PHP world.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="what-is-jit?"><a href="#what-is-jit?" class="heading-anchor">#</a> What is JIT?</h2>
<p>"JIT" stands for "just in time".
You probably know that PHP is an interpreted language:
it's not compiled like a C, Java or Rust program.
Instead it is translated to machine code — stuff the CPU understands — at runtime.</p>
<blockquote>
<p>"JIT" is a technique that will compile parts of the code at runtime,
so that the compiled version can be used instead.</p>
</blockquote>
<p>Think of it like a "cached version" of the interpreted code, generated at runtime.</p>
<p>How does that work, you ask?</p>
<p>There's a so called "monitor" that will look at the code as it's running.
When this monitor detects parts of your code that are re-executed,
it will mark those parts as "warm" or "hot", depending on the frequency.
These hot parts can be compiled as optimised machine code,
and used on the fly instead of the real code.</p>
<p>You can imagine there's a lot more complexity to this topic.
If you want to know a little more,
you can check out <a target="_blank" href="https://hacks.mozilla.org/2017/02/a-crash-course-in-just-in-time-jit-compilers/">Mozilla's crash course in JIT compilers</a>.
For the purpose of this blog post, it's enough to understand that a JIT compiler
may improve the performance of your program significantly,
<em>but</em> it's a difficult thing to get right.</p>
<p>Zeev, one of the PHP core developers, showed a demo with fractal generation a while back:</p>
<p>
    <iframe width="560" height="400" 
        src="https://www.youtube.com/embed/dWH65pmnsrI" 
        frameborder="0" 
        allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
        allowfullscreen>
    </iframe>
</p>
<p>Fancy, right? Hold on though…</p>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="it's-not-all-fun-and-games"><a href="#it's-not-all-fun-and-games" class="heading-anchor">#</a> It's not all fun and games</h2>
<p>Let's address the elephpant in the room:
PHP is seldom used to generate fractal animations.</p>
<p>Knowing that the JIT compiler tries to identify hot parts of your code,
you can guess why it has such an impact on the fractal example:
there's a lot of the same calculations happening over and over again.
However, since PHP is most often used in a web context,
we should also measure the JIT's impact there.</p>
<p>It turns out that, unfortunately, there's a <a href="/blog/jit-in-real-life-web-applications">lot less hot code while handling a web request</a>.
This doesn't mean the JIT couldn't improve web performance at all,
but we also won't see similar improvements like with the fractal example.</p>
<p>Is this a reason to ditch the JIT? Definitely not!
There are good arguments to add it,
even though it might not have the performance impact we'd hope for.</p>
<ul>
<li>It opens the door for PHP to be used as a very performant language outside of the web.</li>
<li>The JIT can be improved upon over time, as well could our code.</li>
</ul>
<p>These are valid arguments in favour of the JIT.
Unfortunately though, there are also more arguments against it.</p>
<h2 id="a-complexity-to-maintain"><a href="#a-complexity-to-maintain" class="heading-anchor">#</a> A complexity to maintain</h2>
<p>Because the JIT generates machine code,
you can imagine it's complex material for a "higher level programmer" to understand.</p>
<p>For example: having machine code as output, it will be harder to debug possible bugs in PHP's JIT compiler.
Luckily there are tools to help debugging.
But still, it <em>is</em> machine code.
Say there is a bug in the JIT compiler, you need a developer who knows how to fix it.
Dmitry is the one who did most of the coding up until now,
and remember that PHP core development is done on a voluntary basis.</p>
<p>With just a few people being able to maintain such a code base today,
the question whether the JIT compiler can be maintained properly seems justified.
Of course people can learn how the compiler works.
But it is complex material nevertheless.
The <a target="_blank" href="https://github.com/php/php-src/pull/3792">pull request right now</a> counts around 50k lines of added code.
And mind you: this is not your average client-web-application-codebase.
This is almost-as-close-as-you-can-get-to-the-CPU-programming.</p>
<p>Again this should not be a reason to ditch the JIT,
but the cost of maintenance should be carefully considered.
In first place by the ones who have to maintain the code;
but also by the userland community, who should also be aware that some bugfixes or version updates might take longer than what we're used to right now.</p>
<div class="sidenote">
    <h2>Cross platform?</h2>
    <p>
        As of newer versions of the JIT, it now also works Windows and Mac!
        A big step forward, and definitely worth mentioning.
    </p>
</div>
<h2 id="so-why-would-you-want-it?"><a href="#so-why-would-you-want-it?" class="heading-anchor">#</a> So why would you want it?</h2>
<p>If right now you're thinking that the JIT offers little short-term benefits for your web applications,
you might be right.
It's difficult to tell what impact it will have on production applications, before actually using it.</p>
<p>The JIT RFC proposed to enable it in PHP 8, but also to add an experimental version in PHP 7.4.
Unfortunately the <a target="_blank" href="https://wiki.php.net/rfc/jit#proposed_voting_choices">RFC</a> has passed for PHP 8, but not for 7.4.
This means we'll have to wait until PHP 8 before being able to try it out on real projects.
You can of course compile PHP 8 from source, if you already want to take a look.</p>
<p>Even though the JIT might not offer any significant short-term improvements,
we should remember that it will open a lot of possibilities for PHP to grow,
both as a web language and a more generally purposed language.
So the question that needs answering: is this possibly bright future worth the investment today?</p>
<p>What do you, the userland programmer think?
Let's discuss it on <a target="_blank" href="https://news.ycombinator.com/item?id=22953879">Hacker News</a>.
If you want to personally reach out, you can find me on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>!</p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
 ]]></summary>

                <updated>2019-02-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ I&#039;m building something ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/announcing-aggregate"/>

                <id>https://www.stitcher.io/blog/announcing-aggregate</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Being a blogger myself, I realise how much
quality content is written on the internet every day;
content that gets lost in an endless stream of online information.</p>
<p>I know how much you want to be able to share your content with an audience,
but it's so difficult to do.
Twitter is very momentarily; Reddit suffers from spam and angry people;
and Facebook is, well, Facebook.</p>
<p>I want a platform where I don't have to feel guilty about sharing my content,
and where readers can easily discover new things to read.</p>
<p>So I took one of the oldest blogging concepts and made a community driven platform out of it: RSS.</p>
<h2 id="community-driven?"><a href="#community-driven?" class="heading-anchor">#</a> Community driven?</h2>
<p>I realise that starting a project on my own, won't get me far.
We live in a day and age where every possible app has been invented at least twice.
Trying to do this myself won't get me far.</p>
<p>That's why I decided on two things.</p>
<p>The code is <strong>open source</strong>. I want to encourage people to contribute,
help build the platform they want it to be.</p>
<p>The <strong>content</strong> is provided by the community, and the platform will always redirect to the source of origin.
It will never try to host your content, it's merely a portal.</p>
<h2 id="how-does-it-work?"><a href="#how-does-it-work?" class="heading-anchor">#</a> How does it work?</h2>
<p>Content creators can add their RSS feed to the platform.
Their posts are synced and tagged according to the content and RSS meta data.</p>
<p>Readers can explore new content daily in their feed.
I've decided to not try and do anything fancy while building this feed.
Platforms like Facebook and Twitter try to be smart and build a feed based on "your interests".
They never succeed.</p>
<p>So the feed is a simple chronological list, which you can filter on tags.
That's it. There are no votes, no comments.
You're encouraged to go the blogs themselves, and share your thoughts over there.</p>
<p>The goal of the platform is simple: help readers discover new content,
and get them to that original content as fast as possible.
Meanwhile, content creators get a platform where they are allowed to share their own stuff,
and an audience hungry for more.</p>
<h2 id="get-in-touch"><a href="#get-in-touch" class="heading-anchor">#</a> Get in touch</h2>
<p>Even though the basic concept is stable and up and running, there's still lots of things to do.
There's improvements to be made to the tagging system,
there are some convenience features that need to be added and more.</p>
<p>If you're a web programmer yourself who's interested in open source,
feel free to take a look around the <a target="_blank" href="https://github.com/brendt/aggregate.stitcher.io/projects/1">project board</a>.</p>
<p>Oh and, of course, here's a link to the platform: <a target="_blank" href="https://aggregate.stitcher.io/">aggregate.stitcher.io</a>.</p>
 ]]></summary>

                <updated>2019-01-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Analytics for developers ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/analytics-for-developers"/>

                <id>https://www.stitcher.io/blog/analytics-for-developers</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been running this blog for almost three years now.
I've used Google Analytics, not only to track the amount of users,
but also to actively improve my blog.</p>
<p>I'm no marketeer, just a simple developer.
Today I want to share from my technical experience, how I use traffic data and react to it.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="filtering-data"><a href="#filtering-data" class="heading-anchor">#</a> Filtering data</h2>
<p>First and foremost, the boring part.
It takes less than five minutes to set up, but will improve the correctness of your data: filters.</p>
<p>As you know, Google Analytics works with a tracking code which you can place everywhere.
That tracking code can easily be used somewhere else, polluting your data.
I'm thinking of local development environments or, more malicious:
people who steal your tracking code as a deliberate attack.</p>
<p>Luckily this can easily be prevented with filters.
So take five minutes to set up some filters in the admin section:</p>
<p><img src="/resources/img/blog/analytics/filter-1.png" srcset="/resources/img/blog/analytics/filter-1-754x459.png 754w, /resources/img/blog/analytics/filter-1-1066x649.png 1066w, /resources/img/blog/analytics/filter-1-1686x1028.png 1686w, /resources/img/blog/analytics/filter-1-1305x795.png 1305w, /resources/img/blog/analytics/filter-1-1508x919.png 1508w" sizes="" alt=""></img></p>
<p>With filters, you can build a whitelist of traffic you want to include.
I usually make a separate view called "Filtered", and keep the "All Web Site Data" view as is, for testing.</p>
<p>Here's an example of a filter I set up, to only include traffic from the "stitcher.io" domain:</p>
<p><img src="/resources/img/blog/analytics/filter-2.png" srcset="/resources/img/blog/analytics/filter-2-1066x693.png 1066w, /resources/img/blog/analytics/filter-2-1192x775.png 1192w, /resources/img/blog/analytics/filter-2-753x490.png 753w, /resources/img/blog/analytics/filter-2-533x346.png 533w, /resources/img/blog/analytics/filter-2-923x600.png 923w" sizes="" alt=""></img></p>
<p>You can also filter out local domains, whitelist IP addresses and more.
If you want to be really safe, you could whitelist the IP address of your host,
in combination with the host name.</p>
<p>With the correct filters set up, it's time to interpret data.</p>
<h2 id="decreasing-bounce-rate"><a href="#decreasing-bounce-rate" class="heading-anchor">#</a> Decreasing bounce rate</h2>
<p>Here's a good question to start with: "should I want to decrease my bounce rate"?
The corporate marketeer will of course scream "YES".</p>
<p>I say: it depends. Take for example this blog, or almost any other blog.
When I share a post on social media, most visitors come to read that post, and that post only.</p>
<p>It's not that weird when you think about it: don't we all do the same when browsing?</p>
<p>A high bounce rate means that not a lot of visitors click through after their first page visit.
In case of a blog, there's nothing wrong with that:
many of these people will return the next time you share a link on social media.</p>
<p>Let's take a look at the traffic in November of 2018, on this blog.</p>
<p><img src="/resources/img/blog/analytics/bounce-rate-1.png" srcset="/resources/img/blog/analytics/bounce-rate-1-1685x873.png 1685w, /resources/img/blog/analytics/bounce-rate-1-1946x1008.png 1946w, /resources/img/blog/analytics/bounce-rate-1-1376x713.png 1376w, /resources/img/blog/analytics/bounce-rate-1-973x504.png 973w, /resources/img/blog/analytics/bounce-rate-1-2176x1128.png 2176w" sizes="" alt=""></img></p>
<p>That's a rather high bounce rate.
Though over the last year, I see a consistent 20-ish percent of returning visitors.
These people also add to the bounce rate,
though they are the ones who visit this site over and over again, albeit only one page at a time.</p>
<p><img src="/resources/img/blog/analytics/bounce-rate-2.png" srcset="/resources/img/blog/analytics/bounce-rate-2-536x514.png 536w, /resources/img/blog/analytics/bounce-rate-2-464x445.png 464w, /resources/img/blog/analytics/bounce-rate-2-268x257.png 268w, /resources/img/blog/analytics/bounce-rate-2-600x576.png 600w, /resources/img/blog/analytics/bounce-rate-2-379x363.png 379w" sizes="" alt=""></img></p>
<p>You can see how relative this data is,
and how you cannot simply say "decrease the bounce rate".</p>
<p>But what can we learn from it though?</p>
<p>If you're a regular reader of my blog, first of all: thanks, you're in the 20% !
Secondly: you know that I place an "up next" link down at the bottom of each post.</p>
<p>In the past, these links were automatically generated and just showed the post before the current one.</p>
<p>When analysing the bounce rate of individual pages though,
I noticed that some pages had a way lower bounce rate than others.</p>
<p>Looking at these low bounce pages,
they were the pages where I deliberately put another link at the bottom,
one to a post of which I thought was a little related to the current one.</p>
<p>So how do you analyse this?</p>
<p>The "Content Drilldown" page is great to analyse per-page statistics.
You can find it under <code>Behavior &gt; Site Content</code>.</p>
<p><img src="/resources/img/blog/analytics/bounce-rate-3.png" srcset="/resources/img/blog/analytics/bounce-rate-3-1574x721.png 1574w, /resources/img/blog/analytics/bounce-rate-3-1928x884.png 1928w, /resources/img/blog/analytics/bounce-rate-3-2490x1142.png 2490w, /resources/img/blog/analytics/bounce-rate-3-1113x510.png 1113w, /resources/img/blog/analytics/bounce-rate-3-2227x1021.png 2227w" sizes="" alt=""></img></p>
<p>Also note how the "advanced filter" is applied to only show pages with lower bounce rates.
We can use this data to learn what we're doing right,
and target pages that might need optimisation.</p>
<h2 id="top-referrals"><a href="#top-referrals" class="heading-anchor">#</a> Top referrals</h2>
<p>I know most of my traffic comes from links that are shared.
I've got some posts that show up high in Google, but more about that later.</p>
<p>The "Referrals" page under <code>Acquisition &gt; All Traffic</code> is an important one to know where your traffic is coming from.</p>
<p><img src="/resources/img/blog/analytics/referrals-1.png" srcset="/resources/img/blog/analytics/referrals-1-2420x971.png 2420w, /resources/img/blog/analytics/referrals-1-1530x614.png 1530w, /resources/img/blog/analytics/referrals-1-2164x869.png 2164w, /resources/img/blog/analytics/referrals-1-1874x752.png 1874w, /resources/img/blog/analytics/referrals-1-1082x434.png 1082w" sizes="" alt=""></img></p>
<p>You can see peaks in traffic during the day, by using the real time overview.
I often check the referrals at these moments, to know where traffic is coming from.</p>
<p>I believe that, as an author, it's important to engage with your readers.
When content is shared on social media, reactions often show up there;
so it's only natural that you reply to them there.</p>
<p>A quick Google search on the blog title and website of the referral,
often gets me to the right place in no time.</p>
<h2 id="average-session-duration"><a href="#average-session-duration" class="heading-anchor">#</a> Average session duration</h2>
<p>Now that we know people are visiting our blog,
we also want to know whether they are actually reading the content.</p>
<p>Again, the "Content Drilldown" page gets us this data.
By adding a simple regex filter <code>^\/[a-z\-]+$</code>, we filter out pages with query parameters.
We're also not interested in pages with very low pageviews.</p>
<p><img src="/resources/img/blog/analytics/session-duration-1.png" srcset="/resources/img/blog/analytics/session-duration-1-1409x860.png 1409w, /resources/img/blog/analytics/session-duration-1-1726x1054.png 1726w, /resources/img/blog/analytics/session-duration-1-2229x1362.png 2229w, /resources/img/blog/analytics/session-duration-1-1993x1217.png 1993w, /resources/img/blog/analytics/session-duration-1-996x608.png 996w" sizes="" alt=""></img></p>
<p>What we're actually interested in, are the pages with the lowest session duration,
to see whether some things can be improved.</p>
<p><img src="/resources/img/blog/analytics/session-duration-2.png" srcset="/resources/img/blog/analytics/session-duration-2-2230x1032.png 2230w, /resources/img/blog/analytics/session-duration-2-1727x799.png 1727w, /resources/img/blog/analytics/session-duration-2-997x461.png 997w, /resources/img/blog/analytics/session-duration-2-1994x922.png 1994w, /resources/img/blog/analytics/session-duration-2-1410x652.png 1410w" sizes="" alt=""></img></p>
<p>Some of these blog posts are very short ones, so nothing strange there.
Though it also shows what posts were less interesting to my audience.
It's a good metric to know what kind of content I shouldn't focus on.</p>
<h2 id="analysing-behaviour-flow"><a href="#analysing-behaviour-flow" class="heading-anchor">#</a> Analysing behaviour flow</h2>
<p>The "Behavior Flow" chart under the <code>Behavior</code> menu is one
that helps visualising how visitors browse your site.</p>
<p>This is what it looks like.</p>
<p><img src="/resources/img/blog/analytics/flow-1.png" srcset="/resources/img/blog/analytics/flow-1-1434x887.png 1434w, /resources/img/blog/analytics/flow-1-828x512.png 828w, /resources/img/blog/analytics/flow-1-1656x1024.png 1656w, /resources/img/blog/analytics/flow-1-1171x724.png 1171w, /resources/img/blog/analytics/flow-1-1852x1146.png 1852w" sizes="" alt=""></img></p>
<p>As with the bounce rate optimisations,
this overview can help identifying pages that encourage people to click through,
and pages that don't.</p>
<p>I use this overview in combination with the "Content Drilldown" page,
to analyse where people come from, where they go,
and whether I can improve my content to help them read what they are actually interested in.</p>
<h2 id="analysing-keywords-and-search"><a href="#analysing-keywords-and-search" class="heading-anchor">#</a> Analysing keywords and search</h2>
<p>I know that most of my traffic comes from links that are shared over the internet,
though I also want to know how much comes through search sites like Google.
These pages get a more constant amount of monthly visitors,
and might pose a good opportunity to introduce readers to my blog.</p>
<p>By going to <code>Acquisition &gt; All Traffic &gt; Channels</code>,
you can click through to the "Organic Search" channel.</p>
<p>By default, this overview shows what keywords were searched on,
which isn't very useful to us right now.
You'll also notice that most of the time, this keyword data is simply missing.</p>
<p>You can however specify a "Secondary Dimension", on the "Landing Page".
Now the overview will be grouped per page the visitor landed on,
which is exactly what we want to know!</p>
<p><img src="/resources/img/blog/analytics/channels-1.png" srcset="/resources/img/blog/analytics/channels-1-912x512.png 912w, /resources/img/blog/analytics/channels-1-1580x887.png 1580w, /resources/img/blog/analytics/channels-1-2041x1146.png 2041w, /resources/img/blog/analytics/channels-1-1290x724.png 1290w, /resources/img/blog/analytics/channels-1-1825x1024.png 1825w" sizes="" alt=""></img></p>
<p>Now we know what pages are good candidates to optimise,
but we still don't know what keywords people actually searched for.</p>
<p>If you link your Search Console to Analytics, you'll get the data you need.
On <code>Acquisition &gt; Search Console &gt; Queries</code>, you'll see an overview of these keywords.</p>
<p>Here's an example, for this past week in January, 2019:</p>
<p><img src="/resources/img/blog/analytics/channels-2.png" srcset="/resources/img/blog/analytics/channels-2-1837x867.png 1837w, /resources/img/blog/analytics/channels-2-2054x970.png 2054w, /resources/img/blog/analytics/channels-2-1299x613.png 1299w, /resources/img/blog/analytics/channels-2-918x433.png 918w, /resources/img/blog/analytics/channels-2-1591x751.png 1591w" sizes="" alt=""></img></p>
<h2 id="measuring-site-speed"><a href="#measuring-site-speed" class="heading-anchor">#</a> Measuring site speed</h2>
<p>Lastly, something I'm very proud of: my blog's performance.
When building this blog I really wanted it to be fast, everywhere.</p>
<p>Analytics also helps with that. Under <code>Behavior &gt; Site Speed &gt; Page Timings</code>,
you can monitor the performance of individual pages.
Take, for example, the most visited pages of November, 2018.</p>
<p><img src="/resources/img/blog/analytics/performance-1.png" srcset="/resources/img/blog/analytics/performance-1-2232x934.png 2232w, /resources/img/blog/analytics/performance-1-998x417.png 998w, /resources/img/blog/analytics/performance-1-1728x723.png 1728w, /resources/img/blog/analytics/performance-1-1411x590.png 1411w, /resources/img/blog/analytics/performance-1-1996x835.png 1996w" sizes="" alt=""></img></p>
<p>The red lines are the interesting ones: these pages load slower than the site's average.
This can be because of many reasons: lots of visitors with a bad connection to the host,
images that should be better optimised, maybe a problem with a script I wrote for a post?</p>
<p>This view allows me to find performance problems early on, and fix them.</p>
<h2 id="in-closing"><a href="#in-closing" class="heading-anchor">#</a> In closing</h2>
<p>This was of course nothing close to all the features Analytics offers.
But I hope that I did show you the mindset I have when analysing data.
These are real people visiting my site, and I want to do good for my audience.</p>
<p>Google Analytics is a great tool to help you with that,
but in the end, it all starts with good content.</p>
 ]]></summary>

                <updated>2019-01-22T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Share a blog: sebastiandedeyne ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/share-a-blog-sebastiandedeyne-com"/>

                <id>https://www.stitcher.io/blog/share-a-blog-sebastiandedeyne-com</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Sebastian's blog has seen many forms the past few years.
From his own personal blog to an aggregator newsletter;
he now settled on a combination of both.</p>
<p>He writes and shares content about web development,
design and programming in general.
In short: a good blog for every programmer to follow!</p>
<p><a target="_blank" href="https://sebastiandedeyne.com/">Check it out</a>!</p>
 ]]></summary>

                <updated>2019-01-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Comparing dates ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/comparing-dates"/>

                <id>https://www.stitcher.io/blog/comparing-dates</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Here's a simple question:</p>
<p>Does the date range <span class="no-break">"2019-01-01 – 2019-01-31"</span> contain the date <span class="no-break">"2019-01-31"</span>?</p>
<p>The answer is yes, right?</p>
<p>… Right?</p>
<p>What if the range ends at 10 o'clock, while our test date starts at 11 o'clock?
Now they don't overlap.</p>
<p>How can we reliably compare dates, if there's always a smaller unit of time we might not know about?
There's two solutions.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="excluding-boundaries"><a href="#excluding-boundaries" class="heading-anchor">#</a> Excluding boundaries</h2>
<p>Here a little mathematics refresher, ranges can be written like so:</p>
<pre>[start, end]
</pre>
<p>Obviously, this notation can be applied to date periods:</p>
<pre>[2019-01-01, 2019-01-31]
</pre>
<p>The square brackets indicate that the boundary is included in the range,
round brackets mean a boundary is excluded:</p>
<pre>(0, 3)
</pre>
<p>This notation tells us this range contains all numbers between 0 and 3, namely <code>1</code> and <code>2</code>.</p>
<p>Using exclusive boundaries, we can compare dates with 100% certainty of correctness.</p>
<p>Instead of testing whether <span class="no-break"><code>[2019-01-01, 2019-01-31]</code></span> contains the date <span class="no-break"><code>2019-01-31</code></span>,
why don't we test whether <span class="no-break"><code>[2019-01-01, 2019-02-01)</code></span> contains it?</p>
<p>An excluded end boundary allows us to say that "all dates before <span class="no-break">2019-02-01</span>" are contained within this range.
The times of our date and period don't matter anymore,
we're always sure that a date before <span class="no-break">2019-02-01</span> will fall within our range.</p>
<h2 id="ensuring-the-same-precision"><a href="#ensuring-the-same-precision" class="heading-anchor">#</a> Ensuring the same precision</h2>
<p>While the above solution mathematically works, it gets awkward in a real world context.
Say we want to note "the whole month of January, 2019" as a range.
It looks like this:</p>
<pre>[2019-01-01, 2019-02-01)
</pre>
<p>This is a little counter intuitive, at least it's not the way we humans think about "January".
We'd never say "from January 1, until February 1, with February 1 excluded".</p>
<p>As it goes in programming, we often sacrifice the "common way of human thinking"
to ensure correctness.</p>
<p>But there <em>is</em> a way to ensure program correctness, <em>with</em> the notation that makes sense to humans:</p>
<pre>[2019-01-01, 2019-01-31]
</pre>
<p>Our problem originated because we weren't sure about the time of the dates we're working with.
My suggestion is to not work around the problem by excluding boundaries,
but to eliminate it for good.</p>
<p>Let's fix the root of the problem instead of working our way around it.
Shouldn't that always be the mindset of every programmer?</p>
<p>Let me say that again, because it's oh so important:</p>
<blockquote>
<p>Let's fix the root of the problem instead of working our way around it.</p>
</blockquote>
<p>The solution? When you're comparing days, make sure you're only comparing days; not hours, minutes or seconds.</p>
<p>When programming, this means you'll have to store the precision of a date range within that range.
It also means you'll have to disallow comparing dates who have different precisions.</p>
<p>What's your opinion?
Let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2018-12-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Have you thought about casing? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/have-you-thought-about-casing"/>

                <id>https://www.stitcher.io/blog/have-you-thought-about-casing</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p id="uncamel-button"></p>
<p>I've made the argument <a href="/blog/where-a-curly-bracket-belongs">many</a> <a href="/blog/visual-perception-of-code">times</a> <a href="/blog/a-programmers-cognitive-load">before</a>:
programmers shouldn't underestimate the value of code readability.
Today I'll argue once more against a common practice we all seem to take for granted: casing.</p>
<p>It seems like such a minor detail, right?
Using camels or snakes or kebabs to string words together, who cares?
There's more to this question though.</p>
<p>Code readability shouldn't be neglected.
It impacts how easy you can navigate and <em>understand</em> your code.
We should talk about the casing conventions we use.</p>
<h2 id="a-little-history"><a href="#a-little-history" class="heading-anchor">#</a> A little history</h2>
<p>Early programming languages didn't have the same conventions we have today.
Languages like Lisp and COBOL originated before widespread ASCII support,
explaining the difference.
Upper- and lower case, and special characters like underscores
simply weren't supported by compilers back in the 50s and early 60s.</p>
<p>Both Lisp and COBOL allowed for hyphens to split words.
Lisp's parser was smart enough to detect whether a hyphen was between two words,
or whether it should be used as the subtraction operator.
COBOL only has full words as operators, eliminating the problem altogether.
Here's a subtraction in COBOL:</p>
<pre>SUBTRACT data-item-1 FROM data-item-2
</pre>
<p>Because the hyphen isn't a reserved keyword, it can be used to split words.</p>
<p>When programming languages matured in the 80s and 90s,
it became clear that the hyphen should be reserved for mathematical operations.
Another issue with Lisp's smart approach was that it didn't scale in modern languages,
it slowed down tokenisation significantly.</p>
<p>Spaces obviously could never be used,
as almost every programming language uses them as the boundary between tokens.
So what's left? How could we write multiple words as one, while keeping these words readable?</p>
<h2 id="conventions-today"><a href="#conventions-today" class="heading-anchor">#</a> Conventions today</h2>
<p>This is why we're left with two major conventions today: camel case, either lower- or upper; and snake case.
As a sidenote: upper camel case is also called pascal case.</p>
<p>Most of the time, a language tends to favourite one of the two casings.
We <em>could</em> say it's a matter of community guidelines, and be done with it.</p>
<p>It's my opinion that there's more to it.
There is one better, more readable way of writing words.
You can probably guess which one, based on the start of this blog post.
camel case makes text more difficult to read, compared to snake case.</p>
<p>Given the word <code>user id</code>, compare the two ways of writing it:</p>
<pre>userId
user_id
</pre>
<p>It's true: camel case is more compact: you don't have to write as much.
But which style is the closest to how the human brain actually reads a text?</p>
<p>This is the only argument that matters to me in this discussion:</p>
<blockquote>
<p>How can we make it as easy as possible for our brain to read and understand code?</p>
</blockquote>
<p>Readable code, reduces cognitive load.
Less cognitive load means more memory space for humans to think about other things,
things like writing business logic.</p>
<p>"All of that just by using underscores?"
No, not just because of underscores.
There's much more to writing readable code than naming conventions.
But all small things help in getting a bigger solution.</p>
<div id="camelcase-end"></div>
<script>
    /**/
    const blog = document.querySelector('.blog');
    const startDiv = blog.querySelector('#uncamel-button');
    const endDiv = blog.querySelector('#camelcase-end');
    const normalParagraphs = blog.querySelectorAll('.blog > p');
    const otherElements = blog.querySelectorAll('.blog > *:not(p):not(script):not(h1):not(aside)');
    const camelParagraphs = [];

    for (let normalParagraph of normalParagraphs) {
        const camelParagraph = document.createElement('p');

        camelParagraph.innerHTML = camelize(normalParagraph.textContent);
        camelParagraph.style.cssText = 'display: block; word-break: break-all;';
        normalParagraph.style.cssText = 'display: none;';

        endDiv.append(camelParagraph);

        camelParagraphs.push(camelParagraph);
    }
    
    for (let otherElement of otherElements) {
        if (otherElement.getAttribute('id') === 'camelcase-end') {
            continue;
        }
        
        otherElement.style.cssText = 'display:none;';
    }

    startDiv.append(createButton());
    startDiv.style.cssText = 'margin-bottom: 1em;font-size:1em; text-align:center;'

    function createButton() {
        const uncamelButton = document.createElement('button');

        uncamelButton.classList.add('cta');
        uncamelButton.classList.add('cta-light');

        uncamelButton.innerHTML = 'Uncammelise';

        uncamelButton.addEventListener('click', function (e) {
            e.preventDefault();
            e.stopPropagation();

            for (let normalParagraph of normalParagraphs) {
                normalParagraph.style.cssText = 'display: block;';
            }

            for (let camelParagraph of camelParagraphs) {
                camelParagraph.style.cssText = 'display: none;';
            }
    
            for (let otherElement of otherElements) {
                otherElement.style.cssText = 'display:block;';
            }

            uncamelButton.style.cssText = 'display: none;';
        });

        return uncamelButton;
    }

    function camelize(str) {
        return str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function (match, index) {
            if (+match === 0) {
                return "";
            }

            return match.toUpperCase();
        });
    }
    /**/
</script>
 ]]></summary>

                <updated>2018-12-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Share a blog: betterwebtype ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/share-a-blog-betterwebtype-com"/>

                <id>https://www.stitcher.io/blog/share-a-blog-betterwebtype-com</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>My colleague <a target="_blank" href="https://mobile.twitter.com/willemvbockstal">Willem</a> always amazes me: the backend developer;
with his insights into design.
It's he who recommended following a blog — it's more like a newsletter — about web typography.</p>
<p>This course broadened the way I think about fonts, and it's the primary reason my own blog, this blog; looks the way it does.
Whether you're a frontend or backend dev, everyone should have basic knowledge about typography,
and I'd recommend following the course over at <a target="_blank" href="https://betterwebtype.com">betterwebtype.com</a> to do so.</p>
 ]]></summary>

                <updated>2018-12-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ New in PHP 7.3 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/new-in-php-73"/>

                <id>https://www.stitcher.io/blog/new-in-php-73</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <h1 id="new-in-php-7.3"><a href="#new-in-php-7.3" class="heading-anchor">#</a> New in PHP 7.3</h1>
<ul>
<li>Released on December 6, 2018</li>
<li>
<a href="#trailing-commas-in-function-calls-rfc">Trailing commas</a> are now allowed in function calls</li>
<li>The <a href="#is_countable-rfc"><code>is_countable</code></a> function</li>
<li>Improvements to the <a href="#flexible-heredoc-syntax-rfc">Heredoc syntax</a> makes it more flexible to use</li>
<li>
<a href="#array_key_first-and-array_key_last-rfc"><code>array_key_first</code> and <code>array_key_last</code></a> are two new array helper functions</li>
</ul>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="is_countable-rfc"><a href="#is_countable-rfc" class="heading-anchor">#</a> <code>is_countable</code> <small><a target="_blank" href="https://wiki.php.net/rfc/is-countable">rfc</a></small></h2>
<p>PHP 7.2 added a warning when counting uncountable objects.
The <code>is_countable</code> function can help prevent this warning.</p>
<pre><span class="hl-variable">$count</span> = <span class="hl-property">is_countable</span>(<span class="hl-variable">$variable</span>) <span class="hl-operator">?</span> <span class="hl-property">count</span>(<span class="hl-variable">$variable</span>) : <span class="hl-keyword">null</span>;
</pre>
<h2 id="array_key_first-and-array_key_last-rfc"><a href="#array_key_first-and-array_key_last-rfc" class="heading-anchor">#</a> <code>array_key_first</code> and <code>array_key_last</code> <small><a target="_blank" href="https://wiki.php.net/rfc/array_key_first_last">rfc</a></small></h2>
<p>These two functions basically do what the name says.</p>
<pre><span class="hl-variable">$array</span> = [
    '<span class="hl-value">a</span>' =&gt; '<span class="hl-value">…</span>',
    '<span class="hl-value">b</span>' =&gt; '<span class="hl-value">…</span>',
    '<span class="hl-value">c</span>' =&gt; '<span class="hl-value">…</span>',
];

<span class="hl-property">array_key_first</span>(<span class="hl-variable">$array</span>); <span class="hl-comment">// 'a'</span>
<span class="hl-property">array_key_last</span>(<span class="hl-variable">$array</span>); <span class="hl-comment">// 'c'</span>
</pre>
<p>The original RFC also proposed <code>array_value_first</code> and <code>array_value_last</code>,
but these were voted against by the majority of people.</p>
<p>Another idea for <code>array_first</code> and <code>array_last</code> was proposed which would return a tuple <code>[$key =&gt; $value]</code>,
but opinions were mixed.
For now we only have two functions to get the first and last key of an array.</p>
<h2 id="flexible-heredoc-syntax-rfc"><a href="#flexible-heredoc-syntax-rfc" class="heading-anchor">#</a> Flexible Heredoc syntax <small><a target="_blank" href="https://wiki.php.net/rfc/flexible_heredoc_nowdoc_syntaxes">rfc</a></small></h2>
<p>Heredoc can be a useful tool for larger strings, though they had an indentation quirk in the past.</p>
<pre><span class="hl-comment">// Instead of this:</span>

<span class="hl-variable">$query</span> = &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">SQL</span></span><span class="hl-injection">
<span class="hl-keyword">SELECT</span> * 
<span class="hl-keyword">FROM</span> `table`
<span class="hl-keyword">WHERE</span> `column` = true;
</span><span class="hl-property"><span class="hl-property">SQL</span></span>;

<span class="hl-comment">// You can do this:</span>

<span class="hl-variable">$query</span> = &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">SQL</span></span><span class="hl-injection">
    <span class="hl-keyword">SELECT</span> * 
    <span class="hl-keyword">FROM</span> `table`
    <span class="hl-keyword">WHERE</span> `column` = true;
    </span><span class="hl-property"><span class="hl-property">SQL</span></span>;
</pre>
<p>This is especially useful when you're using Heredoc in an already nested context.</p>
<p>The whitespaces in front of the closing marker will be ignored on all lines.</p>
<p>An important note: because of this change, some existing Heredocs might break,
when they are using the same closing marker in their body.</p>
<pre><span class="hl-variable">$str</span> = &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">FOO</span></span><span class="hl-injection">
abcdefg
    FOO
</span><span class="hl-property"><span class="hl-property">FOO</span></span>;

<span class="hl-comment">// Parse error: Invalid body indentation level in PHP 7.3</span>
</pre>
<h2 id="trailing-commas-in-function-calls-rfc"><a href="#trailing-commas-in-function-calls-rfc" class="heading-anchor">#</a> Trailing commas in function calls <small><a target="_blank" href="https://wiki.php.net/rfc/trailing-comma-function-calls">rfc</a></small></h2>
<p>What was already possible with arrays, can now also be done with function calls.
Note that it's not possible in function definitions!</p>
<pre><span class="hl-variable">$compacted</span> = <span class="hl-property">compact</span>(
    '<span class="hl-value">posts</span>',
    '<span class="hl-value">units</span>',
);
</pre>
<h2 id="better-type-error-reporting"><a href="#better-type-error-reporting" class="heading-anchor">#</a> Better type error reporting</h2>
<p><code>TypeErrors</code> for integers and booleans used to print out their full name,
it has been changed to <code>int</code> and <code>bool</code>, to match the type hints in the code.</p>
<pre>Argument 1 passed to foo() must be of the type int/bool
</pre>
<p>In comparison to PHP 7.2:</p>
<pre>Argument 1 passed to foo() must be of the type 
integer/boolean
</pre>
<h2 id="json-errors-can-be-thrown-rfc"><a href="#json-errors-can-be-thrown-rfc" class="heading-anchor">#</a> JSON errors can be thrown <small><a target="_blank" href="https://wiki.php.net/rfc/json_throw_on_error">rfc</a></small></h2>
<p>Previously, JSON parse errors were a hassle to debug.
The JSON functions now accept an extra option to make them throw an exception on parsing errors.
This change obviously adds a new exception: <code>JsonException</code>.</p>
<pre><span class="hl-property">json_encode</span>(<span class="hl-variable">$data</span>, <span class="hl-property">JSON_THROW_ON_ERROR</span>);

<span class="hl-property">json_decode</span>(&quot;<span class="hl-value">invalid json</span>&quot;, <span class="hl-keyword">null</span>, 512, <span class="hl-property">JSON_THROW_ON_ERROR</span>);

<span class="hl-comment">// Throws JsonException</span>
</pre>
<p>While this feature is only available with the newly added option,
there's a chance it'll be the default behaviour in a future version.</p>
<h2 id="list-reference-assignment-rfc"><a href="#list-reference-assignment-rfc" class="heading-anchor">#</a> <code>list</code> reference assignment <small><a target="_blank" href="https://wiki.php.net/rfc/list_reference_assignment">rfc</a></small></h2>
<p>The <code>list()</code> and its shorthand <code>[]</code> syntax now support references.</p>
<pre><span class="hl-variable">$array</span> = [1, 2];

<span class="hl-keyword">list</span>(<span class="hl-variable">$a</span>, &amp;<span class="hl-variable">$b</span>) = <span class="hl-variable">$array</span>;

<span class="hl-variable">$b</span> = 3;

<span class="hl-comment">// $array = [1, 3];</span>
</pre>
<h2 id="undefined-variables-in-compact-rfc"><a href="#undefined-variables-in-compact-rfc" class="heading-anchor">#</a> Undefined variables in <code>compact</code> <small><a target="_blank" href="https://wiki.php.net/rfc/compact">rfc</a></small></h2>
<p>Undefined variables passed to <code>compact</code> will be reported with a notice, they were previously ignored.</p>
<pre><span class="hl-variable">$a</span> = '<span class="hl-value">foo</span>';

<span class="hl-property">compact</span>('<span class="hl-value">a</span>', '<span class="hl-value">b</span>'); 

<span class="hl-comment">// Notice: compact(): Undefined variable: b</span>
</pre>
<h2 id="case-insensitive-constants-rfc"><a href="#case-insensitive-constants-rfc" class="heading-anchor">#</a> Case-insensitive constants <small><a target="_blank" href="https://wiki.php.net/rfc/case_insensitive_constant_deprecation">rfc</a></small></h2>
<p>There were a few edge cases were case-insensitive constants were allowed.
These have been deprecated.</p>
<h2 id="same-site-cookie-rfc"><a href="#same-site-cookie-rfc" class="heading-anchor">#</a> Same site cookie <small><a target="_blank" href="https://wiki.php.net/rfc/same-site-cookie">rfc</a></small></h2>
<p>This change not only adds a new parameter,
it also changes the way the <code>setcookie</code>, <code>setrawcookie</code> and <code>session_set_cookie_params</code> functions work in a non-breaking manner.</p>
<p>Instead of one more parameters added to already huge functions, they now support an array of options, whilst still being backwards compatible.
An example:</p>
<pre>bool setcookie(
    string $name 
    [, string $value = &quot;&quot; 
    [, int $expire = 0 
    [, string $path = &quot;&quot; 
    [, string $domain = &quot;&quot; 
    [, bool $secure = false 
    [, bool $httponly = false ]]]]]] 
)

bool setcookie ( 
    string $name 
    [, string $value = &quot;&quot; 
    [, int $expire = 0 
    [, array $options ]]] 
)

// Both ways work.
</pre>
<h2 id="pcre2-migration-rfc"><a href="#pcre2-migration-rfc" class="heading-anchor">#</a> PCRE2 migration <small><a target="_blank" href="https://wiki.php.net/rfc/pcre2-migration">rfc</a></small></h2>
<p>PCRE — short for "Perl Compatible Regular Expressions" — has been updated to v2.</p>
<p>The migration had a focus on maximum backwards compatibility, though there are a few breaking changes.
Be sure to read the <a target="_blank" href="https://wiki.php.net/rfc/pcre2-migration">RFC</a> to know about them.</p>
<h2 id="string-search-functions-readme"><a href="#string-search-functions-readme" class="heading-anchor">#</a> String search functions <small><a target="_blank" href="https://github.com/php/php-src/blob/43329e85e682bed4919bb37c15acb8fb3e63175f/UPGRADING#L327-L339">README</a></small></h2>
<p>You can no longer pass a non-string needle to string search functions.
These are the affected functions:</p>
<pre><span class="hl-property">strpos</span>()
<span class="hl-property">strrpos</span>()
<span class="hl-property">stripos</span>()
<span class="hl-property">strripos</span>()
<span class="hl-property">strstr</span>()
<span class="hl-property">strchr</span>()
<span class="hl-property">strrchr</span>()
<span class="hl-property">stristr</span>()
</pre>
<h2 id="mbstring-updates-readme"><a href="#mbstring-updates-readme" class="heading-anchor">#</a> MBString updates <small><a target="_blank" href="https://github.com/php/php-src/blob/php-7.3.0RC6/UPGRADING#L186-L232">README</a></small></h2>
<p><code>MBString</code> is PHP's way of <a target="_blank" href="http://php.net/manual/en/intro.mbstring.php">handling complex strings</a>.
This module has received some updates in this version of PHP.
You can read about it <a target="_blank" href="https://github.com/php/php-src/blob/php-7.3.0RC6/UPGRADING#L186-L232">here</a>.</p>
<h2 id="several-deprecations-rfc"><a href="#several-deprecations-rfc" class="heading-anchor">#</a> Several deprecations <small><a target="_blank" href="https://wiki.php.net/rfc/deprecations_php_7_3">rfc</a></small></h2>
<p>Several small things have been deprecated, there's a possibility errors can show up in your code because of this.</p>
<ul>
<li>Undocumented <code>mbstring</code> function aliases</li>
<li>String search functions with integer needle</li>
<li>
<code>fgetss()</code> function and <code>string.strip_tags</code> filter</li>
<li>Defining a free-standing <code>assert()</code> function</li>
<li>
<code>FILTER_FLAG_SCHEME_REQUIRED</code> and <code>FILTER_FLAG_HOST_REQUIRED</code> flags</li>
<li>
<code>pdo_odbc.db2_instance_name</code> php.ini directive</li>
</ul>
<p>Please refer to the <a target="_blank" href="https://wiki.php.net/rfc/deprecations_php_7_3">RFC</a> for a full explanation of each deprecation.</p>
 ]]></summary>

                <updated>2018-12-06T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Share a blog: codingwriter.com ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/share-a-blog-codingwriter-com"/>

                <id>https://www.stitcher.io/blog/share-a-blog-codingwriter-com</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>When asking on Twitter for writing advice, I was suggested to check out <a target="_blank" href="https://twitter.com/codingwriter">Sarah Mischinger's</a> blog:
<a target="_blank" href="https://codingwriter.com/">codingwriter.com</a>.
This is a great blog to follow for the technical bloggers out there, myself included.</p>
<p>To me, blogging is more than just shouting my opinion in some corner of the web;
I hope people may learn, the same way I do, by reading other people's blogs.
Writing good content is essential, and I was happy to discover a blog focused on this exact topic.</p>
 ]]></summary>

                <updated>2018-11-14T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Structuring unstructured data ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/structuring-unstructured-data"/>

                <id>https://www.stitcher.io/blog/structuring-unstructured-data</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <h2 id="have-you-ever…"><a href="#have-you-ever…" class="heading-anchor">#</a> Have you ever…</h2>
<p>…worked with an array in PHP that was actually more than just an array?
Did you use the array keys as fields?
And did you feel the pain of not knowing exactly what was in that array?
Not being sure whether the data in it is actually what you expect it to be,
or what fields are available?</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's visualise what I'm talking about:</p>
<pre><span class="hl-variable">$line</span> = <span class="hl-comment">// Get a line from a CSV file</span>

<span class="hl-property">import</span>(<span class="hl-variable">$line</span>['<span class="hl-value">id</span>'], <span class="hl-variable">$line</span>['<span class="hl-value">name</span>'], <span class="hl-variable">$line</span>['<span class="hl-value">amount</span>']);
</pre>
<p>Another example: what about validated request data?</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">store</span>(<span class="hl-injection"><span class="hl-type">PostRequest</span> $request, <span class="hl-type">Post</span> $post</span>) 
{
    <span class="hl-variable">$data</span> = <span class="hl-variable">$request</span>-&gt;<span class="hl-property">validated</span>();
    
    <span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span> = <span class="hl-variable">$data</span>['<span class="hl-value">title</span>'];
    <span class="hl-variable">$post</span>-&gt;<span class="hl-property">author_id</span> = <span class="hl-variable">$data</span>['<span class="hl-value">author_id</span>'];
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>Arrays in PHP are a powerful and versatile data structure.
At some point though, one should wonder whether there are better solutions for their problems.</p>
<h2 id="know-what-you're-writing"><a href="#know-what-you're-writing" class="heading-anchor">#</a> Know what you're writing</h2>
<p>Regular readers of this blog may know that I've written about type theory in <a href="/blog/liskov-and-type-safety">the past</a>.
I won't revisit the pros and cons on strong type systems;
but I do want to say that arrays are a terrible choice
if they are meant to be used as anything else but lists.</p>
<p>Here's a simple question for you: what's in this array?</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">doSomething</span>(<span class="hl-injection"><span class="hl-type">array</span> $blogPost</span>)
{
    <span class="hl-variable">$blogPost</span>[<span class="hl-comment">/* Now what?? */</span>];
}
</pre>
<p>In this case, there are several ways of knowing what data we're dealing with:</p>
<ul>
<li>Read the source code.</li>
<li>Read the documentation.</li>
<li>Dump <code>$blogPost</code> to inspect it.</li>
<li>Or use a debugger to inspect it.</li>
</ul>
<p>I simply wanted to use this data,
but next thing I know, I'm deep into debugging what kind of data I'm actually dealing with.
Are these really the things a programmer should be focused on?</p>
<p>Eliminating this uncertainty can reduce your cognitive load significantly.
This means you can focus on things that really matter:
things like application and business logic.
You know, that's what most clients pay you to do.</p>
<p>It turns out that strongly typed systems can be a great help in understanding what exactly we're dealing with.
Languages like Rust, for example, solve this problem cleanly:</p>
<pre>struct BlogPost {
    title: String,
    body: String,
    active: bool,
}
</pre>
<p>A struct is what we need!
Unfortunately PHP doesn't have structs.
It has arrays and objects, and that's it.</p>
<p>However, we <em>can</em> do something like this:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogPost</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$title</span>;
    <span class="hl-keyword">public</span> <span class="hl-type">string</span> <span class="hl-property">$body</span>;
    <span class="hl-keyword">public</span> <span class="hl-type">bool</span> <span class="hl-property">$active</span>;
}
</pre>
<p>Hang on, I know; we can't really do this, not <em>yet</em>.
PHP 7.4 <a target="_blank" href="https://wiki.php.net/rfc/typed_properties_v2">will add typed properties</a>,
but they are still a long way away.</p>
<p>Imagine for a minute though that typed properties are already supported;
we could use the previous example like so, which our IDE could auto complete:</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">doSomething</span>(<span class="hl-injection"><span class="hl-type">BlogPost</span> $blogPost</span>)
{
    <span class="hl-variable">$blogPost</span>-&gt;<span class="hl-property">title</span>;
    <span class="hl-variable">$blogPost</span>-&gt;<span class="hl-property">body</span>;
    <span class="hl-variable">$blogPost</span>-&gt;<span class="hl-property">active</span>;
}
</pre>
<p>We could even support relations:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogPost</span>
{
    <span class="hl-keyword">public</span> <span class="hl-type">Author</span> <span class="hl-property">$author</span>;
    
    <span class="hl-comment">// …</span>
}
</pre>
<pre><span class="hl-keyword">function</span> <span class="hl-property">doSomething</span>(<span class="hl-injection"><span class="hl-type">BlogPost</span> $blogPost</span>)
{
    <span class="hl-variable">$blogPost</span>-&gt;<span class="hl-property">author</span>-&gt;<span class="hl-property">name</span>;
}
</pre>
<p>Our IDE would always be able to tell us what data we're dealing with.
But of course, typed properties don't exist in PHP yet.
What does exist… are docblocks.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">BlogPost</span>
{
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$title</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">string </span>*/</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$body</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">bool </span>*/</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$active</span>;
    
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">\Author </span>*/</span>
    <span class="hl-keyword">public</span> <span class="hl-property">$author</span>;
}
</pre>
<p>Docblocks are kind of a mess though: they are quite verbose and ugly;
but more importantly, they don't give any guarantees that the data is of the type they say it is!</p>
<p>Luckily, PHP has its reflection API. With it, a lot more is possible, even today.
The above example can actually be type validated with a little reflection magic,
as long as we don't write to the properties directly.</p>
<pre><span class="hl-variable">$blogPost</span> = <span class="hl-keyword">new</span> <span class="hl-type">BlogPost</span>([
    '<span class="hl-value">title</span>' =&gt; '<span class="hl-value">First</span>',
    '<span class="hl-value">body</span>' =&gt; '<span class="hl-value">Lorem ipsum</span>',
    '<span class="hl-value">active</span>' =&gt; <span class="hl-keyword">false</span>,
    '<span class="hl-value">author</span>' =&gt; <span class="hl-keyword">new</span> <span class="hl-type">Author</span>()
]);
</pre>
<p>That seems like a lot of overhead, right?
Remember the first example though!
We're not trying to construct these objects manually,
we're reading them from a CSV file, a request or somewhere else:</p>
<pre><span class="hl-variable">$blogPost</span> = <span class="hl-keyword">new</span> <span class="hl-type">BlogPost</span>(<span class="hl-variable">$line</span>);
</pre>
<p>That's not bad, right?
And remember: a little reflection magic will ensure the values are of the correct type.
I'll show you how that works later.</p>
<p>I prefer this approach.
It enables auto completion on what would otherwise be a black box.
While it requires a little more setup: you'll have to write definitions of data;
the benefits in the long run are worth it.</p>
<p>Sidenote: when I say "in the long run", I mean that this approach is especially useful in larger projects,
where you're working in the same code base with multiple developers, over a longer timespan.</p>
<h2 id="reflecting-types"><a href="#reflecting-types" class="heading-anchor">#</a> Reflecting types</h2>
<p>So, how can we assure that our properties are of the correct type?
Simple: read the <code>@var</code> docblock declaration, validate the value against that type,
and only then set it.
If the value is of a wrong type, we simply throw a <code>TypeError</code>.</p>
<p>Doing this extra check means we cannot write to the properties directly.
At least not if they are declared public.
And in our case public properties are something we really want,
because of when we're using these objects.
We want to be able to easily read data from them;
we don't care as much on making writes easy,
because we should never write to them after the object is constructed.</p>
<p>So we need a "hook" to validate a value against its type, before setting it.
There are two ways to do this in PHP.
Actually there are more, but these two are relevant.</p>
<h3 id="with-a-magic-setter"><a href="#with-a-magic-setter" class="heading-anchor">#</a> With a magic setter</h3>
<p>A magic setter in combination with private or protected properties
would allow us to run type validation before setting the value.</p>
<p>However, as mentioned before, we want a clean and public API to read from;
so magic setters are, unfortunately, a no go.</p>
<h3 id="via-the-constructor"><a href="#via-the-constructor" class="heading-anchor">#</a> Via the constructor</h3>
<p>Like in the previous example, we pass an array of data to the constructor,
and the constructor will map that data onto the properties of its class.
This is the way to go.</p>
<p>Here's a simplified way of doing this:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">array</span> $parameters</span>)
{
    <span class="hl-variable">$publicProperties</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">getPublicProperties</span>();
   
    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$publicProperties</span> <span class="hl-keyword">as</span> <span class="hl-variable">$property</span>) {
        <span class="hl-variable">$value</span> = <span class="hl-variable">$parameters</span>[<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getName</span>()];
        
        <span class="hl-keyword">if</span> (! <span class="hl-variable">$this</span>-&gt;<span class="hl-property">isValidType</span>(<span class="hl-variable">$property</span>, <span class="hl-variable">$value</span>) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">TypeError</span>(&quot;<span class="hl-value">…</span>&quot;);
        }
        
        <span class="hl-variable">$this</span>-&gt;{<span class="hl-variable">$property</span>-&gt;<span class="hl-property">getName</span>()} = <span class="hl-variable">$value</span>;
    }
}
</pre>
<p>Maybe you're curious as to what <code>isValidType</code> exactly does?
Here is, again a simplified, implementation:</p>
<pre><span class="hl-keyword">protected</span> <span class="hl-keyword">function</span> <span class="hl-property">isValidType</span>(<span class="hl-injection"><span class="hl-type">ReflectionProperty</span> $property, $value</span>): <span class="hl-type">bool</span>
{
    <span class="hl-variable">$type</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">getTypeDeclaration</span>(<span class="hl-variable">$property</span>);
    
    <span class="hl-keyword">return</span> <span class="hl-variable">$value</span> <span class="hl-keyword">instanceof</span> <span class="hl-variable">$type</span>
        <span class="hl-operator">||</span> <span class="hl-property">gettype</span>(<span class="hl-variable">$value</span>) === <span class="hl-variable">$type</span>;
    }
}
</pre>
<p>Of course, there are some things missing here:</p>
<ul>
<li>Union types: <code>@var string|int</code>
</li>
<li>
<code>@var mixed</code> support</li>
<li>Generic collections: <code>@var \Foo[]</code>
</li>
<li>Nullable support: <code>@var int|null</code>
</li>
</ul>
<p>But it is very easy to add these checks to our <code>isValidType</code> method.
And that's exactly what we did by the way, we made this into a package: <a target="_blank" href="https://github.com/spatie/data-transfer-object">spatie/data-transfer-object</a>.</p>
<h2 id="what-about-immutability?"><a href="#what-about-immutability?" class="heading-anchor">#</a> What about immutability?</h2>
<p>How to handle immutability is the last question to answer.
If we use these objects to represent data from the outside,
are there any valid use cases for changing these objects once they are constructed?</p>
<p>In 98% of the cases, the answer should be plain and simple: no.
We'll never be able to change the data source,
hence we shouldn't be able to change the object representing that source.</p>
<p>Real life projects are often not as black and white as I portray it here.
While there might be some use cases, I think the mindset of "construct once, and never change"
is a good one.</p>
<p>So how to enforce this in PHP?</p>
<p>Unfortunately: we don't.
There has been talk of so called "read only" properties in PHP's core,
but it's a difficult thing to get right.
Then what about our userland type system?
Unless we're giving up the ease of reading, the auto completion part;
there will be no way to achieve this goal in PHP.</p>
<p>See, we <em>need</em> magic getters to support this behaviour;
at the same time we <em>don't</em> want them.
They would negate one of the goals we're trying to achieve: easy discoverability.</p>
<p>So for now, unfortunately,
our package will allow writes to an object's properties after it is constructed.
We are just careful not to do it.</p>
<p>I hope this post inspired you to think about your own code bases,
and that you might be prompted to try this pattern out in your projects;
with <a target="_blank" href="https://github.com/spatie/data-transfer-object">our package</a> or your own implementation.</p>
<p>If there are any thoughts that come to your mind or if you want to discuss this further, I'd love to here from you!
You can reach me via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2018-11-11T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PhpStorm OSX performance: October 2018 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/phpstorm-performance-october-2018"/>

                <id>https://www.stitcher.io/blog/phpstorm-performance-october-2018</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PhpStorm has had performance issues on OSX for a very long time now,
sometimes to the point of being unusable.</p>
<p>I've written about these issues before, but it's good to keep a regularly updated list of what's going on.
So without further ado: if you're on OSX (Sierra, High Sierra or Mojave);
if you're experiencing PhpStorm performance issues, this post might help you.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="external-monitor-resolution"><a href="#external-monitor-resolution" class="heading-anchor">#</a> External monitor resolution</h2>
<p>Do you have an external monitor plugged into your MacBook?
There's an issue in Java Swing, the UI framework that PhpStorm uses under the hood.
In short: if you're using a non-default resolution,
Java has to do a lot of calculations to deal with half pixels and such.</p>
<p>In case of 4k monitors, we've seen good results with 1080p and 4k resolutions,
as they are natively supported.
All other resolutions can cause massive performance issues.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/phpstorm-performance-october/resolution-default.png" srcset="/resources/img/blog/phpstorm-performance-october/resolution-default-774x524.png 774w, /resources/img/blog/phpstorm-performance-october/resolution-default-999x677.png 999w, /resources/img/blog/phpstorm-performance-october/resolution-default-894x606.png 894w, /resources/img/blog/phpstorm-performance-october/resolution-default-632x428.png 632w, /resources/img/blog/phpstorm-performance-october/resolution-default-447x303.png 447w" sizes="" alt=""></img></p>
<p>Default resolutions work fine.</p>
<div class="image-noborder"></div>
<p><img src="/resources/img/blog/phpstorm-performance-october/resolution-scaled.png" srcset="/resources/img/blog/phpstorm-performance-october/resolution-scaled-894x606.png 894w, /resources/img/blog/phpstorm-performance-october/resolution-scaled-774x524.png 774w, /resources/img/blog/phpstorm-performance-october/resolution-scaled-999x677.png 999w, /resources/img/blog/phpstorm-performance-october/resolution-scaled-447x303.png 447w, /resources/img/blog/phpstorm-performance-october/resolution-scaled-632x428.png 632w" sizes="" alt=""></img></p>
<p>Scaled resolutions not so much…</p>
<h2 id="font-antialiasing"><a href="#font-antialiasing" class="heading-anchor">#</a> Font antialiasing</h2>
<p>In your settings, under <code>Editor &gt; Appearance &amp; Behaviour &gt; Appearance</code>,
you'll find the editor font antialiasing options.</p>
<p>By default, antialiasing is set to <code>subpixel</code>, to render very smooth fonts.
Again, because of Java graphical issues, there can be a big performance hit.</p>
<p><img src="/resources/img/blog/phpstorm-performance-october/font-settings.png" srcset="/resources/img/blog/phpstorm-performance-october/font-settings-1134x284.png 1134w, /resources/img/blog/phpstorm-performance-october/font-settings-878x219.png 878w, /resources/img/blog/phpstorm-performance-october/font-settings-507x126.png 507w, /resources/img/blog/phpstorm-performance-october/font-settings-717x179.png 717w, /resources/img/blog/phpstorm-performance-october/font-settings-1014x253.png 1014w" sizes="" alt=""></img></p>
<p>It's better to set the antialiasing setting to <code>greyscale</code>, or disable it altogether.</p>
<p>Your font choice might also impact performance.
I know this might take some time to get used to, but try using another font.
I always used Ubuntu Mono, but switched to Monaco, and had noticeable improvements.</p>
<h2 id="javafx-enabled-plugins"><a href="#javafx-enabled-plugins" class="heading-anchor">#</a> JavaFX enabled plugins</h2>
<p>Some plugins make use of JavaFX, that may cause rendering issues.
As an easy way to know if you're running such plugins, you can do the following.</p>
<p>Get the PID of the running PhpStorm process:</p>
<pre>&gt; top | grep phpstorm

82912  phpstorm         …
</pre>
<p>Next, run <code>jstack</code> with PhpStorm's process ID, and grep for "quantum":</p>
<pre>&gt; jstack 82912 | grep quantum

at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
</pre>
<p>If you see any output (as above), it means that plugins are using JavaFX.
Using these plugins will increase performance issues over time, especially if you're running PhpStorm as a maximized window.</p>
<p>The only way to know which plugins are using JavaFX is by disabling plugins, one by one; restarting PhpStorm and doing the above <code>jstack</code> test again.
One very popular plugin depending on JavaFX is the Markdown plugin.</p>
<h2 id="jdk-versions"><a href="#jdk-versions" class="heading-anchor">#</a> JDK versions</h2>
<p>The last thing you can do is download a new Java JDK, another version, and use that one to run PhpStorm.</p>
<p>You can configure the JDK PhpStorm is using by opening the command palette and search for <code>Switch Boot JDK…</code>.</p>
<p><img src="/resources/img/blog/phpstorm-performance-october/jdk.png" srcset="/resources/img/blog/phpstorm-performance-october/jdk-804x252.png 804w, /resources/img/blog/phpstorm-performance-october/jdk-508x159.png 508w, /resources/img/blog/phpstorm-performance-october/jdk-359x112.png 359w, /resources/img/blog/phpstorm-performance-october/jdk-622x194.png 622w, /resources/img/blog/phpstorm-performance-october/jdk-719x225.png 719w" sizes="" alt="Boot JDK"><em class="small center">Boot JDK</em></img></p>
<p>It's important to note that IntelliJ products won't run on all JDKs!
At the time of writing, Java 10 won't work yet.</p>
<p>If you've configured a JDK that broke PhpStorm, you can still fix it though.
There's a file in your preferences folder which contains the JDK you're using:</p>
<pre>~/Library/Preferences/IntelliJIdea&lt;VERSION&gt;/idea.jdk
</pre>
<p>You can change the JDK path there.
More information on switching JDKs can be found <a target="_blank" href="https://intellij-support.jetbrains.com/hc/en-us/articles/206544879-Selecting-the-JDK-version-the-IDE-will-run-under">here</a>.</p>
<h2 id="in-closing:"><a href="#in-closing:" class="heading-anchor">#</a> In closing:</h2>
<p>Software development is hard.</p>
<p>It's understandable why JetBrains chooses Java as a platform for their IDEs.
Unfortunately Java Swing, an older UI framework, doesn't play well with modern OSX platforms.</p>
<p>Whose fault is this? Should JetBrains fix it? Will they be able to?
There's no clear answer to those questions.
There's an active issue <a target="_blank" href="https://youtrack.jetbrains.com/issue/JRE-526">here</a>,
where you can follow the progress;
though I doubt there will be any solutions soon.</p>
<p>For now, we'll have to deal with these performance issues,
because — even though they are annoying — PhpStorm is still the best PHP IDE out there, by far.</p>
 ]]></summary>

                <updated>2018-10-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Share a blog: assertchris.io ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/share-a-blog-assertchris-io"/>

                <id>https://www.stitcher.io/blog/share-a-blog-assertchris-io</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><a target="_blank" href="https://twitter.com/assertchris">Christopher Pitt</a> is one of the inspirations why I got into blogging and conference talks.
Being an excellent writer — he used to blog on Sitepoint and Medium — he now decided to host his content on his own website.
A wise decision!</p>
<p>I'd highly recommend adding his blog to your RSS reader, or bookmark it somewhere: <a target="_blank" href="https://assertchris.io/">assertchris.io</a>.
There's lots of good content to look forward to!</p>
 ]]></summary>

                <updated>2018-10-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ array_merge or + in PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/array-merge-vs+"/>

                <id>https://www.stitcher.io/blog/array-merge-vs+</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>PHP has several ways of combining two arrays into one. You can use <code>array_merge</code> or the <code>+</code> operator.
There's a subtle difference between these two methods though, a difference worth knowing.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's take a look at how these two methods compare:</p>
<pre><span class="hl-property">array_merge</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>);

<span class="hl-comment">// vs.</span>

<span class="hl-variable">$first</span> + <span class="hl-variable">$second</span>;
</pre>
<p>Let's say these are the two arrays we're working with:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-value">a</span>',
    '<span class="hl-value">b</span>',
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-value">c</span>',
];
</pre>
<p>This would be the result of a simple <code>array_merge</code> call:</p>
<pre><span class="hl-property">array_merge</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>);

[
    '<span class="hl-value">a</span>',
    '<span class="hl-value">b</span>',
    '<span class="hl-value">c</span>',
]
</pre>
<p>While the <code>+</code> operator gives us this result:</p>
<pre><span class="hl-variable">$first</span> + <span class="hl-variable">$second</span>;

[
    '<span class="hl-value">a</span>',
    '<span class="hl-value">b</span>',
]
</pre>
<p>Switching the operands while using the <code>+</code> operator, gives a different result:</p>
<pre><span class="hl-variable">$second</span> + <span class="hl-variable">$first</span>;

[
    '<span class="hl-value">c</span>',
    '<span class="hl-value">b</span>',
]
</pre>
<p>Confused? So was I.</p>
<p>Let's write out the <code>$first</code> and <code>$second</code> arrays in full, with their indices.
This will make things more clear:</p>
<pre><span class="hl-variable">$first</span> = [
    0 =&gt; '<span class="hl-value">a</span>',
    1 =&gt; '<span class="hl-value">b</span>',
];

<span class="hl-variable">$second</span> = [
    0 =&gt; '<span class="hl-value">c</span>',
];
</pre>
<p>By now you can probably guess what's going on:
the <code>+</code> operator will only <em>add</em> the elements of the rightside operand, if their key
doesn't exist in the leftside operand, while <code>array_merge</code> will <em>override</em> existing keys.</p>
<p>By that definition, we can also determine that <code>+</code> can never be used to recursively merge arrays,
as it will leave existing elements untouched:</p>
<pre><span class="hl-variable">$first</span> = [
    '<span class="hl-property">A</span>' =&gt; [
        '<span class="hl-property">B</span>' =&gt; <span class="hl-keyword">true</span>,
        '<span class="hl-property">C</span>' =&gt; <span class="hl-keyword">true</span>,
    ],
];

<span class="hl-variable">$second</span> = [
    '<span class="hl-property">A</span>' =&gt; [
        '<span class="hl-property">B</span>' =&gt; <span class="hl-keyword">false</span>,
        '<span class="hl-property">C</span>' =&gt; <span class="hl-keyword">false</span>,
    ],
];

<span class="hl-variable">$first</span> + <span class="hl-variable">$second</span>;
</pre>
<p>Here's the result:</p>
<pre>[
    '<span class="hl-property">A</span>' =&gt; [
        '<span class="hl-property">B</span>' =&gt; <span class="hl-keyword">true</span>,
        '<span class="hl-property">C</span>' =&gt; <span class="hl-keyword">true</span>,
    ],
]
</pre>
<p>While using <code>array_merge</code>, would give this result:</p>
<pre>[
    '<span class="hl-property">A</span>' =&gt; [
        '<span class="hl-property">B</span>' =&gt; <span class="hl-keyword">false</span>,
        '<span class="hl-property">C</span>' =&gt; <span class="hl-keyword">false</span>,
    ],
]
</pre>
<p>"Hang on", I hear you say, "isn't that what <code>array_merge_recursive</code> is supposed to do?".</p>
<p>Here we have a case of unfortunate naming.
Please don't be surprised — it's PHP after all.</p>
<p>See, <code>array_merge</code> will merge matching elements by overriding them.
<code>array_merge_recursive</code> on the other hand will keep both elements, and merge them in a new array, keeping both values.</p>
<p>This is what our previous example would look like, using <code>array_merge_recursive</code>:</p>
<pre>[
    '<span class="hl-property">A</span>' =&gt; [
        '<span class="hl-property">B</span>' =&gt; [
            <span class="hl-keyword">true</span>,
            <span class="hl-keyword">false</span>,
        ],
        '<span class="hl-property">C</span>' =&gt; [
            <span class="hl-keyword">true</span>,
            <span class="hl-keyword">false</span>,
        ],
    ],
]
</pre>
<p>What about merging multiple arrays?
You can probably guess the outcome by now:</p>
<pre><span class="hl-variable">$first</span> = ['<span class="hl-value">a</span>'];
<span class="hl-variable">$second</span> = ['<span class="hl-value">b</span>'];
<span class="hl-variable">$third</span> = ['<span class="hl-value">c</span>'];
</pre>
<p>Here's what <code>array_merge</code> results in:</p>
<pre><span class="hl-property">array_merge</span>(<span class="hl-variable">$first</span>, <span class="hl-variable">$second</span>, <span class="hl-variable">$third</span>)
</pre>
<pre>[
    '<span class="hl-value">a</span>',
    '<span class="hl-value">b</span>',
    '<span class="hl-value">c</span>',
]
</pre>
<p>Chaining the <code>+</code> operator also works, with the following result:</p>
<pre><span class="hl-variable">$first</span> + <span class="hl-variable">$second</span> + <span class="hl-variable">$third</span>
</pre>
<pre>[
    '<span class="hl-value">a</span>',
]
</pre>
<hr />
<p>With this little refresher,
I hope that you won't find yourself confused anymore when you're deep into your code and need to merge arrays.</p>
<p>I found it to be a cognitive burden when I had to stop and think about "hang on, what is the correct way to do this?".
Luckily now, we know!</p>
 ]]></summary>

                <updated>2018-10-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Laravel view models vs. view composers ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/laravel-view-models-vs-view-composers"/>

                <id>https://www.stitcher.io/blog/laravel-view-models-vs-view-composers</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="author">
    Update: I've written a new version of this post, as part of my <a href="/blog/laravel-beyond-crud">Laravel beyond CRUD</a> series. You can read it <a href="/blog/laravel-beyond-crud-08-view-models">here</a>. 
</div>
<p>Last month I wrote about view models in Laravel.
I received a lot of good reactions on the post, but also the same question over and over again:
how do view models differ from view composers in Laravel?</p>
<p>Time to clarify this question once and for all.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="view-composers"><a href="#view-composers" class="heading-anchor">#</a> View composers</h2>
<p>Let's look at how view composers are used in Laravel.
View composers are a way of binding data to a view from global configuration.</p>
<p>The Laravel documentation explains it like this:</p>
<blockquote>
<p>View composers are callbacks or class methods that are called when a view is rendered.
If you have data that you want to be bound to a view each time that view is rendered,
a view composer can help you organize that logic into a single location.</p>
</blockquote>
<p>View composers are registered like this, the example is taken from the Laravel docs.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ComposerServiceProvider</span> <span class="hl-keyword">extends</span> <span class="hl-type">ServiceProvider</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">boot</span>()
    {
        <span class="hl-type">View</span>::<span class="hl-property">composer</span>(
            '<span class="hl-value">profile</span>', <span class="hl-type">ProfileComposer</span>::<span class="hl-keyword">class</span>
        );

        <span class="hl-type">View</span>::<span class="hl-property">composer</span>('<span class="hl-value">dashboard</span>', <span class="hl-keyword">function</span> (<span class="hl-injection">$view</span>) {
            <span class="hl-comment">// …</span>
        });
    }
    
    <span class="hl-comment">// …</span>
}
</pre>
<p>As you can see you can both use a class and a closure which you can use to add variables to a view.</p>
<p>Here's how view composers are used in controllers.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ProfileController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>()
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">view</span>('<span class="hl-value">profile</span>');
    }
}
</pre>
<p>Can you see them? Nope, of course not: view composers are registered somewhere in the global state,
and you don't know which variables are available to the view, without that implicit knowledge.</p>
<p>Now I <em>know</em> that this isn't a problem in small projects.
When you're the single developer and only have 20 controllers and maybe 20 view composers,
it'll all fit in your head.</p>
<p>But what about a project with three or four developers, with hundreds of controllers?
What if you're taking over a legacy project where you don't have this implicit knowledge?</p>
<p>This is why at <a target="_blank" href="https://spatie.be">Spatie</a>, we use view models in our larger projects.
They make everything much more explicit, which helps us keep the code maintainable.</p>
<p>Here's what we do:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ProfileController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>(<span class="hl-injection"><span class="hl-type">User</span> $user</span>)
    {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">view</span>(
            '<span class="hl-value">profile</span>', 
            <span class="hl-keyword">new</span> <span class="hl-type">ProfileViewModel</span>(<span class="hl-variable">$user</span>)
        );
    }
}
</pre>
<p>Now it's clear now from the controller itself what variables are available to the view.
We can also re-use the same view for multiple contexts.
An example would be the same form view used in the create and edit actions.</p>
<p>One last added benefit, one you might not have thought about,
is that we can pass data into the view model explicitly.
If you want to use a route argument or bound model to determine data passed to the view,
it is done explicitly.</p>
<p>In conclusion: managing global state is a pain in large applications,
especially when you're working with multiple developers on the same project.
Also remember that just because two means have the same end result,
that doesn't mean that they are the same!</p>
<p>I hope this quick writeup answers all the questions about the difference between view models and -composers.
If you want to know more about view models in particular,
be sure to read the blog post about them <a href="/blog/laravel-view-models">here</a>.</p>
 ]]></summary>

                <updated>2018-10-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Organise by domain ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/organise-by-domain"/>

                <id>https://www.stitcher.io/blog/organise-by-domain</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In this post we'll look at a different approach of structuring large code bases into separate domains.
The name "domain" is derived from the popular DDD paradigm, or also: domain driven design.</p>
<div class="author">
Since I wrote this post, I actually started a whole blog series on how to organise larger Laravel projects. I'd recommend to <a href="/blog/laravel-beyond-crud">check it out</a> instead. 
</div>
<p>While many concepts in this post are inspired by DDD principles,
they don't strictly follow domain driven design.
In our context, "domain" could also be named "module".
A "domain" simply refers to a category of related stuff,
that's it.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>It's also important to note is that this approach isn't a silver bullet.
At <a target="_blank" href="https://spatie.be">Spatie</a> we choose a different project structure
based on the needs of that specific project.
It is possible that your project isn't a good fit for what we'll be reviewing today.</p>
<p>In our experience, today's principles are mostly beneficial in larger projects:</p>
<ul>
<li>Long running projects with an initial development timespan of half a year to one year or more,
with several years of maintenance and extensions after that.</li>
<li>Around fifty to hundred models representing the business.</li>
<li>Several hundred routes exposing functionality to the outside.</li>
</ul>
<h2 id="so,-what-is-a-&quot;domain&quot;-?"><a href="#so,-what-is-a-"domain"-?" class="heading-anchor">#</a> So, what is a "domain" ?</h2>
<p>If you've worked on these kinds of large projects before,
you know that "the business logic" never is just <em>one</em> thing.
Often during development, you'll identify "sub-systems" within the larger domain;
that is: the collection of problems you're trying to solve with your code.</p>
<p>To name a few examples: user management, inventory management, invoicing and contracts.
I'm sure you can think of many others.</p>
<p>Most likely, every sub-system has one or several models.
But it doesn't stop there:
models can be interacted with,
actions can be performed with them,
there can be system-specific validation rules,
ways of passing data between systems, and more.</p>
<p>Looking at a standard Laravel application, the code describing a single system
is often spread across multiple directories:</p>
<pre>app/
├── Enums/
│   ├── ContractDurationType.php
│   └── ContractType.php
├── Exceptions/
│   └── InvalidContractDate.php
├── Models/
│   └── Contract.php
└── Rules/
    ├── ContractAvailabilityRule.php
    └── ContractDurationRule.php
</pre>
<p>This structure was the first struggle that prompted me to look for a better solution.
I often found myself searching through several places in order to work one thing, one system.</p>
<p>So why not group sub-systems together?
It looks something like this:</p>
<pre>Domain/
├── Contracts/
├── Invoicing/
└── Users/
</pre>
<p>You can see the name <code>Domain</code> here.
According to Oxford Dictionary, a "domain" can be described like so:</p>
<blockquote>
<p>A specified sphere of activity or knowledge.</p>
</blockquote>
<p>We're grouping code together based on their sphere of activity, their domain.
Let's zoom into one specific domain folder:</p>
<pre>Contracts/
├── Actions/
├── Enums/
├── Exceptions/
├── Models/
├── Rules/
├── Status/
└── ValueObjects/
</pre>
<p>Modern PHP developers are most likely familiar with most of these folder names.
Though some deserve a little more attention.</p>
<h3 id="actions"><a href="#actions" class="heading-anchor">#</a> Actions</h3>
<p>Actions are probably the most powerful tool within this whole setup.
An action is a class that performs an operation within its domain.
This might be a simple task like creating or updating a model,
or something more complex following one or several business rules like approving a contract.</p>
<p>Because a single action only focuses on one task,
they are extremely flexible:
an action can be composed out of other actions and they can be injected wherever you want.</p>
<p>Here's an example of two actions working together: <code>CreateOrUpdateContractLine</code> and <code>ResolveContractLines</code>.
The first one will do as its name says: create or update a single contract line.
The second one will loop over a collection of user input, and resolve the lines one by one.</p>
<p>Here's what <code>ResolveContractLines</code> will do:</p>
<ul>
<li>Loop over the user input and create or update existing lines.</li>
<li>Keep a list of contract lines which are currently added to the contract.</li>
<li>Remove all lines that don't exist anymore, the user has removed them.</li>
</ul>
<p>Here's the code:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ResolveContractLines</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">CreateOrUpdateContractLine</span> $createOrUpdateContractLine,
        <span class="hl-type">RemoveContractLine</span> $removeContractLine
    </span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">execute</span>(<span class="hl-injection">
        <span class="hl-type">Contract</span> $contract,
        <span class="hl-type">ContractLinesCollection</span> $contractLinesCollection
    </span>) {
        <span class="hl-variable">$lineIds</span> = [];

        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$contractLinesCollection</span> <span class="hl-keyword">as</span> <span class="hl-variable">$contractLineData</span>) {
            <span class="hl-variable">$contractLine</span> = <span class="hl-variable">$this</span>-&gt;<span class="hl-property">createOrUpdateContractLine</span>
                -&gt;<span class="hl-property">execute</span>(<span class="hl-variable">$contractLineData</span>);

            <span class="hl-variable">$lineIds</span>[] = <span class="hl-variable">$contractLine</span>-&gt;<span class="hl-property">id</span>;
        }

        <span class="hl-variable">$contractLinesToRemove</span> = <span class="hl-type">ContractLine</span>::<span class="hl-property">query</span>()
            -&gt;<span class="hl-property">whereContract</span>(<span class="hl-variable">$contract</span>)
            -&gt;<span class="hl-property">whereNotIn</span>('<span class="hl-value">id</span>', <span class="hl-variable">$lineIds</span>)
            -&gt;<span class="hl-property">get</span>();

        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$contractLinesToRemove</span> <span class="hl-keyword">as</span> <span class="hl-variable">$contractLine</span>) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">removeContractLine</span>-&gt;<span class="hl-property">execute</span>(<span class="hl-variable">$contractLine</span>);
        }
    }
}
</pre>
<p>Besides composing actions together, they are also great for testing.
Because of an action's small size and single responsibility,
it can be unit tested very efficiently.</p>
<p>Actions also encapsulate most of the business logic for the app:
generating contract numbers, changing statuses, handling side-effects in an explicit way,…
This makes it easier for developers to reason about what the application does,
as most of its business is encapsulated as actions.</p>
<p>If you're into DDD, you're probably thinking of commands right now.
Actions are a simpler version of them.
There's no command bus and actions may directly return values.
For the scope of our projects, it's a very manageable approach.</p>
<h3 id="valueobjects"><a href="#valueobjects" class="heading-anchor">#</a> ValueObjects</h3>
<p>You're probably wondering how this domain stuff ties together with controllers or CLI commands.
That's of course the place where you'll use them.
There's one more abstraction we need to understand though: value objects.</p>
<p><em>Update</em>: since writing this blog post there has been an interesting discussion
on the name of "value object". We've changed the name to "data transfer object".
You can read more about this naming <a target="_blank" href="https://github.com/spatie/data-transfer-object/issues/17">here</a>.</p>
<p>Have you noticed the <code>ContractLinesCollection</code> passed to the <code>ResolveContractLines</code> action in the previous example?
That's a value object.</p>
<p>Working with user input isn't always straight forward.
For example, in Laravel applications you'll get an array of form data or an array of CLI arguments,
the rest is up to you.</p>
<p>Value objects are a representation of that user data, in a structured way.
Because we want don't want to concern our actions with input validation,
we pass them a value object.
There's one rule applied to value objects: if they exist, they are valid.</p>
<p>Most of the time, value objects are a simple mapping between validated request data,
and properties that can be used by actions.</p>
<p>Here's an example of a value object:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ContractLineData</span>
{
    <span class="hl-keyword">public</span> <span class="hl-property">$price</span>;
    <span class="hl-keyword">public</span> <span class="hl-property">$dateFrom</span>;
    <span class="hl-keyword">public</span> <span class="hl-property">$dateTo</span>;
    <span class="hl-keyword">public</span> <span class="hl-property">$article</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">fromArray</span>(<span class="hl-injection">
        <span class="hl-type">array</span> $input
    </span>): <span class="hl-type">ContractLineData</span> {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">self</span>(
            <span class="hl-variable">$input</span>['<span class="hl-value">price</span>'],
            <span class="hl-type">Carbon</span>::<span class="hl-property">make</span>(<span class="hl-variable">$input</span>['<span class="hl-value">date_from</span>']),
            <span class="hl-type">Carbon</span>::<span class="hl-property">make</span>(<span class="hl-variable">$input</span>['<span class="hl-value">date_to</span>']),
            <span class="hl-type">Article</span>::<span class="hl-property">find</span>(<span class="hl-variable">$input</span>['<span class="hl-value">article_id</span>'])
        );
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">int</span> $price,
        <span class="hl-type">Carbon</span> $dateFrom,
        <span class="hl-type">Carbon</span> $dateTo,
        <span class="hl-type">Article</span> $article
    </span>) { <span class="hl-comment">/* … */</span> }
}
</pre>
<p>Because of convenience, we're using public properties.
You can imagine why we're looking forward to strongly typed and readonly properties in PHP.</p>
<p>Value objects allow actions to only focus on the actual action,
and not be concerned whether input is valid or not.
Furthermore, it's easy to fake a value object, making tests simpler once more.</p>
<h2 id="tying-it-together"><a href="#tying-it-together" class="heading-anchor">#</a> Tying it together</h2>
<p>Up until this point, I've said almost nothing about controllers or CLI commands,
and how they fit into this picture. That's intentional.</p>
<p>See, because our domains are split into separate areas,
we're able to develop a whole domain, without ever writing a single controller or view.
Everything in the domain is easily testable,
and almost every domain can be be developed side by side with other domains.</p>
<p>In larger projects, this is a highly efficient approach.
We've got two or three backend developers working on one project,
and each of them has a domain they are working on next to each other.</p>
<p>Also, because every domain is tested, we're very certain that all business logic
required by the client works as intended, before writing a single form and integration tests.</p>
<p>Once a domain is done, it can be consumed.
The domain itself doesn't care when or where it is used,
its usage rules are clear to the outside.</p>
<p>This means we're able to build one or more applications, using the existing domains.
In one of our projects, there's an admin HTTP application and a REST API.
Both of them use the same domains; their actions, models, rules, etc.
You can see how this approach is not only efficient during development,
but also enables for much better scaling.</p>
<p>Here's an example of how a controller in the admin HTTP application looks:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ContractsController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">index</span>() { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">edit</span>(<span class="hl-injection"><span class="hl-type">Contract</span> $contract</span>) { <span class="hl-comment">/* … */</span> }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">update</span>(<span class="hl-injection">
        <span class="hl-type">Contract</span> $contract,
        <span class="hl-type">UpdateContract</span> $updateContract,
        <span class="hl-type">UpdateContractRequest</span> $updateContractRequest
    </span>) {
        <span class="hl-variable">$contract</span> = <span class="hl-variable">$updateContract</span>-&gt;<span class="hl-property">execute</span>(
            <span class="hl-variable">$contract</span>,
            <span class="hl-type">ContractData</span>::<span class="hl-property">fromRequest</span>(<span class="hl-variable">$updateContractRequest</span>)
        );
        
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">ContractViewModel</span>(<span class="hl-variable">$contract</span>);
    }
}
</pre>
<p>Almost all our controllers actions are as simple as this:</p>
<ul>
<li>Validate the request data and parse it into a value object.</li>
<li>Execute the action, we don't care anymore what happens underneath at this point.</li>
<li>Return the result, in our case using <a href="/blog/laravel-view-models">view models</a>.</li>
</ul>
<h2 id="in-closing"><a href="#in-closing" class="heading-anchor">#</a> In closing</h2>
<p>Structuring code in domains increases efficiency between developers on a single project.
Furthermore, it decreases the complexity of maintenance, because sub-systems are separated and well tested.</p>
<p>By using actions and value objects, you're able to communicate with the domain
in a controlled and testable way.
While it takes longer to initially write, this approach pays off very quickly,
even during early development.</p>
<p>Maybe the most important reason for structuring our code this way,
is that it's easier to understand.
We humans don't think in abstracts like "models", "actions" and "rules";
we categorize complex business processes into sub-systems.
Things like "contracts" and "invoicing".</p>
<p>I've been structuring complex code bases like this for two years,
and can say from experience that it's significantly more easy to reason about them now.
In end, I believe developer experience is equally important as theoretical knowledge and paradigms to succeed.</p>
<hr />
<p>👋 Hi, thanks for reading!
I hope this post can help you in one way or another.</p>
<p>If you want to talk more about this topic –I do– you can always send me a Tweet or e-mail.
Here's my <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a>, and here my <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2018-10-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Laravel view models ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/laravel-view-models"/>

                <id>https://www.stitcher.io/blog/laravel-view-models</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <div class="author">
    Update: I've written a new version of this post, as part of my <a href="/blog/laravel-beyond-crud">Laravel beyond CRUD</a> series. You can read it <a href="/blog/laravel-beyond-crud-08-view-models">here</a>. 
</div>
<p>View models are an abstraction to simplify controller and model code.
View models are responsible for providing data to a view,
which would otherwise come directly from the controller or the model.
They allow a better separation of concerns, and provide more flexibility for the developer.</p>
<p>In essence, view models are simple classes that take some data,
and transform it into something usable for the view.
In this post I'll show you the basic principles of the pattern,
we'll take a look at how they integrate in Laravel projects,
and finally I'll show you how we use the pattern in one of <a target="_blank" href="https://spatie.be">Spatie</a>'s, our company, projects.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Let's get started.
Say you have a form to create a blog post with a category.
You'll need a way to fill the select box in the view with category options.
The controller has to provide those.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">create</span>()
{
    <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">blog.form</span>', [
        '<span class="hl-value">categories</span>' =&gt; <span class="hl-type">Category</span>::<span class="hl-property">all</span>(),
    ]);
}
</pre>
<p>The above example works for the create method,
but let's not forget we should also be able to edit existing posts.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">edit</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>)
{
    <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">blog.form</span>', [
        '<span class="hl-value">post</span>' =&gt; <span class="hl-variable">$post</span>,
        '<span class="hl-value">categories</span>' =&gt; <span class="hl-type">Category</span>::<span class="hl-property">all</span>(),
    ]);
}
</pre>
<p>Next there's a new business requirement:
users should be restricted in which categories they are allowed to post in.
In other words: the category selection should be restricted based on the user.</p>
<pre><span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">blog.form</span>', [
    '<span class="hl-value">categories</span>' =&gt; <span class="hl-type">Category</span>::<span class="hl-property">allowedForUser</span>(
        <span class="hl-property">current_user</span>()
    )-&gt;<span class="hl-property">get</span>(),
]);
</pre>
<p>This approach doesn't scale.
You'll have to change code both in the <code>create</code> and <code>edit</code> method.
Can you imagine what happens when you need to add tags to a post?
Or if there's another special admin form for creating and editing posts?</p>
<p>The next solution is to have the post model itself provide the categories, like so:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Post</span> <span class="hl-keyword">extends</span> <span class="hl-type">Model</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">allowedCategories</span>(): <span class="hl-type">Collection</span> 
    {
        <span class="hl-keyword">return</span> <span class="hl-type">Category</span>::<span class="hl-property">query</span>()
            -&gt;<span class="hl-property">allowedForUser</span>(<span class="hl-property">current_user</span>())
            -&gt;<span class="hl-property">get</span>();
    }
}
</pre>
<p>There are numerous reasons why this is a bad idea, though it happens often in Laravel projects.
Let's focus on the most relevant problem for our case: it still allows for duplication.</p>
<p>Say there's a new model <code>News</code> which also needs the same category selection.
This causes again duplication, but on the model level instead of in the controllers.</p>
<p>Another option is to put the method on the <code>User</code> model.
This makes the most sense, but also makes maintenance harder.
Imagine we're using tags as mentioned before.
They don't rely on the user.
Now we need to get the categories from the user model, and tags from somewhere else.</p>
<p>I hope it's clear that using models as data providers for views also isn't the silver bullet.</p>
<p>In summary, wherever you try to get the categories from,
there always seems to be some code duplication.
This makes it harder to maintain and reason about the code.</p>
<p>This is where view models come into play.
They encapsulate all this logic so that it can be reused in different places.
They have one responsibility and one responsibility only: providing the view with the correct data.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostFormViewModel</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">User</span> $user, 
        <span class="hl-type">Post</span> $post = <span class="hl-keyword">null</span>
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">user</span> = <span class="hl-variable">$user</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">post</span> = <span class="hl-variable">$post</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">post</span>(): <span class="hl-type">Post</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">post</span> ?? <span class="hl-keyword">new</span> <span class="hl-type">Post</span>();
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">categories</span>(): <span class="hl-type">Collection</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">Category</span>::<span class="hl-property">allowedForUser</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">user</span>)-&gt;<span class="hl-property">get</span>();
    }
}
</pre>
<p>Let's name a few key features of such a class:</p>
<ul>
<li>All dependencies are injected, this gives the most flexibility to the outside.</li>
<li>The view model exposes some methods that can be used by the view.</li>
<li>There will either be a new or existing post provided by the <code>post</code> method,
depending on whether your creating or editing a post.</li>
</ul>
<p>This is what the controller looks like:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostsController</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">create</span>()
    {
        <span class="hl-variable">$viewModel</span> = <span class="hl-keyword">new</span> <span class="hl-type">PostFormViewModel</span>(
            <span class="hl-property">current_user</span>()
        );
        
        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">blog.form</span>', <span class="hl-property">compact</span>('<span class="hl-value">viewModel</span>'));
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">edit</span>(<span class="hl-injection"><span class="hl-type">Post</span> $post</span>)
    {
        <span class="hl-variable">$viewModel</span> = <span class="hl-keyword">new</span> <span class="hl-type">PostFormViewModel</span>(
            <span class="hl-property">current_user</span>(), 
            <span class="hl-variable">$post</span>
        );
    
        <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">blog.form</span>', <span class="hl-property">compact</span>('<span class="hl-value">viewModel</span>'));
    }
}
</pre>
<p>And finally, it can be used in the view like so:</p>
<pre>&lt;<span class="hl-keyword">input</span> <span class="hl-property">value</span>=&quot;{{ <span class="hl-variable">$viewModel</span>-&gt;<span class="hl-property">post</span>()-&gt;<span class="hl-property">title</span> }}&quot; /&gt;
&lt;<span class="hl-keyword">input</span> <span class="hl-property">value</span>=&quot;{{ <span class="hl-variable">$viewModel</span>-&gt;<span class="hl-property">post</span>()-&gt;<span class="hl-property">body</span> }}&quot; /&gt;

&lt;<span class="hl-keyword">select</span>&gt;
    @foreach ($viewModel-&gt;categories() as $category)
        &lt;<span class="hl-keyword">option</span> <span class="hl-property">value</span>=&quot;{{ <span class="hl-variable">$category</span>-&gt;<span class="hl-property">id</span> }}&quot;&gt;
            {{ <span class="hl-variable">$category</span>-&gt;<span class="hl-property">name</span> }}
        &lt;/<span class="hl-keyword">option</span>&gt;
    @endforeach
&lt;/<span class="hl-keyword">select</span>&gt;
</pre>
<p>These are the two benefits of using view models:</p>
<ul>
<li>They encapsulate the logic</li>
<li>They can be reused in multiple contexts</li>
</ul>
<h2 id="view-models-in-laravel"><a href="#view-models-in-laravel" class="heading-anchor">#</a> View models in Laravel</h2>
<p>The previous example showed a simple class with some methods.
This is enough to use the pattern,
but within Laravel projects, there are a few more niceties we can add.</p>
<p>For example, you can pass a view model directly to the <code>view</code> function if the view model implements <code>Arrayable</code>.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">create</span>()
{
    <span class="hl-variable">$viewModel</span> = <span class="hl-keyword">new</span> <span class="hl-type">PostFormViewModel</span>(
        <span class="hl-property">current_user</span>()
    );
    
    <span class="hl-keyword">return</span> <span class="hl-property">view</span>('<span class="hl-value">blog.form</span>', <span class="hl-variable">$viewModel</span>);
}
</pre>
<p>The view can now directly use the view model's properties like <code>$post</code> and <code>$categories</code>.
The previous example now looks like this:</p>
<pre>&lt;<span class="hl-keyword">input</span> <span class="hl-property">value</span>=&quot;{{ <span class="hl-variable">$post</span>-&gt;<span class="hl-property">title</span> }}&quot; /&gt;
&lt;<span class="hl-keyword">input</span> <span class="hl-property">value</span>=&quot;{{ <span class="hl-variable">$post</span>-&gt;<span class="hl-property">body</span> }}&quot; /&gt;

&lt;<span class="hl-keyword">select</span>&gt;
    @foreach ($categories as $category)
        &lt;<span class="hl-keyword">option</span> <span class="hl-property">value</span>=&quot;{{ <span class="hl-variable">$category</span>-&gt;<span class="hl-property">id</span> }}&quot;&gt;
            {{ <span class="hl-variable">$category</span>-&gt;<span class="hl-property">name</span> }}
        &lt;/<span class="hl-keyword">option</span>&gt;
    @endforeach
&lt;/<span class="hl-keyword">select</span>&gt;
</pre>
<p>You can also return the view model itself as JSON data, by implementing <code>Responsable</code>.
This can be useful when you're saving the form via an AJAX call,
and want to repopulate it with up-to-date data after the call is done.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">update</span>(<span class="hl-injection"><span class="hl-type">Request</span> $request, <span class="hl-type">Post</span> $post</span>)
{
    <span class="hl-comment">// Update the post…</span>

    <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">PostFormViewModel</span>(
        <span class="hl-property">current_user</span>(),
        <span class="hl-variable">$post</span>
    );
}
</pre>
<p>You might see a similarity between view models and Laravel resources.
Remember that resources map one-to-one on a model, when view models may provide whatever data they want.</p>
<p>In one of our projects, we're actually using resources in view models!</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostViewModel</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">values</span>(): <span class="hl-type">array</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">PostResource</span>::<span class="hl-property">make</span>(
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">post</span> ?? <span class="hl-keyword">new</span> <span class="hl-type">Post</span>()
        )-&gt;<span class="hl-property">resolve</span>();
    }
}
</pre>
<p>Finally, in this project we're working with Vue form components, which require JSON data.
We've made an abstraction which provides this JSON data instead of objects or arrays,
when calling the magic getter:</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">ViewModel</span>
{
    <span class="hl-comment">// …</span>
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__get</span>(<span class="hl-injection">$name</span>): <span class="hl-type">?string</span>
    {
        <span class="hl-variable">$name</span> = <span class="hl-type">Str</span>::<span class="hl-property">camel</span>(<span class="hl-variable">$name</span>);
    
        <span class="hl-comment">// Some validation…</span>
    
        <span class="hl-variable">$values</span> = <span class="hl-variable">$this</span>-&gt;{<span class="hl-variable">$name</span>}();
    
        <span class="hl-keyword">if</span> (! <span class="hl-property">is_string</span>(<span class="hl-variable">$values</span>)) {
            <span class="hl-keyword">return</span> <span class="hl-property">json_encode</span>(<span class="hl-variable">$values</span>);
        }
    
        <span class="hl-keyword">return</span> <span class="hl-variable">$values</span>;
    }
}
</pre>
<p>Instead of calling the view model methods, we can call their property and get a JSON back.</p>
<pre>&lt;<span class="hl-keyword">select-field</span>
    <span class="hl-property">label</span>=&quot;{{ <span class="hl-property">__</span>('<span class="hl-value">Post category</span>') }}&quot;
    <span class="hl-property">name</span>=&quot;post_category_id&quot;
    :<span class="hl-property">options</span>=&quot;{{ <span class="hl-variable"><span class="hl-variable">$postViewModel</span></span>-&gt;<span class="hl-property">post_categories</span> }}&quot;
&gt;&lt;/<span class="hl-keyword">select-field</span>&gt;
</pre>
<h3 id="wait,-what-about-view-composers?"><a href="#wait,-what-about-view-composers?" class="heading-anchor">#</a> Wait, what about view composers?</h3>
<p>I hear you! There's a whole separate blog post on that topic.
You can read it <a href="/blog/laravel-view-models-vs-view-composers">here</a>.</p>
<hr />
<p>In summary, view models can be a viable alternative to working with the data directly in a controller.
They allow for better reusability and encapsulate logic that doesn't belong in the controller.</p>
<p>You're also not confined to forms when using them.
At Spatie we also use them to populate facet filter options,
based on a complex context the user is currently working in.</p>
<p>I'd recommend trying this pattern out.
You don't need anything to get started by the way.
All Laravel gimmicks listed above are optional and can be added depending on your use case.</p>
<p>And just in case you'd like to use Laravel gimmicks, we've got a package for it:
<a target="_blank" href="https://github.com/spatie/laravel-view-models">spatie/laravel-view-models</a> 🤗.</p>
 ]]></summary>

                <updated>2018-09-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Eloquent MySQL views ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/eloquent-mysql-views"/>

                <id>https://www.stitcher.io/blog/eloquent-mysql-views</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>MySQL views are a way of storing queries on the database level, and producing virtual tables with them.
In this post we'll look at why you want to use them and how they can be integrated in Laravel with Eloquent models.</p>
<p>If you're already convinced of the power of MySQL views, or just want to know how to implement them in Laravel,
you're free to <a href="#impatient">skip ahead</a>.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="benefits-of-mysql-views"><a href="#benefits-of-mysql-views" class="heading-anchor">#</a> Benefits of MySQL views</h2>
<p>A view in MySQL stores the result of a query in a table-like structure.
You're able to query this view just like you would query a normal table.</p>
<p>The power of views is twofold:</p>
<ul>
<li>Complex queries with joins and unions can be represented as a queryable table on their own.</li>
<li>MySQL is generally smarter than us when it comes to querying data.
Compared to using collections or array functions in PHP, there's a big performance gain.</li>
</ul>
<p>There's also a caveat to using views though.
Depending on the kind of query, MySQL will need to construct an "in memory" table representing the view, at runtime.
This operation is called table materialization and happens when using certain keywords like <code>GROUP BY</code>, or aggregated functions.</p>
<p>The takeaway is that views might actually hurt query performance,
depending on the kind of query you're executing.
As with all things, views are a good solution for some problems, but a terrible idea for others.
Use them wisely, and read up on their restrictions <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/view-restrictions.html">here</a>.</p>
<h2 id="views-and-their-alternatives"><a href="#views-and-their-alternatives" class="heading-anchor">#</a> Views and their alternatives</h2>
<p>Let's look at a real-life example, to demonstrate how we could solve a given problem.</p>
<p>We've got a model <code>MeterReading</code> which logs a meter reading done in an apartment building.
Every unit in the building has its own electricity, water and gas meters.</p>
<p>Every reading is listed in the database with a reference to the unit, the date,
the user doing the reading, the type, and the actual meter value.
Type in this example is <code>electricity</code>, <code>water</code> or <code>gas</code>.</p>
<p>This is what a simplified migration of this table looks like:</p>
<pre><span class="hl-type">Schema</span>::<span class="hl-property">create</span>('<span class="hl-value">meter_readings</span>', <span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">Blueprint</span> $table</span>) {
    <span class="hl-variable">$table</span>-&gt;<span class="hl-property">unsignedInteger</span>('<span class="hl-value">unit_id</span>');
    <span class="hl-variable">$table</span>-&gt;<span class="hl-property">unsignedInteger</span>('<span class="hl-value">user_id</span>');

    <span class="hl-variable">$table</span>-&gt;<span class="hl-property">string</span>('<span class="hl-value">type</span>');
    <span class="hl-variable">$table</span>-&gt;<span class="hl-property">dateTime</span>('<span class="hl-value">date</span>');
    <span class="hl-variable">$table</span>-&gt;<span class="hl-property">unsignedInteger</span>('<span class="hl-value">value</span>');
});
</pre>
<p>Now the client asks us to generate reports based on this raw data.
He wants to see an overview of the units, where every row represents
the readings for that unit, on that day, and whether all readings were done or not.</p>
<p>In short, he wants to see this:</p>
<pre>+---------+---------+------------+-------------+-------+-----+
| unit_id | user_id | date       | electricity | water | gas |
+---------+---------+------------+-------------+-------+-----+
|      14 |      72 | 2018-08-19 |           0 |     1 |   0 |
|      59 |      61 | 2018-08-06 |           0 |     0 |   1 |
|      41 |      64 | 2018-08-02 |           1 |     1 |   1 |
|      41 |      45 | 2018-08-02 |           1 |     1 |   1 |
...
|      41 |      51 | 2018-08-02 |           1 |     1 |   1 |
+---------+---------+------------+-------------+-------+-----+
</pre>
<p>The report show a data set that is grouped by unit, user and day;
and the corresponding readings done for at the time.</p>
<p>Here are a few ways of generating this report.</p>
<h3 id="on-the-fly"><a href="#on-the-fly" class="heading-anchor">#</a> On the fly</h3>
<p>We always query all the data, and group it in our code.
This is the most easy way of doing it, but has some downsides:</p>
<ul>
<li>PHP and Laravel collections are slow, compared to the optimised algorithms MySQL can use.</li>
<li>Building a virtual data set means you'll have to manually implement pagination. One row can represent multiple models.</li>
<li>You're adding a lot of code to manage that special collection of readings.</li>
</ul>
<h3 id="using-a-raw-query"><a href="#using-a-raw-query" class="heading-anchor">#</a> Using a raw query</h3>
<p>We can of course skip PHP and build the raw query to fully use the power of MySQL.
While this solves the performance issue, we're still working with a custom data set which can't make use of standard pagination.
Also, you're now maintaining a big SQL query somewhere in your code.
It's probably a string somewhere in PHP, or –slightly better– a separate sql file.</p>
<h3 id="projecting-the-changes"><a href="#projecting-the-changes" class="heading-anchor">#</a> Projecting the changes</h3>
<p>We could make a separate model called <code>MeterReadingReport</code>,
and use event hooks on <code>MeterReading</code> to manage these reports.</p>
<p>Every time a reading is added, we can get or create a report for that unit, day and user;
and update the data accordingly.</p>
<p>Now there's a separate model that's simple to query.
There's no more performance impact and the pagination issue is also solved.</p>
<p>But on the other hand, there's a lot more code to manage these event hooks.
Creating reports is one thing, but what if a reading is updated or deleted?
That's a lot of complexity we need to manage.</p>
<p>Projecting events into other models isn't a bad idea though.
It's one of the key features in event sourcing.
If you've got the right setup, making projectors would definitely be an option.</p>
<p>While we do have a package that handles this exact use case (<a target="_blank" href="https://github.com/spatie/laravel-event-projector">laravel-event-projector</a>),
it seemed overkill for this use case;
especially since there are a lot of other "normal" models in this project.</p>
<h3 id="finding-the-middle-ground"><a href="#finding-the-middle-ground" class="heading-anchor">#</a> Finding the middle ground</h3>
<p>Looking at all the possible solutions, we can make a simple list of requirements:</p>
<ul>
<li>As less overhead as possible in the code base.</li>
<li>Good performance.</li>
<li>Be able to use the standard Laravel features without any workarounds.</li>
</ul>
<p>MySQL views are this perfect middle ground.
Let's look at how they are implemented.</p>
<p><a name="impatient"></a></p>
<h2 id="sql-views-in-laravel"><a href="#sql-views-in-laravel" class="heading-anchor">#</a> SQL views in Laravel</h2>
<p>To work with a view, we'll have to first create a query that can build this view.
While many people are scared of SQL –modern ORMs made us way too lazy– I find it a lot of fun.</p>
<p>Beware that I'm no SQL master, so there might be things that could be done better.
I also won't explain what this query does exactly, as it'll be different for your use case.</p>
<p>In this case, it generates the table listed above. This is it:</p>
<pre><span class="hl-keyword">SELECT</span> 
    unit_id
    , <span class="hl-property">user_id</span>
    , <span class="hl-property">DATE_FORMAT</span>(`date`, '<span class="hl-value">%Y-%m-%d</span>') <span class="hl-keyword">AS</span> <span class="hl-type">day</span>
    , <span class="hl-property">COUNT</span>(<span class="hl-keyword">CASE</span> <span class="hl-keyword">WHEN</span> type = '<span class="hl-value">electricity</span>' <span class="hl-keyword">THEN</span> type <span class="hl-keyword">END</span>) 
        <span class="hl-keyword">AS</span> `electricity`
    , <span class="hl-property">COUNT</span>(<span class="hl-keyword">CASE</span> <span class="hl-keyword">WHEN</span> type = '<span class="hl-value">water</span>' <span class="hl-keyword">THEN</span> type <span class="hl-keyword">END</span>) 
        <span class="hl-keyword">AS</span> `water`
    , <span class="hl-property">COUNT</span>(<span class="hl-keyword">CASE</span> <span class="hl-keyword">WHEN</span> type = '<span class="hl-value">gas</span>' <span class="hl-keyword">THEN</span> type <span class="hl-keyword">END</span>) 
        <span class="hl-keyword">AS</span> `gas`
    
<span class="hl-keyword">FROM</span> 
    meter_readings
    
<span class="hl-keyword">GROUP BY</span>
    unit_id
    , <span class="hl-property">user_id</span>
    , <span class="hl-property">day</span>
;
</pre>
<p>It's very easy to build this query in your favourite SQL browser,
and afterwards plug it into your project.</p>
<p>How to plug it in, you ask? Very simple, with a migration.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">up</span>()
{
    <span class="hl-type">DB</span>::<span class="hl-property">statement</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">dropView</span>());
    
    <span class="hl-type">DB</span>::<span class="hl-property">statement</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">createView</span>());
}
</pre>
<p>First of all, <code>dropView</code> is required, because Laravel only drops tables when doing a fresh migration.
It's as simple as this:</p>
<pre>    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">dropView</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">SQL</span></span><span class="hl-injection">
<span class="hl-keyword">DROP VIEW</span> IF <span class="hl-keyword">EXISTS</span> `meter_reading_reports`;
</span><span class="hl-property"><span class="hl-property">SQL</span></span>;
    }
</pre>
<p>You notice I prefer Heredoc in these cases, a separate SQL file is of course equally good.</p>
<p>Michael Dyrynda pointed out to me that there's a <code>--drop-views</code> flag you can pass to the migrate command.
So, technically, this manual dropping isn't required.
I prefer this way though, because now we don't have to remember to add the extra flag.</p>
<p>Next up, the <code>createView</code> method returns the query, with some added syntax.
I've shortened the sample a bit, but you get the point.</p>
<pre>    <span class="hl-keyword">private</span> <span class="hl-keyword">function</span> <span class="hl-property">createView</span>(): <span class="hl-type">string</span>
    {
        <span class="hl-keyword">return</span> &lt;&lt;&lt;<span class="hl-property"><span class="hl-property">SQL</span></span><span class="hl-injection">
<span class="hl-keyword">CREATE VIEW</span> `meter_reading_reports` <span class="hl-keyword">AS</span>

<span class="hl-keyword">SELECT</span> <span class="hl-comment">/* … The query */</span>
</span><span class="hl-property"><span class="hl-property">SQL</span></span>;
    }
</pre>
<p>Sidenote: I'm very much looking forward to PHP 7.3 and <a href="/blog/new-in-php-73">flexible Heredoc syntax</a>.</p>
<p>Now that we have a migration in place, all else just works like normal Laravel!</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MeterReadingReport</span> <span class="hl-keyword">extends</span> <span class="hl-type">Model</span>
{
    <span class="hl-keyword">protected</span> <span class="hl-property">$casts</span> = [
        '<span class="hl-value">day</span>' =&gt; '<span class="hl-value">date</span>',
    ];
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">unit</span>(): <span class="hl-type">BelongsTo</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">belongsTo</span>(<span class="hl-type">Unit</span>::<span class="hl-keyword">class</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">user</span>(): <span class="hl-type">BelongsTo</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">belongsTo</span>(<span class="hl-type">User</span>::<span class="hl-keyword">class</span>);
    }
}
</pre>
<p>We're using a simple model, without any workarounds whatsoever.
Relations work just like normal, casting like you're used to,
pagination works like it should be, and there no more performance impact.</p>
<p>The only thing that's not possible is of course writing to a view.
It is actually possible to do it in MySQL, but completely irrelevant to our use case.</p>
<p>Maybe you can already see some use cases where MySQL views might be useful?
Maybe you have a followup question or remark?
I'd love to hear from you!
You can reach me on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2018-08-27T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The web in 2045 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/the-web-in-2045"/>

                <id>https://www.stitcher.io/blog/the-web-in-2045</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>On August 6 1991, Sir Tim Berners-Lee put the world's first website online.
It's been 27 years since that first website has been reachable via the world wide web.
With the massive progression we've seen throughout the web's lifetime,
I can't help but wonder what will happen in the next 27 years, what the web will look like in 2045.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="a-brief-history"><a href="#a-brief-history" class="heading-anchor">#</a> A brief history</h2>
<p>What better way to know the future, than to look at the past?
There's an excellent blog called "<a target="_blank" href="https://thehistoryoftheweb.com/archives/">The History Of The Web</a>".
Thanks to Jay Hoffman, the writer of the blog,
I've been fascinated by the roots of the web.</p>
<p>On August 6, 1991 Tim Berners-Lee puts the first website online.
A few months later, on October 29 of the same year,
the first HTML draft is posted on the <em>www-talk</em> mailing list.</p>
<p>Three years went by until Netscape Navigator, the most popular browser at the time,
was released on October 13, 1994.
It took Microsoft almost a year longer to release their own Internet Explorer 1 on August 15 of 1995.
In December of 1996, the first iteration for CSS was conceptualised.</p>
<p>Mozilla released Firefox more than ten years after the beginning of the web in 2004.
Only a few years later, Apple flipped the web to its mobile side
by presenting the very first iPhone on January 8, 2007.</p>
<p>Twenty-three years after the first mention of HTML
modern websites found their identity as we know it today,
when HTML5 was made the formal recommendation by the W3C on October 28, 2014.</p>
<p>It's amazing to see how the web has evolved in less than three decades.
Not only its technical boundaries were pushed;
people also kept finding innovating ways for what the technology was used for.
Think about sites like GeoCities or NeoPets; the first blog post written in <em>1997</em>;
or some recent examples like <a target="_blank" href="https://i.redd.it/agcbmqgjn14z.png">/r/place</a> on Reddit
and an experience beyond words crafted by <a target="_blank" href="https://www.sbnation.com/a/17776-football">SB Nation</a>.</p>
<h2 id="today"><a href="#today" class="heading-anchor">#</a> Today</h2>
<p>While the web's primary focus was to distribute content,
its users have shaped it into a completely different, broader platform.</p>
<p>It's only in more recent years that we've been able to observe – and be part of –
the unique phenomenon of the JavaScript world.
While the language has been around since the nineties,
it were frameworks like Ember, Backbone and Angular that opened a whole new area the web could grow in.</p>
<p>It's impossible to pinpoint an exact date on when people started looking at JavaScript as something more
than a simple scripting language. But there are a few milestones worth mentioning.</p>
<ul>
<li>jQuery's initial release in August, 2006.</li>
<li>AngularJS was released in October, 2010.</li>
<li>React saw the light in March, 2013.</li>
</ul>
<p>Especially with the modern frameworks, better syntax was required;
and projects like Babel came into view.
This is where it starts to get real interesting: JavaScript in the browser becoming a compilation target,
for <em>other</em> languages and supersets.</p>
<p>Gary Bernhardt, a well known public speaker;
said that, in order for JavaScript to become as successful as it is today,
it had to really suck.
It's only then that people start investing in alternatives.
And when JavaScript is the <em>only</em> thing that runs in the browsers,
people are really forced to think out of the box.</p>
<p>With the arrival of frontend frameworks in JavaScript,
people needed to start investing in performance.
On the one hand, browser vendors are doing amazing things with their JavaScript engines.
On the other hand, one of the most creative, out of the box thinking solutions;
must have been asm.js.</p>
<p>Here you have an optimised subset of JavaScript; being able to run, for example, a 3D game engine—in the browser.
With asm.js, and Web Assembly following; web technologies can be used for yet another, completely different goal.</p>
<p>It begs the question: "what is the web?"</p>
<p>The technologies the web was built upon: HTTP, HTML, CSS and JavaScript,
became technologies to make applications and games;
some of the programs we use to build the web,
are built on these same technologies themselves.</p>
<p>Does "the web today" refer to all these technologies and creations,
or just a collection of connected documents, built on top of the same technologies?
Is the browser's goal still just that: browsing documents;
or has it become a platform for all kinds of things, whatever we can imagine?</p>
<h2 id="2045"><a href="#2045" class="heading-anchor">#</a> 2045</h2>
<p>With the web advancing so fast,
one can only wonder what it will look like a few decades from now.</p>
<p>One of the key changes could be the sandbox we're all using today: the browser.
Will applications stay confined to that browser window,
or will they break free and live as first-class programs on your operating system?</p>
<p>The mobile world is already moving in this direction with progressive web apps.
Chrome OS was completely built on top of the web, independent of the browser.
But, some might argue, it was too ahead of its time.</p>
<p>Imagine a world where web apps can be "installed" via an app store;
where you don't need bookmarks or URLs anymore, but simply open an app, like we open the browser today.
Obviously, being built on top of the web; these apps don't need to be installed, they just work, everywhere.</p>
<p>Imagine JavaScript and DOM engines baked into operating systems.
No more Electron or Java for easy cross-platform programming.
All programs can be shared, everything will be interconnected.</p>
<p>And once all that is achieved, someone will come along, claiming a new invention:
a simple web app for browsing and sharing content…</p>
<hr />
<p>Hi, thanks for reading! What's your view for the web in 2045?
Feel free to share your thoughts on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>,
I'd love to chat!</p>
<p>And if you're reading this in 2045:
what's your opinion on this blog post, looking back?
Where will the web be in, say, another 27 years?</p>
 ]]></summary>

                <updated>2018-08-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Service locator: an anti-pattern ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/service-locator-anti-pattern"/>

                <id>https://www.stitcher.io/blog/service-locator-anti-pattern</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>As a Laravel developer, I'm confronted daily with the service locator pattern.
Every facade call and several helper functions are built upon it.</p>
<p>Let's take a look at a common facade call: <code>Auth::user()</code>.
The <code>Auth</code> facade will reach into Laravel's service container, grab the registered component,
and forward the static call to that component.
In this case, it'll return the logged in user.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>During a discussion with my colleagues, I found it difficult to put into words
what exactly is wrong with grabbing things out of the container –a service locator– so I decided to write my thoughts down,
with an example: a class <code>CreatePostAction</code> which is tasked to create a blog post,
based on a set of parameters.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreatePostAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title, 
        <span class="hl-type">string</span> $body
    </span>): <span class="hl-type">Post</span>
    {
        <span class="hl-keyword">return</span> <span class="hl-type">Post</span>::<span class="hl-property">create</span>([
            '<span class="hl-value">title</span>' =&gt; <span class="hl-variable">$title</span>,
            '<span class="hl-value">body</span>' =&gt; <span class="hl-variable">$body</span>,
            '<span class="hl-value">author_id</span>' =&gt; <span class="hl-type">Auth</span>::<span class="hl-property">user</span>()-&gt;<span class="hl-property">id</span>,
        ]);
    }
}
</pre>
<p>I want to highlight three problems with this approach, directly caused by the use of a service locator.</p>
<ul>
<li>There's a bigger chance of runtime errors.</li>
<li>The code is obfuscated to the outside.</li>
<li>It increases cognitive load.</li>
</ul>
<p>Let's look at these problems, one by one.</p>
<h2 id="runtime--instead-of-compile-time-errors"><a href="#runtime--instead-of-compile-time-errors" class="heading-anchor">#</a> Runtime- instead of compile time errors</h2>
<p>Before even looking into this first problem, there's one assumption I'll make.
That is that, as a developer, you prefer to know bugs in your code as early as possible,
so that you can fix them as early as possible.</p>
<p>I'll assume that you don't like a situation where a client tells you a production project is broken,
and the issue can only be reproduced by taking several steps.</p>
<p>As the name says, runtime errors can only be discovered by running the program.
Truth be told: PHP, being an interpreted language; highly leans towards these kind of errors.
You cannot know if a PHP program will work before running it.</p>
<p>There's nothing wrong with that, but my argument here is that every place we can
avoid these errors, we should.</p>
<p>Compile time errors are errors that can be detected without running the code.
For example: in your IDE or using a static analysis tool.
The benefit is that you know a piece of code will absolutely work,
even without testing it.</p>
<p>Let's put that into practice. What does <code>Auth::user()</code> return?
A logged in <code>User</code>—most of the time.</p>
<p>Our action class doesn't know anything about the system it lives in,
except the things we tell it.
This means that, when calling <code>Auth::user()-&gt;id</code>,
we assume that the surrounding system has a logged in user, with an <code>id</code>.</p>
<p>Of course, your first thought is that we <em>know</em> there's a user,
because this action is called within a controller that requires a logged in user.
I'll come back to that argument later on.</p>
<p>For now, speaking from a mathematical point of view,
it's impossible to prove whether <code>Auth::user()-&gt;id</code> will work, without running it.
There are two ways to fix it, from the action's perspective.</p>
<p>By doing a runtime check:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreatePostAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title, 
        <span class="hl-type">string</span> $body
    </span>): <span class="hl-type">Post</span>
    {
        <span class="hl-keyword">if</span> (! <span class="hl-type">Auth</span>::<span class="hl-property">user</span>()) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">Exception</span>('<span class="hl-value">…</span>');
        }
        
        <span class="hl-comment">// ...</span>
    }
}
</pre>
<p>Or by requiring a valid user, before executing:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreatePostAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title, 
        <span class="hl-type">string</span> $body,
        <span class="hl-type">User</span> $author
    </span>): <span class="hl-type">Post</span>
    {
        <span class="hl-comment">// ...</span>
    }
}
</pre>
<p>I <em>know</em> you have arguments why this will never happen and I shouldn't be worried about it;
I'll address those arguments soon.</p>
<h2 id="obfuscated-classes"><a href="#obfuscated-classes" class="heading-anchor">#</a> Obfuscated classes</h2>
<p>Before looking at the biggest problem, how service locators affect cognitive load;
there's the issue with obfuscated classes.
Let's look at our action's definition.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreatePostAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title, 
        <span class="hl-type">string</span> $body
    </span>): <span class="hl-type">Post</span>
    { <span class="hl-comment">/* ... */</span> }
}
</pre>
<p>I've blogged and spoken about this a lot already:
developers don't read every line of code, they scan it.</p>
<p>At the time of writing the code, it all seems obvious:
you <em>know</em> a blog post requires a logged in user.
However, for the developer working in your legacy code, that intent is not clear.
Not unless he's reading every single line of code.</p>
<p>Imagine being that person: having to work in a legacy project where you need to read every line of code,
in order to get the general idea of what's happening.</p>
<p>You might as well not be interested in the specifics of how a post is created,
you just want to know what's required to do so.
There's two ways to solve this issue.</p>
<p>Either be using docblocks;
meaning a lot more work for both the author and reader, and it clutters your code:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreatePostAction</span>
{
    <span class="hl-comment">/**
     * This action will create a post, 
     * and attach the logged in user as its author.
     *
     * <span class="hl-value">@param</span> <span class="hl-type">string</span> <span class="hl-variable">$title</span>
     * <span class="hl-value">@param</span> <span class="hl-type">string</span> <span class="hl-variable">$body</span>
     *
     * <span class="hl-value">@return</span> <span class="hl-type">Post</span>
     */</span>
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title, 
        <span class="hl-type">string</span> $body
    </span>): <span class="hl-type">Post</span>
    { <span class="hl-comment">/* ... */</span> }
}
</pre>
<p>Or by injecting the user:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreatePostAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title, 
        <span class="hl-type">string</span> $body,
        <span class="hl-type">User</span> $author
    </span>): <span class="hl-type">Post</span>
    { <span class="hl-comment">/* ... */</span> }
}
</pre>
<p>Which one do you prefer?
Remember: from the perspective of the person working in a legacy project,
and it's not just one class, there are dozens and dozens.</p>
<h2 id="increased-cognitive-load"><a href="#increased-cognitive-load" class="heading-anchor">#</a> Increased cognitive load</h2>
<p>This all leads up to the final, and major, problem: cognitive load.
I already wrote a lot on this topic, and I'll share some links at the end of this post.</p>
<p>The important question, which counters most of the pro-arguments for service locators;
is how much brain effort you, the developer, has to spend on trivial questions like:</p>
<blockquote>
<p>How sure am I this code will actually work?</p>
</blockquote>
<p>Let's look at the most basic example: <code>Auth::user()-&gt;id</code>.
I work on Laravel projects and admit to have used this piece of code numerous times.
Here's a non-exhaustive list of questions popping into my head when writing this code:</p>
<ul>
<li>Am I sure a user is logged in at this point?</li>
<li>Should I add an extra check, to be sure?</li>
<li>What context will this method be called from?</li>
<li>Are there any future features in the project's scope I need to take into account?</li>
<li>Should I add a test to be sure this never breaks in the future?</li>
</ul>
<p>These are all such trivial questions,
and I need to think about them <em>every</em> time I use a facade.
How much more easy is it to simply say:</p>
<blockquote>
<p>I <em>need</em> the logged in user to do this action, and the context which is calling this action can figure it out from there.</p>
</blockquote>
<pre><span class="hl-keyword">class</span> <span class="hl-type">CreatePostAction</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__invoke</span>(<span class="hl-injection">
        <span class="hl-type">string</span> $title, 
        <span class="hl-type">string</span> $body,
        <span class="hl-type">User</span> $author
    </span>): <span class="hl-type">Post</span>
    { <span class="hl-comment">/* ... */</span> }
}
</pre>
<p>Sure, compile time errors and less code are niceties,
but my main problem is this cognitive load.
I don't want to ask all these questions every time I use a facade.</p>
<p>Seasoned Laravel developers will tell me this is the way the framework works and we should embrace it.
They are right, of course.
But making the assumption that "it will work" isn't good enough for me.
At least, it's no argument against increased cognitive load,
as you're still left with a lot of questions about the surrounding context.</p>
<h2 id="dependency-injection-solves-it"><a href="#dependency-injection-solves-it" class="heading-anchor">#</a> Dependency injection solves it</h2>
<p>Dependency injection, of course; fixes this.
It's a pattern which allows for inversion of control and clarifies intent.
It's also perfectly possible to do proper DI in Laravel;
and, in my opinion, we should do it more.</p>
<p>I've written about DI before, feel free to read up on it <a href="/blog/dependency-injection-for-beginners">here</a>.
I also recently gave a talk about cognitive load, from a visual perspective.
You can find it <a href="/blog/visual-perception-of-code">here</a>.</p>
 ]]></summary>

                <updated>2018-08-10T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The Visual Perception of Code ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/visual-perception-of-code"/>

                <id>https://www.stitcher.io/blog/visual-perception-of-code</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>How do we read code? Are there things we can do to make that reading more easy?
I recently gave a talk about this exact topic.</p>
<p>In this talk, I gave six pointers to improve this visual perception,
to make it easier to read your own code: fonts, code folding, colours, patterns, documentation and names.</p>
<p>These are the links mentioned in the video:</p>
<ul>
<li>
<a href="/blog/a-programmers-cognitive-load">A programmer's cognitive load</a>
</li>
<li>
<a href="/blog/mastering-key-bindings">Mastering key bindings</a>
</li>
<li>
<a href="/blog/where-a-curly-bracket-belongs">Where a curly bracket belongs</a>
</li>
</ul>
<p>The colour scheme used is a port of Mozilla's Photon Light theme.
Here's the <a target="_blank" href="https://github.com/brendt/photon-light">PHPStorm version</a>.</p>
<p>
<iframe width="560" height="400" src="https://www.youtube.com/embed/5qRFxMCEbLs?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</p>
<p>I you have any thoughts coming to mind, if you want to discuss this further
or tell me I'm wrong;
you can reach me on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2018-06-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Scopes in JetBrains IDEs ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/phpstorm-scopes"/>

                <id>https://www.stitcher.io/blog/phpstorm-scopes</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Any JetBrains IDE has an amazing feature that can significantly improve your development experience; whether it's PhpStorm, WebStorm, IntelliJ IDEA, PyCharm, or any other project; this feature enables better search and allows for custom file colours.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>For example, this is what I'm talking about:</p>
<p><img src="/resources/img/blog/phpstorm-coloured-scopes/tree-view.png" srcset="/resources/img/blog/phpstorm-coloured-scopes/tree-view-372x600.png 372w, /resources/img/blog/phpstorm-coloured-scopes/tree-view-646x1043.png 646w, /resources/img/blog/phpstorm-coloured-scopes/tree-view-527x851.png 527w, /resources/img/blog/phpstorm-coloured-scopes/tree-view-834x1347.png 834w, /resources/img/blog/phpstorm-coloured-scopes/tree-view-745x1203.png 745w" sizes="" alt="A tree view configured with coloured scopes"><em class="small center">A tree view configured with coloured scopes</em></img></p>
<p>These colours allow you to easily recognise files,
and that in turn allow you to think more freely about things that really matter when coding.
First you'll want to configure one or more scopes.
A scope is a set of textual filters that are applied on your files, you can configure them by going to <code>Settings &gt; Scopes</code>.</p>
<p><img src="/resources/img/blog/phpstorm-coloured-scopes/scope-configuration.png" srcset="/resources/img/blog/phpstorm-coloured-scopes/scope-configuration-1546x529.png 1546w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1976x812.png 0w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-883x362.png 0w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1530x628.png 0w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-1996x684.png 1996w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-1785x611.png 1785w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1249x513.png 0w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended.png 0w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-892x305.png 892w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-1262x432.png 1262w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1767x726.png 0w" sizes="" alt=""></img></p>
<p>You can use the buttons to include and exclude folders and files,
or you can write the filters yourself.
There's a special syntax to do that, you can read about it described <a target="_blank" href="https://www.jetbrains.com/help/phpstorm/scope-language-syntax-reference.html">here</a>. Don't forget you can expand the text area for easier configuration:</p>
<p><img src="/resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended.png" srcset="/resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1976x812.png 1976w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-883x362.png 883w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1530x628.png 1530w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1249x513.png 1249w, /resources/img/blog/phpstorm-coloured-scopes/scope-configuration-extended-1767x726.png 1767w" sizes="" alt=""></img></p>
<h2 id="file-colours"><a href="#file-colours" class="heading-anchor">#</a> File colours</h2>
<p>Every scope can be applied a specific colour.
This makes it easy to easily spot files.</p>
<p><img src="/resources/img/blog/phpstorm-coloured-scopes/file-colours.png" srcset="/resources/img/blog/phpstorm-coloured-scopes/file-colours-1767x692.png 1767w, /resources/img/blog/phpstorm-coloured-scopes/file-colours-1249x489.png 1249w, /resources/img/blog/phpstorm-coloured-scopes/file-colours-883x345.png 883w, /resources/img/blog/phpstorm-coloured-scopes/file-colours-1976x774.png 1976w, /resources/img/blog/phpstorm-coloured-scopes/file-colours-1530x599.png 1530w" sizes="" alt=""></img></p>
<p>By applying colours to a scope, you'll see them in the tree view,
in file tabs and when using file navigation.</p>
<p><img src="/resources/img/blog/phpstorm-coloured-scopes/tab-colours.png" srcset="/resources/img/blog/phpstorm-coloured-scopes/tab-colours-991x34.png 991w, /resources/img/blog/phpstorm-coloured-scopes/tab-colours-1214x42.png 1214w, /resources/img/blog/phpstorm-coloured-scopes/tab-colours-1402x49.png 1402w, /resources/img/blog/phpstorm-coloured-scopes/tab-colours-1568x54.png 1568w, /resources/img/blog/phpstorm-coloured-scopes/tab-colours-701x24.png 701w" sizes="" alt=""></img></p>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<h2 id="filtering-by-scope"><a href="#filtering-by-scope" class="heading-anchor">#</a> Filtering by scope</h2>
<p>Besides colours, scopes also allow for easy filtering. For example, in the tree view:</p>
<p><img src="/resources/img/blog/phpstorm-coloured-scopes/tree-filter.png" srcset="/resources/img/blog/phpstorm-coloured-scopes/tree-filter-466x248.png 466w, /resources/img/blog/phpstorm-coloured-scopes/tree-filter-933x496.png 933w, /resources/img/blog/phpstorm-coloured-scopes/tree-filter-1044x556.png 1044w, /resources/img/blog/phpstorm-coloured-scopes/tree-filter-660x351.png 660w, /resources/img/blog/phpstorm-coloured-scopes/tree-filter-808x430.png 808w" sizes="" alt="File colours"><em class="small center">File colours</em></img></p>
<p>But also in the finder:</p>
<p><img src="/resources/img/blog/phpstorm-coloured-scopes/finder.png" srcset="/resources/img/blog/phpstorm-coloured-scopes/finder-935x252.png 935w, /resources/img/blog/phpstorm-coloured-scopes/finder-2092x566.png 2092w, /resources/img/blog/phpstorm-coloured-scopes/finder-1871x506.png 1871w, /resources/img/blog/phpstorm-coloured-scopes/finder-1323x357.png 1323w, /resources/img/blog/phpstorm-coloured-scopes/finder-1620x438.png 1620w" sizes="" alt="File colours"><em class="small center">File colours</em></img></p>
<h2 id="defaults"><a href="#defaults" class="heading-anchor">#</a> Defaults</h2>
<p>Setting up scopes shouldn't take longer than 10 minutes every project,
and saves a lot of time in the long run.
There's also the possibility to set default options though,
which will be used every every time you create a new project.
Go to <code>File &gt; New Project Settings &gt; Preference for New Projects</code> and configure your default scopes and colours over there, the same way you'd do as explained before.</p>
<p>And just in case you'd need some inspiration, these are my default scopes:</p>
<pre>App
file:app//*||file:config//*||file:routes//*||file:app||file:config||file:routes||file:src//*||file:src

Resources
file:resources//*||file:resources

Database
file:database//*||file:database
</pre>
 ]]></summary>

                <updated>2020-09-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Acquisition by giants ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/acquisition-by-giants"/>

                <id>https://www.stitcher.io/blog/acquisition-by-giants</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Yesterday, Microsoft acquired GitHub.
I don't think GitHub is in any immediate danger of becoming obsolete or feature bloated.
But we should think about what this acquisition, one of many; means.</p>
<p>I say many, because GitHub isn't by far Microsoft's first big acquisition.
Think of Skype and Nokia a few years back, or Linkedin and Minecraft more recently.
Who can blame them?
It's only natural that a company continues to look for ways to improve their market footprint,
especially in the tech world.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>But now what? GitHub becomes one of the many products swallowed by tech giants.
It will become even more difficult for smaller products to stand a competing chance.
Should we, the tech industry, be worried about big monopolies growing larger and larger?</p>
<h2 id="embrace,-extend,-and-extinguish"><a href="#embrace,-extend,-and-extinguish" class="heading-anchor">#</a> Embrace, extend, and extinguish</h2>
<p>What better way to look at the future, than to look at the past?
Many will say Microsoft isn't deploying their "embrace, extend, and extinguish" strategy anymore;
but are they?</p>
<p>Here's what this strategy means, from <a target="_blank" href="https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish">wikipedia</a>.</p>
<ul>
<li>Embrace: Development of software substantially compatible with a competing product,
or implementing a public standard.</li>
<li>Extend: Addition and promotion of features not supported by the competing product or part of the standard,
creating interoperability problems for customers who try to use the 'simple' standard.</li>
<li>Extinguish: When extensions become a de facto standard because of their dominant market share,
they marginalize competitors that do not or cannot support the new extensions.</li>
</ul>
<p>It sounds like a smart strategy.
It may not be called like this anymore but it seems reasonable that,
if Microsoft still wants to grow; they must look at how to outgrow their competitors.</p>
<p>We've seen them <strong>embracing</strong> a lot of technologies and platforms recently.
Think of open sourcing .NET, developing VSCode, embedding Linux etc.
Microsoft is doing a lot of good for the open source community lately,
but you can't help but think they are also serving their own agenda while at it.</p>
<p>It's only guessing what Microsoft will do to <strong>extend</strong> GitHub,
but we've already seen a lot of nice features added to other acquired products.
Growing them to, indeed, part of the standard.</p>
<p>Let's not forget the obvious example though: VSCode, a direct competitor to GitHub's Atom editor.
Both are built on the same technology: Electron, managed by GitHub.</p>
<p>So will the tech community allow a giant to <strong>extinguish</strong> all its competitors?
Time will tell.</p>
<h2 id="the-drive-for-innovation"><a href="#the-drive-for-innovation" class="heading-anchor">#</a> The drive for innovation</h2>
<p>Thinking back 20 years ago, the browser wars were raging.
There was a lot of competition, and with that competition came innovation.
We must not forget that it was this period of rivalry between many different players,
that lead to the web platform we have today.
And it's a platform that grew beyond the wildest expectations of these first pioneers.</p>
<p>So we must wonder: what if there's less and less competition in the tech world?
What if the giants, Microsoft, Apple, Amazon, Google and Facebook; only grow larger and larger?
What does it mean for innovation?</p>
<p>It's worrisome to see that in the startup culture,
it's actually one of the biggest questions right at the beginning: "what's our exit strategy?"
The goal of almost every startup, from the start, is to be absorbed by a bigger company, in just a few years.</p>
<p>The drive for innovation gets replaced by the need for money.
But we cannot afford stagnation.
We must be aware that this, still very young, industry
has very large odds of becoming the same as so many others.</p>
<p>To me, these are the thoughts behind GitHub's acquisition.
And yes, they are scary.</p>
 ]]></summary>

                <updated>2018-06-05T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Liskov and type safety ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/liskov-and-type-safety"/>

                <id>https://www.stitcher.io/blog/liskov-and-type-safety</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been fascinated by type systems in programming languages for a while now.
Recently, something clicked for me about inheritance and types.</p>
<p>Not only did it clarify type variance,
I also understood what the Liskov substitution principle actually is about.
Today, I'm going to share these insights with you.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="prerequisites"><a href="#prerequisites" class="heading-anchor">#</a> Prerequisites</h2>
<p>I'll be writing pseudo code to make clear what I'm talking about.
So let's make sure you know what the syntax of this pseudo code will be.</p>
<p>A function is defined like so.</p>
<pre>foo(T) : void

bar(S) : T
</pre>
<p>First comes the function name, second the argument list with types as parameters,
and finally the return type.
When a function returns nothing, it's indicated as <code>void</code>.</p>
<p>A function can extend — overwrite — another function, as can types.
Inheritance is defined like so.</p>
<pre>bar &gt; baz(S) : T

T &gt; S
</pre>
<p>In this example, <code>baz</code> extends <code>bar</code>, and <code>S</code> is a subtype of <code>T</code>.
The last step is being able to invoke the function, which is done like so.</p>
<pre>foo(T)

a = bar(S)
</pre>
<p>Once again: it's all pseudo code and I'll use it to show what types are,
how they can and cannot be defined in combination with inheritance, and
how this results in type-safe systems.</p>
<h2 id="liskov-substitution-principle"><a href="#liskov-substitution-principle" class="heading-anchor">#</a> Liskov substitution principle</h2>
<p>Let's look at the official definition of the LSP.</p>
<blockquote>
<p>If <code>S</code> is a subtype of <code>T</code>, then objects of type <code>T</code> may be replaced with objects of type <code>S</code>
<br>—<a target="_blank" href="https://en.wikipedia.org/wiki/Liskov_substitution_principle">Wikipedia</a></p>
</blockquote>
<p>Instead of using <code>S</code> and <code>T</code>, I'll be using more concrete types in my examples.</p>
<pre>Organism &gt; Animal &gt; Cat
</pre>
<p>These are the three types we'll be working with.
Liskov tells us that wherever objects of type <code>Organism</code> appear in our code,
they must be replaceable by subtypes like <code>Animal</code> or <code>Cat</code>.</p>
<p>Let's say there's a function used to <code>feed</code> an <code>Organism</code>.</p>
<pre>feed(Organism) : void
</pre>
<p>It must be possible to call it like so:</p>
<pre>feed(Animal)
feed(Cat)
</pre>
<p>Try to think of function definition as a contract, a promise; for the programmer to be used.
The contract states:</p>
<blockquote>
<p>Given an object of the type <code>Organism</code>,
I'll be able to execute and <code>feed</code> that <code>Organism</code>.</p>
</blockquote>
<p>Because <code>Animal</code> and <code>Cat</code> are subtypes of <code>Organism</code>,
the LSP states that this function should also work when one of these subtypes are used.</p>
<p>This brings us to one of the key properties of inheritance.
If Liskov states that objects of type <code>Organism</code> must be replaceable by objects of type <code>Animal</code>,
it means that <code>Animal</code> may not change the expectations we have of <code>Organism</code>.
<code>Animal</code> may extend <code>Organism</code>, meaning it may <em>add</em> functionality,
but <code>Animal</code> may not change the certainties given by <code>Organism</code>.</p>
<p>This is where many OO programmers make mistakes.
They see inheritance more like
"re-using parts of the parent type, and overriding other parts in the sub-type",
rather than extending the behaviour defined by its parent.
This is what the LSP guards against.</p>
<h2 id="benefits-of-the-lsp"><a href="#benefits-of-the-lsp" class="heading-anchor">#</a> Benefits of the LSP</h2>
<p>Before exploring the details of type safety with inheritance,
we should stop and ask ourselves what's to gain by following this principle.
I've explained what Barbara Liskov meant when she defined it,
but why is it necessary? Is it bad to break it?</p>
<p>I mentioned the idea of a "promise" or "contract".
If a function or type makes a promise about what it can do,
we should be able to blindly trust it.
If we can't rely on function <code>feed</code> being able to feed all <code>Organisms</code>,
there's a piece of undocumented behaviour in our code.</p>
<p>If we know that the LSP is respected, there's a level of security.
We may trust that this function will do the thing we expect;
even without looking at the implementation of that function.
When the contract is breached, however; there's a chance of runtime errors
that both the programmer and the compiler could not –or did not– anticipate for.</p>
<p>In the above examples, we looked at respecting the LSP form the developer's point of view.
There's another party involved though: a language's type system.
A language can be designed in a type-safe way or not.
Types are the building blocks to mathematically proof whether a function will do the thing you want it to do.</p>
<p>So, next up; we're going to look at the other side: type-safety on the language level.</p>
<h2 id="type-safety"><a href="#type-safety" class="heading-anchor">#</a> Type safety</h2>
<p>To understand how type safety can –or cannot– be guaranteed by a language,
let's look at these functions.</p>
<pre><span class="hl-property">take_care</span>(Animal) : <span class="hl-type">void</span>

take_care &gt; <span class="hl-property">feed</span>(Animal) : <span class="hl-type">void</span>
</pre>
<p>As you can see, <code>feed</code> extends <code>take_care</code> and follows its parent signature one-to-one.
Some programming languages don't allow children to change the type signature of their parent.
This is called type invariance.</p>
<p>It's the easiest approach to handle type safety with inheritance,
as types are not allowed to <em>vary</em> when inheriting.</p>
<p>But when you think back at how our example types are related to each other,
we know that <code>Cat</code> extends <code>Animal</code>.
Let's see whether the following is possible.</p>
<pre>take_care(Animal) : void

take_care &gt; feed(Cat) : void
</pre>
<p>The LSP only defines rules about objects, so on first sight, the function definition itself doesn't break any rules.
The real question is: does this function allow for proper use of the LSP when it's called?</p>
<p>We know that <code>feed</code> extends from <code>take_care</code>, and thus provides at least the same contract as its parent.
We also know that <code>take_care</code> allows <code>Animal</code> and its sub-types to be used.
So <code>feed</code> should also be able to take an <code>Animal</code> type.</p>
<pre>feed(Animal)

// Type error
</pre>
<p>Unfortunately, this is not the case. There's a type error occurring.
Can you see what we're doing here?
Instead of applying the LSP only to the parameters of a function,
we're also applying the same principles to the function itself.</p>
<blockquote>
<p>Wherever an invocation of <code>take_care</code> is used, we must be able to replace it
with an invocation of <code>feed</code>.</p>
</blockquote>
<p>This especially makes sense in an OO language where a function is no standalone entity in your code,
but rather part of a class, which represents a type itself.</p>
<p>To keep a system type-safe, it may not allow children to make the parameter types more specific.
This breaks the promises given by the parent.</p>
<p>However, take a look at the following definition:</p>
<pre>take_care(Animal) : void

take_care &gt; feed(Organism) : void
</pre>
<p>Does this definition ensures type safety?
It may seem backwards at first, but it does.
<code>feed</code> still follows the contract specified by <code>take_care</code>.
It can take <code>Animal</code> as an argument, and work just fine.</p>
<p>In this case, <code>feed</code> widens the parameter types allowed,
while still respecting the parent's contract.
This is called contravariance.
Types in argument lists should be contravariant for a type system to be safe.</p>
<h2 id="return-type-variance"><a href="#return-type-variance" class="heading-anchor">#</a> Return type variance</h2>
<p>Moving on to return types.
There are a few more types we'll have to define, in order for the examples to make sense.
I'm sorry in advance for the choice of words!</p>
<pre>Excretion &gt; Poop
</pre>
<p>And these are the functions we're working with.</p>
<pre>take_care(Animal) : Excretion

take_care &gt; feed(Animal) : Poop
</pre>
<p>The question now: is the overridden return type safe?
In contrast to the contravariance for the argument list,
this example actually is type safe!</p>
<p>The parent definition <code>take_care</code> tells us that this function will always return
an object of type <code>Excretion</code>.</p>
<pre>excretion = take_care(Animal)

excretion = feed(Animal)
</pre>
<p>Because <code>Poop</code> is a subtype of <code>Excretion</code>, we can be a 100% sure that whatever <code>feed</code> returns,
it will be within the category of <code>Excretion</code>.</p>
<p>You see the opposite rule applies for return types compared to function parameters.
In the case of return types, we're calling it covariance, or covariant types.</p>
<h2 id="real-life-impact"><a href="#real-life-impact" class="heading-anchor">#</a> Real-life impact</h2>
<p>There' no guarantee that a type-safe language will always write a bug-free program.
We've seen that the language design only carries half the responsibility of respecting the LSP.
The other half is the programmer's task.</p>
<p>Languages differ though, all have their own type system,
and each will have a different level of type safety.</p>
<p>Eiffel, for example, allows for parameter covariance.
By now you know this means there's an area of wrong behaviour possible that's undetectable by the compiler.
Hence there's the possibility of runtime errors.</p>
<p>PHP allows for constructors of child classes to have another signature,
while keeping an invariant type system for all other functions.
As with many things PHP, this inconsistency increases the confusion for developers.</p>
<p>Some languages like Java, C# and Rust have a concept that I didn't cover today: generics.
Type variance also plays a big role there.
That topic is out of scope for this blog post, but I might cover it in the future.</p>
<p>With all these differences, there's one thing to keep in mind.
The safety of a type system doesn't mean a language is better or worse.
I think it's fair to say that some cases would benefit from a very strong type system,
while others need the exact opposite.
The key takeaway is that every programmer
should learn more than just the concepts and paradigms of the languages they are used to the most.
A broadened view will be beneficial, now and in the future.</p>
<p>So what's your opinion on type safety?
If you're up for it, I'd love to talk about it even more:
you can reach me on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2018-05-19T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Dependency injection for beginners ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/dependency-injection-for-beginners"/>

                <id>https://www.stitcher.io/blog/dependency-injection-for-beginners</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>You're in the car business,
your job is to make cars on-demand.
The object-oriented programmer in you says:
"no problem, I'll make a blueprint that I can use to make as many cars as I want!".</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Car</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">drive</span>()
    {
        <span class="hl-comment">// ...</span>
    }
}
</pre>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>For this car to work, it needs an engine and wheels.
Now, there are several approaches to achieve that goal.
You could, for example, do the following:</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Car</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">engine</span> = <span class="hl-keyword">new</span> <span class="hl-type">Engine</span>();
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">wheels</span> = [
            <span class="hl-keyword">new</span> <span class="hl-type">Wheel</span>(), <span class="hl-keyword">new</span> <span class="hl-type">Wheel</span>(), 
            <span class="hl-keyword">new</span> <span class="hl-type">Wheel</span>(), <span class="hl-keyword">new</span> <span class="hl-type">Wheel</span>(),
        ];
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">drive</span>() { ... }
}
</pre>
<p>There's the blueprint for every car you'll make!
Next up, your boss comes to you and says there's a new client and he wants an electric car.</p>
<p>So you end up doing this.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">ElectricCar</span> <span class="hl-keyword">extends</span> <span class="hl-type">Car</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>()
    {
        <span class="hl-keyword">parent</span>::<span class="hl-property">__construct</span>();
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">engine</span> = <span class="hl-keyword">new</span> <span class="hl-type">ElectricEngine</span>();
    }
}
</pre>
<p>"Beautifully solved"—you think.
There's of course that redundant normal engine that's created when calling <code>parent::__construct()</code>,
but at least you could re-use the wheels!</p>
<p>I think you can see where this is going.
The next client wants a car with some fancy wheel covers,
another one would like a diesel engine with those same wheel covers,
another one requests a race car,
and the last one wants a self driving car.
<br>
Oh—there also was a client who wanted to buy an engine to build a boat with himself,
but you told your boss that wouldn't be possible.</p>
<p>After a while, there's a ton of blueprints in your office,
each describing a very specific variation of a car.
You started with a neatly ordered pile of blueprints.
But after a while you had to group them in different folders and boxes,
because it was taking too long to find the blueprint you're looking for.</p>
<p>Object oriented programmers often fall into this trap of inheritance,
ending in a completely messed up codebase.
So let's look at a better approach.
Maybe you've heard about "composition over inheritance" before?</p>
<blockquote>
<p>Composition over inheritance is the principle that classes should achieve polymorphic behavior
and code reuse by their composition rather than inheritance from a base or parent class—<a target="_blank" href="https://en.wikipedia.org/wiki/Composition_over_inheritance">Wikipedia</a></p>
</blockquote>
<p>That's a lot of buzzwords. Let's just look at our car example.
The principle states that <code>Car</code> should achieve its polymorphic behaviour
by being composed of other classes.</p>
<p>The word <em>polymorphic</em> literally means "many shapes"
and implies that <code>Car</code> should be able to do <code>drive</code> in many different ways,
depending on the context it's used in.</p>
<p>With <em>code reuse</em>, we're trying to make code reusable;
so that we don't end up with tens of classes doing almost exactly the same thing.</p>
<h2 id="what-does-this-have-to-do-with-dependency-injection?"><a href="#what-does-this-have-to-do-with-dependency-injection?" class="heading-anchor">#</a> What does this have to do with dependency injection?</h2>
<p>Instead of making a unique blueprint that describes every single possible variation of a car,
we'd rather have <code>Car</code> do one thing, and do it good: drive.</p>
<p>This means it shouldn't be the car's concern how its engine is built,
what wheels it has attached.
It should only know the following thing:</p>
<blockquote>
<p>Given a working engine and four wheels, I'm able to drive!</p>
</blockquote>
<p>We could say that in order for <code>Car</code> to work, it <em>needs</em> an engine and wheels.
In other words: <code>Car</code> depends on <code>Engine</code> and a collection of <code>Wheels</code>.</p>
<p>Those dependencies should be <em>given</em> to the car. Or, said otherwise: injected.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Car</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
        <span class="hl-type">Engine</span> $engine, 
        <span class="hl-type">array</span> $wheels
    </span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">engine</span> = <span class="hl-variable">$engine</span>;
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">wheels</span> = <span class="hl-variable">$wheels</span>;
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">drive</span>()
    {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">engine</span>-&gt;<span class="hl-property">connectTo</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">wheels</span>);
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">engine</span>-&gt;<span class="hl-property">start</span>();
        
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">engine</span>-&gt;<span class="hl-property">accelerate</span>();
    }
}
</pre>
<p>Would you like a race car? No problem!</p>
<pre><span class="hl-variable">$raceCar</span> = <span class="hl-keyword">new</span> <span class="hl-type">Car</span>(<span class="hl-keyword">new</span> <span class="hl-type">TurboEngine</span>(), [
    <span class="hl-keyword">new</span> <span class="hl-type">RacingWheel</span>(), <span class="hl-keyword">new</span> <span class="hl-type">RacingWheel</span>(),
    <span class="hl-keyword">new</span> <span class="hl-type">RacingWheel</span>(), <span class="hl-keyword">new</span> <span class="hl-type">RacingWheel</span>(),
]);
</pre>
<p>That client who wanted special wheel covers? You've got that covered!</p>
<pre><span class="hl-variable">$smugCar</span> = <span class="hl-keyword">new</span> <span class="hl-type">Car</span>(<span class="hl-keyword">new</span> <span class="hl-type">Engine</span>(), [
    <span class="hl-keyword">new</span> <span class="hl-type">FancyWheel</span>(), <span class="hl-keyword">new</span> <span class="hl-type">FancyWheel</span>(),
    <span class="hl-keyword">new</span> <span class="hl-type">FancyWheel</span>(), <span class="hl-keyword">new</span> <span class="hl-type">FancyWheel</span>(),
]);
</pre>
<p>You've got <em>a lot</em> more flexibility now!</p>
<p>Dependency injection is the idea of giving a class its requirements from the outside,
instead of having that class being responsible for them itself.</p>
<h2 id="what-dependency-injection-is-not"><a href="#what-dependency-injection-is-not" class="heading-anchor">#</a> What dependency injection is not</h2>
<p>Built upon this simple principle, there are frameworks and tools that take it to the next level.
You might, for example, have heard about the following things before.</p>
<h3 id="shared-dependencies"><a href="#shared-dependencies" class="heading-anchor">#</a> Shared dependencies</h3>
<p>One of the most beneficial side effects of injecting dependencies,
is that the outside context can control them.
This means that you can give the same instance of a class
to several others that have a dependency on that class.</p>
<p>Shared- or reusable dependencies are the ones most often getting the label "dependency injection".
Though it's certainly a very good practice,
sharing a dependency is not actually the core meaning of dependency injection.</p>
<h3 id="the-dependency-container"><a href="#the-dependency-container" class="heading-anchor">#</a> The dependency container</h3>
<p>Sometimes it's also called "inversion of control" container, though that's not an accurate name.</p>
<p>Whatever the exact name, the container is a set of class definitions.
It's a big box that knows how objects in your application can be constructed with other dependencies.
While such a container definitely has a lot of use cases, it's not necessary to do dependency injection.</p>
<h3 id="auto-wiring"><a href="#auto-wiring" class="heading-anchor">#</a> Auto wiring</h3>
<p>To give developers even more flexibility, some containers allow
for smart, automatically determined, class definitions.
This means you don't have to manually describe how every class should be constructed.
These containers will scan your code, and determine which dependencies are needed
by looking at type hints and doc blocks.</p>
<p>A lot of magic happens here, but auto wiring can be a useful tool for rapid application development.</p>
<h3 id="service-location"><a href="#service-location" class="heading-anchor">#</a> Service location</h3>
<p>Instead of injecting dependencies into a class,
there are some tools and frameworks that allow a class to ask the container
to "give it an instance of another class".</p>
<p>This might seem beneficial at first,
because our class doesn't need to know how to construct a certain dependency anymore.
However: by allowing a class to ask for dependencies on its own account,
we're back to square one.</p>
<p>For service location to work, our class needs to know about the systems on the outside.
It doesn't differ a lot from calling <code>new</code> in the class itself.
This idea is actually the opposite of what dependency injection tries to achieve.
It's a misuse of what the container is meant to do.</p>
<h3 id="inject-everything"><a href="#inject-everything" class="heading-anchor">#</a> Inject everything</h3>
<p>As it goes in real-life projects, you'll notice that dependency injection
is not <em>always</em> the solution for your problem.</p>
<p>It's important to realise that there are limits to the benefits of everything.
You should always be alert that you're not taking this to the extreme,
as there are valid cases in which a pragmatic approach <em>is</em> the better solution.</p>
<h2 id="in-closing"><a href="#in-closing" class="heading-anchor">#</a> In closing</h2>
<p>The core idea behind dependency injection is very simple,
yet allows for better maintainable, testable and decoupled code to be written.</p>
<p>Because it's such a powerful pattern,
it's only natural that lots of tools emerge around it.
I believe it's a good thing to first understand the underlying principle,
before using the tools built upon it.
And I hope this blog post has helped with that.</p>
<p>If there are any thoughts coming to your mind that you want to share,
feel free to reach out to me on via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
<p>Also special thanks to <a target="_blank" href="https://www.reddit.com/user/ImSuperObjective2">/u/ImSuperObjective2</a> on Reddit
and my colleague <a target="_blank" href="https://twitter.com/sebdedeyne">Sebastian</a> for proof reading this post.</p>
 ]]></summary>

                <updated>2018-04-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHPStorm performance issues on OSX ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/phpstorm-performance-issues-on-osx"/>

                <id>https://www.stitcher.io/blog/phpstorm-performance-issues-on-osx</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Are you using a fancy Mac with the latest and greatest hardware,
yet still having performance issues with PHPStorm?
I've been struggling with this the past few months.</p>
<p>It turns out, the solution might be rather unexpected.
Instead of disabling plugins, inspections and what not;
it seems like there's an issue with font rendering in the JRE for Mac.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>This means that on certain resolutions, for certain fonts and for certain kinds of antialiasing,
PHPStorm will need <em>a lot</em> of CPU power just to render fonts.
So how to fix it? There are a few options.</p>
<ul>
<li>Use another font. I was using Ubuntu Mono, and it turns out it requires quite a lot of CPU.
I've switched to Monaco instead.</li>
<li>Disabling <code>Subpixel</code> antialiasing. Go to <code>Preferences &gt; Appearance &amp; Behavior &gt; Appearance</code>
to configure antialiasing in your editor to <code>Greyscale</code> instead.
Your fonts won't look as good, but you'll notice a huge performance improvement.</li>
<li>Wait for JetBrains to find a fix. 2018.2 might fix some things,
but the real solution will take a while. There's an active discussion on the topic <a target="_blank" href="https://youtrack.jetbrains.com/issue/JRE-526#u=1466510431624">here</a>.</li>
</ul>
<p>If you're looking for even more performance improvements that can be made in PHPStorm,
take a look over <a href="/blog/phpstorm-performance">here</a>.</p>
 ]]></summary>

                <updated>2018-04-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ What PHP can be ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/what-php-can-be"/>

                <id>https://www.stitcher.io/blog/what-php-can-be</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Have you ever wondered how your life as a PHP developer would be different
if that <em>one</em> feature you want was added?
I've made the thought experiment quite a few times already, and came to surprising conclusions.</p>
<p>Let's take, for example, the debate about strong types in PHP.
A lot of people, including myself, would like a better type system.
Strong types in PHP would definitely have an impact on my daily work.
Not just strong types, I also want generics, better variance and variable types.
Improvements to PHP's type system in general would have quite the impact on my programming life.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>So what's stopping us from reaching a solution?</p>
<h2 id="type-theory"><a href="#type-theory" class="heading-anchor">#</a> Type theory</h2>
<p>Not everyone agrees on the vocabulary used when talking about type systems.
So let's clarify a few terms in the way that I will use them here.</p>
<p><strong>Strong or weak types</strong> define whether a variable can change its type after it's defined.
A simple example: say there's a variable <code>$a = 'test';</code>, which is a string;
you are able to re-assign that variable to another type, for example <code>$a = 1;</code>, an integer.</p>
<p>PHP is a weakly typed language, and I can illustrate this with a more real-life example:</p>
<pre><span class="hl-variable">$id</span> = '<span class="hl-value">1</span>'; <span class="hl-comment">// An ID retrieved as a URL parameter.</span>

<span class="hl-keyword">function</span> <span class="hl-property">find</span>(<span class="hl-injection"><span class="hl-type">int</span> $id</span>): <span class="hl-type">Model</span>
{
    <span class="hl-comment">// ...</span>
}


<span class="hl-property">find</span>(<span class="hl-variable">$id</span>);
</pre>
<p>You might think that in modern PHP, you can avoid these problems with strict types, but that's not completely true.
Declaring strict types prevents other types being passed into a function,
but you can still change the value of the variable in the function itself.</p>
<pre><span class="hl-keyword">declare</span>(strict_types=1);

<span class="hl-keyword">function</span> <span class="hl-property">find</span>(<span class="hl-injection"><span class="hl-type">int</span> $id</span>): <span class="hl-type">Model</span>
{
    <span class="hl-variable">$id</span> = '<span class="hl-value"></span>' . <span class="hl-variable">$id</span>;

    <span class="hl-comment">// This is perfectly allowed in PHP: `$id` is a string now.</span>
}

<span class="hl-property">find</span>('<span class="hl-value">1</span>'); <span class="hl-comment">// This would trigger a TypeError.</span>

<span class="hl-property">find</span>(1); <span class="hl-comment">// This would be fine.</span>
</pre>
<p>Like I said: PHP's type system is weak.
Type hints only ensure a variable's type at that point in time,
without a guarantee about any future value that variable might have.</p>
<p>Am I saying that strong types are better than weak ones? No.
But there's an interesting property to strong types, they come with a few guarantees.
If a variable has a type that's unchangeable, a whole range of unexpected behaviour simply cannot happen anymore.</p>
<p>You see, it's mathematically provable that if a strongly typed program compiles,
it's impossible for that program to have a range of bugs which can exist in weakly typed languages.
In other words, strong types give the programmer a stronger insurance that the code actually behaves how it's supposed to.</p>
<p>This doesn't mean that a strongly typed language cannot have bugs!
You're perfectly able to write a buggy implementation.
But when a strongly typed program compiles successfully,
you're sure a certain set of bugs and errors can't occur in that program.</p>
<p>If you want to further explore the topic on strong and weak types,
I'd recommend starting with <a target="_blank" href="https://www.destroyallsoftware.com/talks/ideology">this video</a> by Gary Bernhardt.
Not only does it go further into detail on types,
Gary also discusses an important mindset in the whole types debate.</p>
<h3 id="when-types-are-checked"><a href="#when-types-are-checked" class="heading-anchor">#</a> When types are checked</h3>
<p>We talked about <strong>strong</strong> and <strong>weak</strong> types, what about <strong>static</strong> and <strong>dynamic</strong> types?
– This is where it starts to get truly interesting.</p>
<p>As you're probably aware, PHP is an interpreted language.
This means a PHP script is compiled at runtime.
When you send a request to a server running PHP,
it will take those plain <code>.php</code> files, and parse the text in it to something the processor can execute.</p>
<p>This is one of PHP's strong points by the way: the simplicity on how you can write a script,
refresh your webpage and everything is there.
That's a big difference compared to a language that has to be compiled before it can be run.</p>
<p>There is a downside though: performance.
And it's not hard to pinpoint this down: the more tasks there are to do at runtime,
the more impact there is on performance.
One of those many tasks the PHP engine has to take care of? Type checking.</p>
<p>Because PHP checks the type of variables at runtime,
it is often described as a <strong>dynamically typed</strong> language.
A <strong>statically typed</strong> language on the other hand,
will have all its type checks done before the code is executed.</p>
<blockquote>
<p>Hang on – I can hear you say – what does this have to do with what PHP can be?</p>
<p>—We'll get to that.</p>
</blockquote>
<h2 id="what-this-means-for-php"><a href="#what-this-means-for-php" class="heading-anchor">#</a> What this means for PHP</h2>
<p>Now we know what we're talking about, let's take a look at PHP's type system today.</p>
<p>I hope that after the theory, it's clear to you that PHP is a <strong>dynamic, weakly typed</strong> language.
And <strong>there's nothing wrong with that</strong>!</p>
<p>On the other hand, it's interesting to note that many people are asking for a better type system in PHP.
This doesn't mean we understand the implications of such a type system on PHP,
yet but many of us feel that <em>natural urge</em> for a better type system.
I'm sure that a lot of developers can point to real-life,
daily situations where a better type system would actually benefit them.</p>
<p>To give one obvious example: the question for generics.
Whether it is to ensure an array only contains one type of elements
or to improve ORM abstractions, lots of people are asking for generics in PHP.</p>
<p>The question than becomes: is creating a more complicated type system feasible with PHP's current type paradigm?
And the answer is, in part, yes—for sure.
There are parts that could be improved in the current, dynamic weak type system.</p>
<p>Type hints for one, added in PHP 7.0 and 7.1 are useful to many PHP developers;
Levi Morrison is working on <a target="_blank" href="https://github.com/morrisonlevi/php-src/tree/generic_traits">generics in traits</a>;
also, there are very active discussions about the type system on the internals mailing list.</p>
<p><strong>However</strong>: we're missing a very important point.
As long as we're striving to improve PHP's runtime type system,
we'll always be dealing with the huge performance cost it will take.</p>
<h2 id="the-benefits-of-a-static-type-system"><a href="#the-benefits-of-a-static-type-system" class="heading-anchor">#</a> The benefits of a static type system</h2>
<p>This is what Rasmus Lerdorf has to say on the topic.</p>
<blockquote>
<p>Now if the RFC was a plan for baking a compile-time static analysis engine
into PHP itself, that would be interesting. But that is a massive project.</p>
<p>— <a target="_blank" href="https://externals.io/message/101477#101592">Rasmus</a></p>
</blockquote>
<p>Imagine the possibilities when you can write PHP code that can be statically type checked
before running the code. Tools like PHPStan and Psalm already do a lot of static analysis,
but in my opinion it could go a step further. Say we could do this.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">List</span>&lt;<span class="hl-property">T</span>&gt;
{
    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$list</span>;
    
    <span class="hl-comment">// ...</span>
}
</pre>
<p>What if this was valid PHP code?
And what if the runtime engine would just plain ignore it,
and a part of PHP engine could do all the type checks, before runtime?</p>
<p>That's –in my opinion– a better solution than standalone tools which rely on docblocks
and can't benefit from the core PHP engine, as they are written, in the case of Psalm and PHPStan, in PHP.</p>
<p>Don't get me wrong: tools like these are the first important step
towards a bigger goal. I just think we shouldn't stop here.</p>
<p>The need for a better type system is clear.
Lots of programmers experience a natural longing for something more than what's possible now.
This doesn't only happen in the PHP community, look at modern languages like Rust,
or supersets like TypeScript for JavaScript.</p>
<p>So maybe the answer for PHP lies into baked-in features in the core,
maybe it lies in a superset that compiles to PHP with extra type checking.
That last one by the way, has already been tried: Hack on HHVM.</p>
<p>There even is a third option, a question every programmer should ask themselves from time to time.
Should we want PHP to change dramatically to match our needs,
or should we change our frame of reference, and maybe look at other languages that might fit those needs better?</p>
<p>There's no shame in using another tool for the job, if that tools fit your needs better.
And after all, isn't a programming language just that? A tool.</p>
 ]]></summary>

                <updated>2018-04-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHPStorm tips for power users ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/phpstorm-tips-for-power-users"/>

                <id>https://www.stitcher.io/blog/phpstorm-tips-for-power-users</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>A selection of less-known-yet-powerful features of PHPStorm.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="pane-modes"><a href="#pane-modes" class="heading-anchor">#</a> Pane modes</h2>
<p>Every pane in PHPStorm has several modes and can be configured either by hand or via key bindings.</p>
<ul>
<li>
<code>docked</code>: makes a pane not overlap with other panes or the code screen.</li>
<li>
<code>pinned</code>: automatically hides a pane when not pinned.</li>
<li>
<code>floating</code>: makes the pane float.</li>
<li>
<code>windowed</code>: makes the pane a full-blown window.</li>
<li>
<code>split</code>: to allow multiple panes in one area.</li>
</ul>
<p>Working with non-pinned panes will allow for a much cleaner editor view.
Binding certain panes to a key combination will show them at will.</p>
<p>
    <img src="/resources/img/static/phpstorm-power-users/panes.gif"/>
</p>
<h2 id="auto-imports"><a href="#auto-imports" class="heading-anchor">#</a> Auto-imports</h2>
<p>By default, PHPStorm will only auto-import namespaces if you're already in a namespaced file.
Auto imports can be configured to also work in normal PHP files
in <code>Settings &gt; Editor &gt; General &gt; Auto Import</code>.</p>
<h2 id="code-templates"><a href="#code-templates" class="heading-anchor">#</a> Code templates</h2>
<p>You can change almost every template of auto-generated code in <code>Settings &gt; Editor &gt; File and Code Templates</code>
For example: generate getters and setters without docblocks, generate test functions in another format and others.</p>
<p><img src="/resources/img/blog/phpstorm-power-users/code-templates.png" srcset="/resources/img/blog/phpstorm-power-users/code-templates-1967x1296.png 1967w, /resources/img/blog/phpstorm-power-users/code-templates-2540x1674.png 2540w, /resources/img/blog/phpstorm-power-users/code-templates-2271x1496.png 2271w, /resources/img/blog/phpstorm-power-users/code-templates-1606x1058.png 1606w" sizes="" alt="-"><em class="small center">-</em></img></p>
<h2 id="string-actions"><a href="#string-actions" class="heading-anchor">#</a> String actions</h2>
<p>When pressing <code>alt + enter</code> (<code>Show Intention Actions</code>) on a string, you'll get multiple useful actions.
Things like <code>replace quotes</code> to toggle between single- and double quotes,
<code>split string</code> to split the string, and more.</p>
<p>
    <img src="/resources/img/static/phpstorm-power-users/string-actions.gif"/>
</p>
<h2 id="copy-paths"><a href="#copy-paths" class="heading-anchor">#</a> Copy paths</h2>
<p>Two very useful commands:</p>
<ul>
<li>
<code>Copy Paths</code> to copy the full path to the current file.</li>
<li>
<code>Copy Reference</code> to copy the relative project path and line number to the current file.</li>
</ul>
<p>This "current file" can be the file you're editing,
but could also be the selected file in the tree view or navigation bar.</p>
<h2 id="commands-to-toggle-options"><a href="#commands-to-toggle-options" class="heading-anchor">#</a> Commands to toggle options</h2>
<p>Instead of opening the settings to toggle options,
there are a lot of toggles you can manage from the command palette.
For example: show or hide the tabs bar.</p>
<p>
    <img src="/resources/img/static/phpstorm-power-users/tab-placement.gif"/>
</p>
<p>You can open the command palette with <code>⌘ ⇧ A</code> on the default Mac keymap.
If you want to lookup the keybinding on your system: the command is called <code>Find Action</code>.</p>
<h2 id="custom-jvm-options"><a href="#custom-jvm-options" class="heading-anchor">#</a> Custom JVM options</h2>
<p>PHPStorm runs on Java, and there's a file in which you can specify extra options for the JVM
to optimise performance. I've written about those options <a href="/blog/phpstorm-performance">here</a>.</p>
<h2 id="distraction-free-mode"><a href="#distraction-free-mode" class="heading-anchor">#</a> Distraction free mode</h2>
<p>Distraction free mode will hide all panes by default,
but you can easily bring them back via the command palette or key bindings.</p>
<p>Besides this "no clutter by default", your code will also align more centered, which can be a much more pleasant reading experience.
The width of this centered code view is configured in <code>Settings &gt; Editor &gt; Code Style &gt; Hard wrap at</code>.</p>
<p>
    <img src="/resources/img/static/phpstorm-power-users/distraction-free.gif"/>
</p>
<h2 id="color-inspection"><a href="#color-inspection" class="heading-anchor">#</a> Color inspection</h2>
<p>Do you want to know why a word is highlighted or change the colouring?
There's a command called <code>Jump to Colors and Fonts</code> which will allow you to edit
the color of your current scheme, for that entry.</p>
<p>
    <img src="/resources/img/static/phpstorm-power-users/colors-and-fonts.gif"/>
</p>
<h2 id="any-more-suggestions?"><a href="#any-more-suggestions?" class="heading-anchor">#</a> Any more suggestions?</h2>
<p>I'd love to hear your own tips on how to use PHPStorm.
Feel free to let me know via <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or <a href="mailto:brendt@stitcher.io">e-mail</a>.</p>
 ]]></summary>

                <updated>2018-03-15T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Responsive images done right ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/responsive-images-done-right"/>

                <id>https://www.stitcher.io/blog/responsive-images-done-right</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I want to share some thoughts on responsive images.
I'll write about a certain mindset which many projects could benefit from:
small- and mid-sized web projects that don't need a full blown CDN setup,
but would enjoy the performance gain of responsive images.</p>
<p>The idea behind responsive images is simple:
try to serve an image with dimensions as close as possible to the image dimensions on screen.
This results in smaller bandwidth usage and faster load times!</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>For example: if you're displaying an image on a mobile device with a screen of 600px wide,
there's no need for downloading that image with a width of 1000px.</p>
<p>The responsive images spec handles not only media queries, but pixel density too.
The only thing the server has to do is generate multiple variations of the same image,
each with a different size.</p>
<p>If you'd like to know more about how things are done behind the scenes,
I'll share some links to interesting resources at the end of this post.</p>
<h2 id="how-to-render-responsive-images"><a href="#how-to-render-responsive-images" class="heading-anchor">#</a> How to render responsive images</h2>
<p>There are different ways to render variations of the same image.
The simplest approach could be this:
<strong>given an image, create 4 variations: 1920px, 1200px, 800px and 400px</strong>.</p>
<p>While this approach is easy to implement, it's not the most optimal.
The goal of responsive images is to serve faster loading images
while maintaining the highest possible quality for the user's screen.</p>
<p>There are two variables in this equation: the width of the user's screen
(and therefore the width of the image itself) and the file size of an image.</p>
<p>Say you have two images with the exact same dimensions.
Depending on the content in that image and the encoding used,
their file sizes could differ a lot.</p>
<p>Another approach could be to manually define the most optimal <code>srcset</code> for each image.
This is impossible to do for most websites.
A website could have lots of images,
and it's also difficult to manually calculate the dimensions for that optimal <code>srcset</code>.</p>
<p>Luckily, computers are very good at tedious calculations on a large scale.
This approach sounds like a good idea:
<strong>given an image, generate x-amount of variations of that image,
each variation being approximately 10% smaller in file size</strong>.</p>
<p>How does that sound? You now have a small margin of possible "overhead"
for variable screen sizes, but at least we're sure that margin won't be more than 10%.
Depending on the size of the image, for example: a thumbnail vs. a hero image;
we could even reduce the margin to 5% instead of 10%.
This will result in a different <code>srcset</code> for every image,
but that's not our concern: the responsive images spec can handle that for us.</p>
<p>So how can you determine the dimensions of, say 10 variants of the same image, if you only know the dimensions of the original image? This is where high school maths come into play.</p>
<pre>We start with these known variables
filesize = 1.000.000
width = 1920
ratio = 9 / 16
height = ratio * width

Next we introduce another one: area
area = width * height
 &lt;=&gt; area = width * width * ratio

We say that the pixelprice is filesize / area
pixelprice = filesize / area

Now we can replace variables until we have the desired result
 &lt;=&gt; filesize = pixelprice * area
 &lt;=&gt; filesize = pixelprice * (width * width * ratio)
 &lt;=&gt; width * width * ratio = filesize / pixelprice
 &lt;=&gt; width ^ 2 = (filesize / pixelprice) / ratio
 &lt;=&gt; width = sqrt((filesize / pixelprice) / ratio)
</pre>
<p>This proof says that given a constant <code>pixelprice</code>, we can calculate the width a scaled-down image needs to have a specified filesize. Here's the thing though: <code>pixelprice</code> is an approximation of what one pixel in this image costs. Because we'll scale down the image as a whole, this approximation is enough to yield accurate results though. Here's the implementation in PHP:</p>
<pre><span class="hl-comment">/*
$fileSize        file size of the source image
$width           width of the source image
$height          height of the source image
$area            the amount of pixels
                 `$width * $height` or `$width * $width * $ration` 
$pixelPrice      the approximate price per pixel:
                 `$fileSize / $area`
*/</span>

<span class="hl-variable">$dimensions</span> = [];

<span class="hl-variable">$ratio</span> = <span class="hl-variable">$height</span> / <span class="hl-variable">$width</span>;
<span class="hl-variable">$area</span> = <span class="hl-variable">$width</span> * <span class="hl-variable">$width</span> * <span class="hl-variable">$ratio</span>;
<span class="hl-variable">$pixelPrice</span> = <span class="hl-variable">$fileSize</span> / <span class="hl-variable">$area</span>;
<span class="hl-variable">$stepModifier</span> = <span class="hl-variable">$fileSize</span> * 0.1;

<span class="hl-keyword">while</span> (<span class="hl-variable">$fileSize</span> &gt; 0) {
    <span class="hl-variable">$newWidth</span> = <span class="hl-property">floor</span>(
        <span class="hl-property">sqrt</span>(
            (<span class="hl-variable">$fileSize</span> / <span class="hl-variable">$pixelPrice</span>) / <span class="hl-variable">$ratio</span>
        )
    );

    <span class="hl-variable">$dimensions</span>[] = <span class="hl-keyword">new</span> <span class="hl-type">Dimension</span>(<span class="hl-variable">$newWidth</span>, <span class="hl-variable">$newWidth</span> * <span class="hl-variable">$ratio</span>);

    <span class="hl-variable">$fileSize</span> -= <span class="hl-variable">$stepModifier</span>;
}
</pre>
<p>I want to clarify once more that this approach will be able to calculate the dimensions for each variation
with a 10% reduction in file size, without having to scale that image beforehand.
That means there's no performance overhead or multiple guesses to know how an image should be scaled.</p>
<h2 id="in-practice"><a href="#in-practice" class="heading-anchor">#</a> In practice</h2>
<p>Let's take a look at a picture of a parrot. This image has a fixed <code>srcset</code>:</p>
<p>
    <img src="/resources/img/static/responsive/parrot-fixed-800.jpg" srcset="/resources/img/static/responsive/parrot-fixed-1920.jpg 1920w, /resources/img/static/responsive/parrot-fixed-1200.jpg 1200w, /resources/img/static/responsive/parrot-fixed-800.jpg 800w, /resources/img/static/responsive/parrot-fixed-400.jpg 400w"/>
</p>
<p>This one has a dynamic <code>srcset</code>:</p>
<p><img src="/resources/img/blog/responsive/parrot.jpg" srcset="/resources/img/blog/responsive/parrot-1214x809.jpg 1214w, /resources/img/blog/responsive/parrot-858x572.jpg 858w, /resources/img/blog/responsive/parrot-1487x991.jpg 1487w, /resources/img/blog/responsive/parrot-1920x1280.jpg 1920w, /resources/img/blog/responsive/parrot-1717x1144.jpg 1717w" sizes="" alt=""></img></p>
<p>Feel free to open up your inspector and play around with it in responsive mode.
Be sure to disable browser cache and compare which image is loaded on different screen sizes. Also keep in mind that the pixel density of your screen can have an impact.</p>
<p>Can you imagine doing this by hand? Neither can I! One of the first features I proposed when I started working at Spatie, my current job, was to add this behaviour in the <a target="_blank" href="https://spatie.be/docs/laravel-medialibrary/v8/responsive-images/using-your-own-width-calculator">Laravel media library</a>, its usage is as simple as this:</p>
<pre><span class="hl-variable">$model</span>
   -&gt;<span class="hl-property">addMedia</span>(<span class="hl-variable">$yourImageFile</span>)
   -&gt;<span class="hl-property">withResponsiveImages</span>()
   -&gt;<span class="hl-property">toMediaCollection</span>();
</pre>
<pre>&lt;img 
    src=&quot;{{ $media-&gt;getFullUrl() }}&quot; 
    srcset=&quot;{{ $media-&gt;getSrcset() }}&quot; 
    sizes=&quot;[your own logic]&quot;
/&gt;
</pre>
<p><div class="sidenote">
    <div class="center">
        <a href="https://www.youtube.com/watch?v=nJFsD0bnlTI" target="_blank" rel="noopener noreferrer">
            <img class="small hover-outline" src="/resources/img/static/83-thumb.png" alt="New in PHP 8.3">
            <p><em class="center small">New in PHP 8.3</em></p>
        </a>
    </div>
</div>
</p>
<p>To finish off, here are the links which I mentioned at the start of this post.</p>
<ul>
<li>Responsive images explained in depth:
<a target="_blank" href="https://ericportis.com/posts/2014/srcset-sizes/">https://ericportis.com/posts/2014/srcset-sizes/</a>
</li>
<li>The official specification website:
<a target="_blank" href="https://responsiveimages.org/">https://responsiveimages.org/</a>
</li>
</ul>
<p>Special thanks to my colleague <a target="_blank" href="https://twitter.com/sebdedeyne">Sebastian</a> for reviewing and editing this post.</p>
 ]]></summary>

                <updated>2018-03-07T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Showing full MySQL foreign key errors ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/mysql-show-foreign-key-errors"/>

                <id>https://www.stitcher.io/blog/mysql-show-foreign-key-errors</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In case of a foreign key error when creating or altering a table, MySQL doesn't show the full message.</p>
<p>You can read the full message by executing the following query and inspecting the <code>Status</code> column.</p>
<pre>show engine innodb status;
</pre>
<pre>------------------------
LATEST FOREIGN KEY ERROR
------------------------
2018-02-13 11:12:26 0x70000b776000 Error in foreign key constraint of table table/#sql-7fa_247a:
 foreign key (`my_foreign_key`) references `table` (`id`)
   on delete cascade:
Cannot resolve table name close to:
 (`id`)
   on delete cascade
</pre>
 ]]></summary>

                <updated>2018-02-13T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ MySQL query logging ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/mysql-query-logging"/>

                <id>https://www.stitcher.io/blog/mysql-query-logging</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <h2 id="enable-query-logging"><a href="#enable-query-logging" class="heading-anchor">#</a> Enable query logging</h2>
<pre>mysql -p -u root

&gt; SET GLOBAL general_log = 'ON';

# Turning it off again when finished

&gt; SET GLOBAL general_log = 'OFF';
</pre>
<h2 id="find-the-log-file"><a href="#find-the-log-file" class="heading-anchor">#</a> Find the log file</h2>
<p>First, find the <code>mysqld</code> process ID.</p>
<pre>ps auxww | grep mysql

brent             2042   0.0  0.4  2849776  67772   ??  S    Fri11AM   0:16.80 /usr/local/opt/mysql/bin/mysqld
</pre>
<p>Second, use <code>lsof</code> to find all files used by this process, and filter on <code>log</code>.</p>
<pre># sudo lsof -p &lt;PID&gt; | grep log

sudo lsof -p 2042 | grep log

mysqld  2042 brent    4u     REG                1,4  50331648  780601 /usr/local/var/mysql/ib_logfile0
mysqld  2042 brent    9u     REG                1,4  50331648  780602 /usr/local/var/mysql/ib_logfile1
mysqld  2042 brent   26u     REG                1,4        35  780672 /usr/local/var/mysql/mysql/general_log.CSM
mysqld  2042 brent   32r     REG                1,4         0  780673 /usr/local/var/mysql/mysql/general_log.CSV
mysqld  2042 brent   33w     REG                1,4     25504 9719379 /usr/local/var/mysql/HOST.log
</pre>
<p><code>/usr/local/var/mysql/HOST.log</code> is the one you want, <code>HOST</code> will be the name of your host.</p>
<pre>tail -f /usr/local/var/mysql/HOST.log
</pre>
 ]]></summary>

                <updated>2018-01-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Where a curly bracket belongs ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/where-a-curly-bracket-belongs"/>

                <id>https://www.stitcher.io/blog/where-a-curly-bracket-belongs</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>This blogpost is based on <a target="_blank" href="https://www.youtube.com/watch?v=ZsHMHukIlJY">this amazing talk by Kevlin Henney</a>.</p>
<p>Dedicating a whole blogpost to curly brackets might seem like overkill
but I believe it's worth thinking about them.
Not just because of one curly bracket, but because there's a bigger message in all this.
Thinking about how we read and write code not only improves the quality of that code,
it also increases our own and others ease of mind when working with it.
It can improve the fluency of your work and free your mind to think about real important stuff.
You know, things like "application logic" for example.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>I wrote about visual code improvements a while back in a previous blogpost about <a href="/blog/a-programmers-cognitive-load">cognitive load</a>.
Today I want to focus on that one little, yet very important character in our codebase: the curly bracket.
More specifically, we're only going to look at the opening curly bracket,
because there's little to no discussion about the closing one.</p>
<p>Let's take a look at a code sample.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">string</span> $publicDirectory, <span class="hl-type">string</span> $configurationFile, <span class="hl-type">PageParser</span> $pageParser, <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>A constructor for a render task in Stitcher. It takes two config arguments and two objects.
Depending on the width of your screen, this piece of code might be fully visible in your IDE.
On this website it surely will not.</p>
<p>So what's wrong with this code?
Well first of all, you probably have to scroll to read it. That's a bad thing.
Scrolling requires an extra action for the developer to take.
You'll have to consciously search for information about the arguments of this method.
That time distracts you from focusing on the application code.</p>
<p>Second, if you're a web developer, you probably know people don't read, they rather scan.
This is especially true for websites, where the biggest area of attention leans towards the left.
And the same goes for reading code.
Putting important information to the right makes it more difficult to find,
and it also doesn't convey the same importance as things to the left.</p>
<p>In case of an argument list, all arguments are equally important;
yet in the above example a lot of useful information is pushed to that right, dark side.</p>
<p>So how do we pull the useful information more to the left?</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">string</span> $publicDirectory, 
                            <span class="hl-type">string</span> $configurationFile, 
                            <span class="hl-type">PageParser</span> $pageParser, 
                            <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>This could be the first thing you think about. But it doesn't really scale.
As soon as you're refactoring a method name, the alignment breaks.
Say we want to make this a static constructor instead of a normal one.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">create</span>(<span class="hl-injection"><span class="hl-type">string</span> $publicDirectory, 
                            <span class="hl-type">string</span> $configurationFile, 
                            <span class="hl-type">PageParser</span> $pageParser, 
                            <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
</pre>
<p>See the alignment breaking?
Another issue with this approach is that things are still pushed rather far to the right;
let's take a look at another approach.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $publicDirectory, <span class="hl-type">string</span> $configurationFile, 
    <span class="hl-type">PageParser</span> $pageParser, <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>The advantage here is that the alignment issue on refactoring is solved.
However, how will you decide how many arguments should go on one line?
Will you make some styling guidelines about this?
How will you enforce them?
This example has four arguments, but what if it had three or five?</p>
<p>Consistency is key. If there is a consistent rule about this, you won't have to think about it anymore.
And like we said before, if you don't have to think about this, there's room in your head for more important things.</p>
<p>So let's continue searching for that consistency.</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $publicDirectory, 
    <span class="hl-type">string</span> $configurationFile, 
    <span class="hl-type">PageParser</span> $pageParser, 
    <span class="hl-type">PageRenderer</span> $pageRenderer</span>) {
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publicDirectory</span> = <span class="hl-property">rtrim</span>(<span class="hl-variable">$publicDirectory</span>, '<span class="hl-value">/</span>');
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">configurationFile</span> = <span class="hl-variable">$configurationFile</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageParser</span> = <span class="hl-variable">$pageParser</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageRenderer</span> = <span class="hl-variable">$pageRenderer</span>;
}
</pre>
<p>By giving each argument its own line, we solve the above mentioned problems.
But there's still one issue with this example:
it's hard to distinguish between the argument list and the method body.</p>
<p>Kevlin Henney visualises this problem in a simple, yet clever way.
Let's replace all characters in this code with X's:</p>
<pre>XXXXXX XXXXXXXX __XXXXXXXXX(
    XXXXXX XXXXXXXXXXXXXXXX, 
    XXXXXX XXXXXXXXXXXXXXXXXX, 
    XXXXXXXXXX XXXXXXXXXXX, 
    XXXXXXXXXXXX XXXXXXXXXXXXX) {
    XXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXX = XXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXX;
}
</pre>
<p>Can you see how difficult it has become to spot where the argument list ends
and the method body starts?</p>
<p>You might say "there's still the curly bracket on the right indicating the end".
That's the thing we want to avoid! We want to keep the visual important information to the <em>left</em>.
How do we solve it? Kevlin Henney phrased it very well:</p>
<blockquote>
<p>Turns out, there is one true place where to put your curly brackets - Kevlin Henney</p>
</blockquote>
<pre>XXXXXX XXXXXXXX __XXXXXXXXX(
    XXXXXX XXXXXXXXXXXXXXXX, 
    XXXXXX XXXXXXXXXXXXXXXXXX, 
    XXXXXXXXXX XXXXXXXXXXX, 
    XXXXXXXXXXXX XXXXXXXXXXXXX
) {
    XXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXXXXXXX;
    XXXXXXXXXXXXXXXXX = XXXXXXXXXXX;
    XXXXXXXXXXXXXXXXXXX = XXXXXXXXXXXXX;
}
</pre>
<p>That is why it makes sense to put that curly bracket on a new line.
Here's the final result:</p>
<pre><span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection">
    <span class="hl-type">string</span> $publicDirectory, 
    <span class="hl-type">string</span> $configurationFile, 
    <span class="hl-type">PageParser</span> $pageParser, 
    <span class="hl-type">PageRenderer</span> $pageRenderer
</span>) {
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">publicDirectory</span> = <span class="hl-property">rtrim</span>(<span class="hl-variable">$publicDirectory</span>, '<span class="hl-value">/</span>');
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">configurationFile</span> = <span class="hl-variable">$configurationFile</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageParser</span> = <span class="hl-variable">$pageParser</span>;
    <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pageRenderer</span> = <span class="hl-variable">$pageRenderer</span>;
}
</pre>
<p>Now, you might not like this way of structuring your code.
You might think it adds unnecessary length to a file.
But take a look at the facts:</p>
<ul>
<li>You're keeping the important information to the left of the screen, where most of your focus is.</li>
<li>This method is consistent, which allows us not having to think about it when reading it.
This frees up some of your human "memory space": it reduces cognitive load;
it allows you to focus on the important stuff: the real application logic.</li>
<li>No one ever died because a file was "longer than absolutely needed".
People do however get very frustrated working in legacy code bases,
having to read what other people wrote, especially when that code is difficult to read.</li>
<li>If the length of the file is really a bother for you, code folding can solve that issue.</li>
</ul>
<p>I like having this rule when coding.
There's never a discussion in my head about "should I do it this way or that way"?
This consistency helps me write and read my own code, and benefits other developers too, maybe even years later.</p>
<h2 id="what-about-small-functions?"><a href="#what-about-small-functions?" class="heading-anchor">#</a> What about small functions?</h2>
<p>Say your function only has one parameter, should it be split on multiple lines?
I personally don't think so. And if we're strictly applying the rules above,
the curly bracket may be put on the same line.</p>
<p>However, now that we're used to that one almost-empty line between the argument list and the method body,
it does seem like a nice idea to use this visual divider also for smaller functions.</p>
<pre><span class="hl-type">XXXXXX</span> <span class="hl-property">XXXXXXXX</span> <span class="hl-property">__XXXXXXXXX</span>(<span class="hl-property">XXXXXX</span> <span class="hl-property">XXXXXXXXXXXXXXXX</span>) 
{
    <span class="hl-type">XXXXXXXXXXXXXXXXXXXXXX</span> = <span class="hl-property">XXXXXXXXXXXXXXXX</span>;
}
</pre>
<p>Now we could start arguing about the placement of that closing bracket,
but that's a blogpost for another time.</p>
<h2 id="and-control-structures?"><a href="#and-control-structures?" class="heading-anchor">#</a> And control structures?</h2>
<p>The question about <code>if</code>, <code>for</code>, <code>while</code> and others should of course be addressed too.
In my opinion, the answer is simple, we can apply the same rules to them.</p>
<p>If the operands are pushed too far to the right, and we feel the need to split it, we do it like this:</p>
<pre><span class="hl-keyword">if</span> (
    <span class="hl-variable">$firstCondition</span> === <span class="hl-variable">$secondCondition</span>
    <span class="hl-operator">||</span> <span class="hl-variable">$thirdOperand</span> === 1
    <span class="hl-operator">||</span> <span class="hl-variable">$fourthOperand</span>
) {
    <span class="hl-comment">// ...</span>
}
</pre>
<p>Finally, here is a daring thought - and I don't do this myself by the way,
because following standards is also a good thing -
it might make sense to apply the same rule to short control structures.
After all: consistency, right?</p>
<pre><span class="hl-keyword">foreach</span> (<span class="hl-variable">$things</span> <span class="hl-keyword">as</span> <span class="hl-variable">$thing</span>)
{
    <span class="hl-comment">// ...</span>
}
</pre>
<hr />
<p>If you're not convinced by now, I'd love to hear why!
You can reach out to me on <a target="_blank" href="https://twitter.com/brendt_gd">Twitter</a> or via <a href="mailto:brendt@stitcher.io">e-mail</a>.
I'm looking forward to discussing this further with you!</p>
<p>If you're looking for more to read on clean code.
Feel free to browse this blog a little further.
<a href="/blog/a-programmers-cognitive-load">This is the best starting point</a>.</p>
 ]]></summary>

                <updated>2018-01-16T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ MySQL import: JSON with binary character set ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/mysql-import-json-binary-character-set"/>

                <id>https://www.stitcher.io/blog/mysql-import-json-binary-character-set</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>If you see this error when importing MySQL files:</p>
<pre>cannot create a JSON value from a string with CHARACTER SET 'binary'
</pre>
<p>You should find and replace parts of the import file with the following regex:</p>
<p>Find: <code>(X'[^,\)]*')</code>, and replace by: <code>CONVERT($1 using utf8mb4)</code></p>
<p>Source: <a target="_blank" href="https://stackoverflow.com/questions/38078119/mysql-5-7-12-import-cannot-create-a-json-value-from-a-string-with-character-set">StackOverflow</a>.</p>
 ]]></summary>

                <updated>2018-01-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Asynchronous PHP ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/asynchronous-php"/>

                <id>https://www.stitcher.io/blog/asynchronous-php</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>We're working on a new package at Spatie.
It's called <a target="_blank" href="https://github.com/spatie/async">spatie/async</a> and meant to do asynchronous parallel processing in PHP.</p>
<p>Parallel processing in PHP might seem like an edge case for many web developers,
but let's take a look at a few use-cases we see at Spatie:</p>
<ul>
<li>
<a target="_blank" href="https://github.com/spatie/laravel-medialibrary">Image optimisation</a>
</li>
<li>PDF rendering</li>
<li>
<a target="_blank" href="https://github.com/spatie/crawler">Concurrent site crawling</a>
</li>
<li>
<a target="_blank" href="https://github.com/spatie/schema-org">Code generators</a>
</li>
<li>Static site generators - like Stitcher</li>
</ul>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>We wanted to create an easy-to-use package, yet one that could solve our use cases.
Some of the examples listed above will not use the new <code>spatie/async</code> package,
because there's also a queueing system provided with Laravel.</p>
<p>This is how asynchronous code with our package looks like.</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Spatie\Async\Process</span>;

<span class="hl-variable">$pool</span> = <span class="hl-type">Pool</span>::<span class="hl-property">create</span>();

<span class="hl-keyword">foreach</span> (<span class="hl-property">range</span>(1, 5) <span class="hl-keyword">as</span> <span class="hl-variable">$i</span>) {
    <span class="hl-variable">$pool</span>[] = <span class="hl-property">async</span>(<span class="hl-keyword">function</span> (<span class="hl-injection">) use ($i</span>) {
        <span class="hl-comment">// Something to execute in a child process.</span>
    })-&gt;<span class="hl-property">then</span>(<span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">int</span> $output</span>) {
        <span class="hl-comment">// Handle output returned from the child process.</span>
    })-&gt;<span class="hl-property">catch</span>(<span class="hl-keyword">function</span> (<span class="hl-injection"><span class="hl-type">Exception</span> $exception</span>) {
        <span class="hl-comment">// Handle exceptions thrown in the child process.</span>
    });
}

<span class="hl-property">await</span>(<span class="hl-variable">$pool</span>);
</pre>
<h2 id="outperforming-amp?-not-quite-yet."><a href="#outperforming-amp?-not-quite-yet." class="heading-anchor">#</a> Outperforming Amp? Not quite yet.</h2>
<p>If you're into parallel PHP, you've probably heard of <a target="_blank" href="https://github.com/amphp">Amp</a> and <a target="_blank" href="https://github.com/reactphp">ReactPHP</a>.
Our package aims not to compete with those two, as it only solves one tiny aspect of parallelism in PHP;
and tries to solve it in a different way.</p>
<p>We did however run some benchmarks to compare our package performance against Amp.
Special thanks to <a target="_blank" href="https://github.com/kelunik">Niklas Keller</a>, one of the developers of Amp.
He pointed out some mistakes in our previous benchmarks, and helped making them more fair.</p>
<p>The new benchmarks compare a few scenarios.
The first two groups plot the execution time of an empty process,
while the third and fourth groups show the execution time of processes with a different time to finish,
using several <code>sleep</code> intervals.
Between the two groups, we're also comparing a capped concurrency configuration and a non-capped configuration.
Capped means that there are more processes than the pool can execute at once.</p>
<p>The benchmark code can be found <a target="_blank" href="https://github.com/spatie/async-benchmark">here</a>.</p>
<p><img src="/resources/img/blog/async/benchmarks.png" srcset="/resources/img/blog/async/benchmarks-489x301.png 489w, /resources/img/blog/async/benchmarks-599x369.png 599w, /resources/img/blog/async/benchmarks-692x427.png 692w, /resources/img/blog/async/benchmarks-773x477.png 773w, /resources/img/blog/async/benchmarks-346x213.png 346w" sizes="" alt="Comparing Amp and spatie/async"><em class="small center">Comparing Amp and spatie/async</em></img></p>
<p>I tried to draw a few conclusions from these test.</p>
<ul>
<li>Real life processes take time to run and finish.
For our use-cases, the "with logic" benchmarks are more relevant.</li>
<li>Regarding process execution time, it seems like our package has less overhead:
as long as the pool doesn't have to manage concurrency, we're finishing faster.</li>
<li>In real life applications though, the maximum concurrency setting will most likely be in effect,
so it's clear that we'll need to improve that part of our codebase if we want better performance compared to Amp.</li>
</ul>
<h2 id="what-about-reactphp?"><a href="#what-about-reactphp?" class="heading-anchor">#</a> What about ReactPHP?</h2>
<p>We've excluded ReactPHP from the benchmarks, because it's not a fair comparison.
ReactPHP doesn't allow to run closures or <code>Tasks</code> as sub-processes the way Amp and our package do.
With ReactPHP, you're working with plain processes, so there's no way to compare to it.</p>
<h2 id="about-process-signals"><a href="#about-process-signals" class="heading-anchor">#</a> About process signals</h2>
<p>The biggest difference between our package and Amp is the way of communicating between processes.
We're solely relying on process signals to determine when a process is finished.
It allows for less overhead, but also excludes Windows as a target platform.</p>
<p>Processes in UNIX systems can send signals to each other.
Depending on what kind of signal is received, a process will act different.
Signals are handled by the kernel, so they are pretty low level.
Before PHP 7.1 though, you had to <code>declare(ticks=1)</code> to use asynchronous signals in a reliable way.
This means that PHP will check for signals much more often, but it also introduces a lot of overhead:</p>
<blockquote>
<p>A tick is an event that occurs for every N low-level tickable statements executed by the parser within the declare block. The value for N is specified using ticks=N within the declare block's directive section.</p>
</blockquote>
<p>With PHP 7.1, there's a new way of handling interrupts sent by the kernel.</p>
<blockquote>
<p>Zend Engine in PHP 7.1 was extended with ability of safe time-out and interrupt handling. Actually, PHP VM checks for EG(vm_interrupt) flag on each loop iteration, user function entry or internal function exit, and call callback function if necessary.</p>
</blockquote>
<p>By using <code>pcntl_async_signals(true)</code>, PHP will now check for signals in a much more performant way.
A more in-depth explanation can be found in the <a target="_blank" href="https://wiki.php.net/rfc/async_signals">rfc</a>,
submitted by Dmitry Stogov.</p>
<p>It's thanks to this mechanism that we're able to act on process status changes in a real asynchronous way,
without having to rely on sockets or process status polling.</p>
 ]]></summary>

                <updated>2017-12-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Optimised UUIDs in mysql ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/optimised-uuids-in-mysql"/>

                <id>https://www.stitcher.io/blog/optimised-uuids-in-mysql</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>At <a target="_blank" href="https://www.spatie.be">Spatie</a>, we're working on a large project which uses UUIDs in many database tables.
These tables vary in size from a few thousand records to half a million.</p>
<p>As you might know, normal UUIDs are stored as <code>CHAR(36)</code> fields in the database.
This has an enormous performance cost, because MySQL is unable to properly index these records.
Take a look at the following graph, plotting the execution time of hundred queries against two datasets: one with 50k rows, one with 500k rows.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p><img src="/resources/img/blog/binary-uuid/textual_uuid.png" srcset="/resources/img/blog/binary-uuid/textual_uuid-703x434.png 703w, /resources/img/blog/binary-uuid/textual_uuid-812x501.png 812w, /resources/img/blog/binary-uuid/textual_uuid-908x561.png 908w, /resources/img/blog/binary-uuid/textual_uuid-406x250.png 406w, /resources/img/blog/binary-uuid/textual_uuid-574x354.png 574w" sizes="" alt=""></img></p>
<p><em>That's an average of more than 1.5 seconds when using textual UUIDs!</em></p>
<p>There's an <strong>important edit</strong> here: the benchmark above was performed on un-indexed fields.
I've since changed the benchmark results to work with indexed textual fields for a more fair comparison.
There's still a performance gain to not using textual UUIDs, so keep reading!</p>
<p>Looking around for better alternatives, we found a two-part solution.</p>
<h2 id="saving-uuids-as-binary-data"><a href="#saving-uuids-as-binary-data" class="heading-anchor">#</a> Saving UUIDs as binary data</h2>
<p>Instead of saving UUIDs as <code>CHAR</code>, it's possible to store their actual binary data in a <code>BINARY</code> field.
Storing them in this format, MySQL has a lot less trouble indexing this table.
This is the graph plotting a much faster result.</p>
<p><img src="/resources/img/blog/binary-uuid/binary_uuid.png" srcset="/resources/img/blog/binary-uuid/binary_uuid-574x354.png 574w, /resources/img/blog/binary-uuid/binary_uuid-908x561.png 908w, /resources/img/blog/binary-uuid/binary_uuid-812x501.png 812w, /resources/img/blog/binary-uuid/binary_uuid-406x250.png 406w, /resources/img/blog/binary-uuid/binary_uuid-703x434.png 703w" sizes="" alt=""></img></p>
<p>That's an average of 0.00008832061291 seconds per query,
in comparison to ~~1.5~~ 0.0001493031979 seconds for the <strong>indexed</strong> textual UUID.</p>
<h2 id="it-becomes-even-better!"><a href="#it-becomes-even-better!" class="heading-anchor">#</a> It becomes even better!</h2>
<p>The binary encoding of UUIDs solved most of the issue.
There's one extra step to take though,
which allows MySQL to even better index this field for large datasets.</p>
<p>By switching some of the bits in the UUID, more specifically time related data,
we're able to save them in a more ordered way.
And it seems that MySQL is especially fond of ordered data when creating indices.
There's one important thing to note: this time related bits are only available in UUID version 1.</p>
<p>Using this approach, we can see following result.</p>
<p><img src="/resources/img/blog/binary-uuid/comparison.png" srcset="/resources/img/blog/binary-uuid/comparison-419x258.png 419w, /resources/img/blog/binary-uuid/comparison-937x579.png 937w, /resources/img/blog/binary-uuid/comparison-592x365.png 592w, /resources/img/blog/binary-uuid/comparison-838x517.png 838w, /resources/img/blog/binary-uuid/comparison-725x447.png 725w" sizes="" alt=""></img></p>
<p>The optimised approach is actually slower for lookups in a small table,
but it outperforms the normal binary approach on larger datasets.
It even performs better than an <code>AUTO_INCREMENT</code> integer ID!
But as you can see, we need very large tables before the optimised UUID has a benefit.</p>
<p>I would recommend only using UUIDs when there's a very good use case for them.
For example: when you want unique IDs over all tables, and not just one;
or if you want to hide exactly how many rows there are in the table.</p>
<p>The MySQL team wrote a <a target="_blank" href="http://mysqlserverteam.com/storing-uuid-values-in-mysql-tables/">blogpost</a>
explaining this bit-shifting of UUIDs in further detail.
If you'd like to know how it works internally, over there is a good start.</p>
<p>If you're building a Laravel application and would like to use optimised UUIDs in your project,
we've made <a target="_blank" href="https://github.com/spatie/laravel-binary-uuid">a package</a> especially for you.
You'll also find more benchmark details in the README over there.</p>
<p>Finally, if you're looking into implementing this behaviour in a non-Laravel project,
you should definitely take a look at <a target="_blank" href="https://github.com/ramsey/uuid">Ramsey's UUID package</a>, we're using it too!</p>
 ]]></summary>

                <updated>2017-11-29T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Improving PHPStorm&#039;s performance ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/phpstorm-performance"/>

                <id>https://www.stitcher.io/blog/phpstorm-performance</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Let's just dive right in.</p>
<h2 id="java-vm-options"><a href="#java-vm-options" class="heading-anchor">#</a> Java VM options</h2>
<p>PHPStorm is made in Java. If you ever played Minecraft, you know you could allocate extra RAM by adding
flags to your startup command. You can also do this in PHPStorm, it's even built into the UI.</p>
<p>Go to <code>help &gt; Edit Custom VM Options</code>. You can play around with the settings here.
I for one changed the maximum amount of RAM allocated to PHPStorm, and added two graphics options
(at the end of the file).</p>
<pre>-Xms500m
-Xmx1500m

-Dawt.useSystemAAFontSettings=lcd
-Dawt.java2d.opengl=true

# Only for people on Mac, it makes Java use an optimised graphics engine.
-Dapple.awt.graphics.UseQuartz=true
</pre>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="custom-properties"><a href="#custom-properties" class="heading-anchor">#</a> Custom properties</h2>
<p>PHPStorm also has a file to set custom properties: <code>help &gt; Edit Custom Properties</code>.
Adding one option here changed the way PHPStorm renders text: it will show text immediately,
instead of analysing it first. The downside is that you can sometimes see a flash of unstyled text.
It feels much smoother though.</p>
<pre>editor.zero.latency.typing=true
</pre>
<h2 id="inspections-and-plugins"><a href="#inspections-and-plugins" class="heading-anchor">#</a> Inspections and plugins</h2>
<p>PHPStorm is a powerful IDE, with lots of functionality built in by default. While I'd highly recommend using
these options to their full extent, there are some things that are never used.</p>
<p>Disabling unused plugins can be a start, but disabling inspections has a much bigger impact.
Take a look at the list and decide for yourself which ones you don't need: <code>Settings &gt; Editor &gt; Inspections</code>.</p>
<h2 id="language-injection"><a href="#language-injection" class="heading-anchor">#</a> Language injection</h2>
<p>One plugin in particular has a big performance impact: <code>IntelliLang</code>. This plugins allows for
languages to be recognised in different file formats. Eg. HTML autocompletion and highlighting in a PHP file.</p>
<p>I would not recommend completely disabling this plugin, but there might be some injections
which you don't need in your projects: <code>Settings &gt; Editor &gt; Language Injections</code>.</p>
<h2 id="project-setup"><a href="#project-setup" class="heading-anchor">#</a> Project setup</h2>
<p>Managing which files PHPStorm must index has to be done on a project level basis.
It is worth spending 5 minutes on initial project setup, for projects you'll work hours and days on.</p>
<h3 id="excluding-directories"><a href="#excluding-directories" class="heading-anchor">#</a> Excluding directories</h3>
<p>Go to <code>Settings &gt; Directories</code> to mark directories as excluded. PHPStorm won't index these files.
Directories to exclude would be eg. cache, public and storage directories;
directories which contain generated files from asset building, and last but not least: <code>vendor</code> and <code>node_modules</code>.</p>
<h3 id="the-vendor-problem"><a href="#the-vendor-problem" class="heading-anchor">#</a> The vendor problem</h3>
<p>Excluding directories from indexing means no auto-complete from those directories.
So excluding the vendor directory might not be the best idea.
There's a neat little trick though, which allows you to whitelist vendor directories you want to use,.</p>
<p>Go to <code>Settings &gt; Languages &amp; Frameworks &gt; PHP</code>. In here you can set include paths.
By manually specifying which vendor directories should be indexed, you can eliminate a lot of indexing time.
You might eg. always keep dependencies of vendors excluded, because chances are you won't be using those APIs.
If you come across a vendor you need auto-completion for, just add it to the list.</p>
<h3 id="node-modules"><a href="#node-modules" class="heading-anchor">#</a> Node modules</h3>
<p>Node modules are "excluded" by default, but they are added as include paths nevertheless.
Because of the size of the <code>node_modules</code> directory, it can take quite a while to index it.</p>
<p>JavaScript include paths are managed like PHP includes, but in <code>Settings &gt; Languages &amp; Frameworks &gt; JavaScript &gt; Libraries</code>.
I personally don't write a lot of JavaScript, so I just remove the inclusion of <code>node_modules</code> completely.</p>
<p>Managing directories requires a bit of time for each project, but it's worth the performance gain in the long run.</p>
<h2 id="font-rendering-on-osx"><a href="#font-rendering-on-osx" class="heading-anchor">#</a> Font rendering on OSX</h2>
<p>There's a confirmed issue in the JRE with certain fonts.
While this might seem like a minor detail, certain fonts actually require a lot of processor power to render text,
slowing down PHPStorm in its whole.</p>
<p>I've written a separate blog post on this issue, and how you can fix it.
You can read it <a href="/blog/phpstorm-performance-issues-on-osx">here</a>.</p>
<h2 id="on-a-personal-note"><a href="#on-a-personal-note" class="heading-anchor">#</a> On a personal note</h2>
<p>I didn't start this post by writing my own thoughts, because I figured people were looking for some quick tips to speed of their IDE.
As a PHP developer, I think that PHPStorm is such a powerful tool, which helps me to write good and maintainable code.
I don't want it to stand in my way though, so good performance is an absolute requirement.</p>
<p>With the things listed above, I feel that PHPStorm offers the best balance between performance and intelligence.
I've written PHP in Sublime Text for ± 5 years. I did put some time into tweaking PHPStorm to my needs,
and now I'm 100% sure I'll never go back to Sublime Text.
My IDE is just way too smart and helpful to me. It allows me to focus on real application logic,
instead of writing the same boilerplate code over and over again.
I'll talk more about the benefits of an IDE over a text editor in another post.
For now, I hope that you found these tips helpful.</p>
<p>Happy coding!</p>
<hr />
<p>Ready for more? I've got a new blog post full of <a href="/blog/phpstorm-tips-for-power-users">tips for PHPStorm users</a>!</p>
 ]]></summary>

                <updated>2017-10-22T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Stitcher beta 2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/stitcher-beta-2"/>

                <id>https://www.stitcher.io/blog/stitcher-beta-2</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>The second beta release of Stitcher ties a lot of loose ends together, getting ready for real production sites.</p>
<h3 id="installation"><a href="#installation" class="heading-anchor">#</a> Installation</h3>
<pre>composer require pageon/stitcher-core @beta
</pre>
<h3 id="changelog"><a href="#changelog" class="heading-anchor">#</a> Changelog</h3>
<p>Note the a few config parameters are changed. These changes might fall under the category "breaking",
but were really needed in order to get a more consistent API, before a real 1.0.0 release comes along.</p>
<ul>
<li>Add Parsedown extension to support classes on <code>&lt;pre&gt;</code> tags in fenced code blocks.</li>
<li>Disable directory listing via .htaccess.</li>
<li>Add <code>redirect.www</code> and <code>redirect.https</code> options. Allowing to automatically redirect non-www to www, and http to https.</li>
<li>Add <code>redirect</code> option in site config files to make a route redirect to another page.</li>
<li>Use <code>pageon/html-meta</code> ^2.0 from now on. Lots of tweaks to social meta tags were added.</li>
<li>Add <code>async</code> option which, when <code>ext-pcntl</code> is installed, will enable asynchronous page rendering.</li>
<li>Add Parsedown extension to support <code>target=&quot;_blank&quot;</code> links by prefixing the URL with <code>*</code>.</li>
<li>Add <code>sitemap.xml</code> support. When setting the <code>sitemap.url</code> variable, a <code>sitemap.xml</code> will be generated.</li>
<li>Fix bug with Collection Adapters not copying meta tags from the base page for its sub-pages.</li>
<li>Add responsive images support to markdown parser.</li>
<li>The following config parameters are changed (#2):
<ul>
<li>
<code>caches.cdn</code> becomes <code>cache.cdn</code>.</li>
<li>
<code>caches.image</code> becomes <code>cache.images</code>.</li>
<li>
<code>directories.htaccess</code> is removed.</li>
<li>
<code>minify</code> becomes <code>engines.minifier</code>
</li>
</ul>
</li>
<li>Support multiple extensions per template engine (#7).</li>
<li>Support nested conditions in the filter adapter (#1).</li>
<li>Remove unused <code>eninges.async</code> option.</li>
</ul>
 ]]></summary>

                <updated>2017-08-27T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Mastering key bindings ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/mastering-key-bindings"/>

                <id>https://www.stitcher.io/blog/mastering-key-bindings</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>This blog post aims to make you think about the way you use key bindings whilst programming.
You'll read about some techniques I use to assign key bindings, how to memorise them, and use them efficiently.
But before we go on, I'll need to explain why spending time on key bindings is worth the effort.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<h2 id="the-need-for-keys"><a href="#the-need-for-keys" class="heading-anchor">#</a> The need for keys</h2>
<p>I can't point to some psychological study to back this claim, just my own experience and common sense.
Using the mouse as less as possible when coding is a good thing.
You're not moving your hands around to grab the mouse, which saves time.
Also you don't have to make the mental switch between using a keyboard and a mouse as input device.</p>
<p>I believe these small things have the power to improve our skills as professional programmers significantly.
I've experienced a lot of gain by taking the time to learn to use the keyboard as often as I can.
While I'm still searching the optimal setup, I can already share some thoughts and techniques.
The most important thing to know is that key bindings are a matter of personal taste.
So don't take these next points as law, but rather apply them to your own situation.</p>
<blockquote>
<p>Key bindings are a personal preference.</p>
</blockquote>
<h2 id="the-meaning-of-modifiers"><a href="#the-meaning-of-modifiers" class="heading-anchor">#</a> The meaning of modifiers</h2>
<p>A keyboard has a few modifier keys, which allow you to modify the behaviour of other key presses.
A long time ago these keys were actually hard wired in the keyboard, to change the electronic bits sent to the computer.
In this modern time, it's still good to look at what their original meaning was.
It helped me define a formal definition for each modifier key, allowing me to remember what key combination belongs to which action.</p>
<blockquote>
<p>Define a personal meaning for each modifier key, and stick to it.</p>
</blockquote>
<h3 id="meta/command-(⌘)"><a href="#meta/command-(⌘)" class="heading-anchor">#</a> Meta/Command (⌘)</h3>
<p>I use this key when "executing" commands. Basically most of what's possible through the menu of an application.</p>
<h3 id="option/alt-(⌥)"><a href="#option/alt-(⌥)" class="heading-anchor">#</a> Option/Alt (⌥)</h3>
<p>Alt stands for "alternate", changing the behaviour of another key combination. I use this key for a related action
of another key binding.</p>
<h3 id="shift-(⇧)"><a href="#shift-(⇧)" class="heading-anchor">#</a> Shift (⇧)</h3>
<p>Shift has a double meaning. First it's used for selections, because that's default OS behaviour.
Second, it's also often used to reverse the action.</p>
<p>I prefer a maximum of two modifier keys, and if complexer combinations are needed, opt for <strong>double key bindings</strong>.
One exception though: Shift (⇧) may be used in combination with other modifier keys to reverse the action.</p>
<blockquote>
<p>Prefer at most two modifier keys, or use double key bindings.</p>
</blockquote>
<h3 id="control/ctrl-(^)"><a href="#control/ctrl-(^)" class="heading-anchor">#</a> Control/Ctrl (^)</h3>
<p>I use the control key for text- and code related manipulations.
Actions like moving the cursor, working with selections, working with lines, etc.
I find it hard to give a formal definition for the Control key, but its use is clear in most cases.</p>
<p>A note for Windows users: the Control key is used much more in comparison to the Meta (Windows) key.
Meaning you probably want to switch the definition of the two, or even ditch the Meta key.
Even though this might seem like a good idea, adding the meta key in your workflow can be a good thing,
as it adds another modifier key to your availability.</p>
<h3 id="function-(fn)"><a href="#function-(fn)" class="heading-anchor">#</a> Function (fn)</h3>
<p>Because the function key is often not accessible on desktop keyboards, I choose not to depend on this key.
I only make an exception for some edge cases like page-up or page-down.</p>
<h2 id="learning"><a href="#learning" class="heading-anchor">#</a> Learning</h2>
<p>Keeping my own definitions in mind, it's easy to start defining key bindings. Though to remember them requires practice.
I'd recommend not assigning all key bindings at once, but rather slowly add them when you need them.</p>
<blockquote>
<p>Assign new key bindings when you need them.</p>
</blockquote>
<p>I choose not to override operating system (OS) key bindings. Things like <code>copy</code>, <code>paste</code>, <code>select all</code> or <code>quit</code> are
never overridden.
Key binding defaults provided by your IDE or editor, however, may be changed.
If you come from Sublime Text like me, you've probably learned some defaults which you are accustomed with.
When switching to PHPStorm a few years ago, I decided to keep some of those key bindings I knew from Sublime.</p>
<blockquote>
<p>There's no need to change OS-level key bindings like <code>copy</code> or <code>select all</code>.</p>
</blockquote>
<p>Even now, I'm still changing key bindings from time to time. Especially when I came up with my definition list.
One thing I find useful when learning new key bindings, is to disable the old ones. IDEs like PHPStorm allow you to add
multiple combinations for the same action. I prefer to immediately notice when I'm using an old combination.
This makes me learn faster.</p>
<blockquote>
<p>Remove key bindings you wish to unlearn.</p>
</blockquote>
<p>Furthermore, when stuck in a situation, I try not to immediately grab the mouse.
I try to think the problem and define what I want to do.
Most of the time, I can remember which combination of keys should be pressed, because of the definition list above.
When my memory fails me, I'm lucky to be working in an IDE with awesome key binding management,
so it's easy to find the correct combination back.</p>
<blockquote>
<p>Don't grab the mouse when panicking.</p>
</blockquote>
<p>Your keymap is a very personal file, which slowly grows to match your workflow the best. I recommend you storing a backup
of your keymap somewhere else, GitHub would be a good place.
<a target="_blank" href="https://github.com/brendt/settings-repository/blob/master/keymaps/Brendt.xml">Here's mine</a>.</p>
<blockquote>
<p>Check your keymap into version control.</p>
</blockquote>
<h3 id="a-few-of-my-own-examples"><a href="#a-few-of-my-own-examples" class="heading-anchor">#</a> A few of my own examples</h3>
<ul>
<li>
<code>⌘ p</code> Search file</li>
<li>
<code>⌘ ⇧ p</code> Search recent files</li>
<li>
<code>⌘ ⌥ p</code> Search symbols in file</li>
<li>
<code>⌘ ⌥ space</code> Show suggestions</li>
<li>
<code>⌘ ⌥ enter</code> Go to declaration</li>
<li>
<code>^ ⌥ →</code> Move right with camelHops</li>
<li>
<code>^ ⌥ ←</code> Move left with camelHops</li>
<li>
<code>⌥ ↑</code>  Move cursor paragraph up</li>
<li>
<code>⌥ ↓</code>  Move cursor paragraph down</li>
<li>
<code>⇧ ⌥ ↑</code> Extend selection</li>
<li>
<code>⇧ ⌥ ↓</code> Shrink selection</li>
</ul>
<h2 id="closing-thoughts"><a href="#closing-thoughts" class="heading-anchor">#</a> Closing thoughts</h2>
<p>I grew in love with key bindings over the years. I still use the mouse for basic navigation,
but once I start coding, I try to use it as little as possible. I find that it's easier to work this way.
Not only do I gain time by not switching as often to the mouse; I also find it puts less cognitive load on my brain,
meaning I'm able to concentrate more on coding.</p>
<p>This might seem like a small thing to do, but as a professional programmer, you're doing those small things many,
many times a day. It's worth taking the time to optimise these areas and skills, I find they make me a better programmer.</p>
<p>Do you want to read more about cognitive load? I've written about <a target="_blank" href="https://www.stitcher.io/blog/a-programmers-cognitive-load">fonts and visuals</a>
in a previous blog post. Do you still have a question or something on your mind? <a href="mailto:brendt@stitcher.io">Send me an email</a>!</p>
 ]]></summary>

                <updated>2017-08-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Responsive images as CSS background ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/responsive-images-as-css-background"/>

                <id>https://www.stitcher.io/blog/responsive-images-as-css-background</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Integrating the <a target="_blank" href="https://responsiveimages.org/">Responsive Images spec</a> together with CSS backgrounds, allowing for more flexibility for eg. hero images because you can use <code>background-size: cover;</code> etc., and still have the full benefits of responsive image loading.</p>
<pre>&lt;<span class="hl-keyword">html</span>&gt;
&lt;<span class="hl-keyword">head</span>&gt;
    &lt;<span class="hl-keyword">style</span>&gt;<span class="hl-keyword">
        img </span>{
            <span class="hl-property">width</span>:100%;
        }<span class="hl-keyword">
        img.loaded </span>{
            <span class="hl-property">display</span>: none;
        }<span class="hl-keyword">
        .responsive-image </span>{
            <span class="hl-property">width</span>:100%;
            <span class="hl-property">height</span>:500px;
            <span class="hl-property">background-size</span>: cover;
            <span class="hl-property">background-position</span>: center;
        }
    &lt;/<span class="hl-keyword">style</span>&gt;
&lt;/<span class="hl-keyword">head</span>&gt;
&lt;<span class="hl-keyword">body</span>&gt;
    &lt;<span class="hl-keyword">div</span> <span class="hl-property">class</span>=&quot;responsive-image&quot;&gt;
        &lt;<span class="hl-keyword">img</span> <span class="hl-property">src</span>=&quot;./small.jpg&quot; <span class="hl-property">srcset</span>=&quot;./large.png 3000w, ./medium.jpg 1920w, ./small.jpg 425w&quot; &gt;
    &lt;/<span class="hl-keyword">div</span>&gt;
    
    &lt;<span class="hl-keyword">script</span>&gt;
        document.<span class="hl-property">addEventListener</span>('<span class="hl-value">DOMContentLoaded</span>', <span class="hl-keyword">function</span>() {
            <span class="hl-keyword">const</span> images = document.<span class="hl-property">querySelectorAll</span>('<span class="hl-value">.responsive-image</span>');
            
            [].<span class="hl-property">forEach</span>.<span class="hl-property">call</span>(images, <span class="hl-keyword">function</span> (imageContainer) {
                <span class="hl-keyword">const</span> image = imageContainer.<span class="hl-property">querySelector</span>('<span class="hl-value">img</span>');
                
                image.<span class="hl-property">addEventListener</span>('<span class="hl-value">load</span>', <span class="hl-keyword">function</span> () {
                    <span class="hl-keyword">if</span> (!image.<span class="hl-property">currentSrc</span>) {
                        <span class="hl-keyword">return</span>;
                    }
                    
                    imageContainer.<span class="hl-property">style</span>['<span class="hl-value">background-image</span>'] = &quot;<span class="hl-value">url('</span><span class="hl-value">&quot; + image.currentSrc + &quot;</span><span class="hl-value">')</span>&quot;;
                    image.<span class="hl-property">classList</span>.<span class="hl-property">add</span>('<span class="hl-value">loaded</span>');
                });
            })
        });
    &lt;/<span class="hl-keyword">script</span>&gt;
&lt;/<span class="hl-keyword">body</span>&gt;
&lt;/<span class="hl-keyword">html</span>&gt;
</pre>
 ]]></summary>

                <updated>2017-06-24T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Object oriented generators ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/object-oriented-generators"/>

                <id>https://www.stitcher.io/blog/object-oriented-generators</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>The following code shows an object oriented way of implementing a well known generator function: to read lines from a large file.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">FileReader</span> <span class="hl-keyword">implements</span><span class="hl-type"> </span>\Iterator 
{
    <span class="hl-keyword">private</span> <span class="hl-property">$handle</span>;
    <span class="hl-keyword">private</span> <span class="hl-property">$current</span>;

    <span class="hl-keyword">public</span> <span class="hl-keyword">static</span> <span class="hl-keyword">function</span> <span class="hl-property">read</span>(<span class="hl-injection"><span class="hl-type">string</span> $fileName</span>) : <span class="hl-type">FileReader</span> {
        <span class="hl-keyword">return</span> <span class="hl-keyword">new</span> <span class="hl-type">self</span>(<span class="hl-variable">$fileName</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>(<span class="hl-injection"><span class="hl-type">string</span> $fileName</span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">handle</span> = <span class="hl-property">fopen</span>(<span class="hl-variable">$fileName</span>, '<span class="hl-value">r</span>');
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">next</span>();
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__destruct</span>() {
        <span class="hl-property">fclose</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">handle</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">current</span>() {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">current</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">next</span>() {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">current</span> = <span class="hl-property">fgets</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">handle</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">key</span>() {
        <span class="hl-keyword">return</span> <span class="hl-property">ftell</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">handle</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">valid</span>() {
        <span class="hl-keyword">return</span> !<span class="hl-property">feof</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">handle</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">rewind</span>() {
        <span class="hl-property">rewind</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">handle</span>);
    }
}
</pre>
<p>Using the file reader.</p>
<pre><span class="hl-variable">$lines</span> = <span class="hl-type">FileReader</span>::<span class="hl-property">read</span>('<span class="hl-value">path_to_large_file.txt</span>');

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$lines</span> <span class="hl-keyword">as</span> <span class="hl-variable">$line</span>) {
    <span class="hl-keyword">echo</span> <span class="hl-variable">$line</span>;
}
</pre>
<p>A comparison to using generators and the <code>yield</code> keyword, based on the tests I ran:</p>
<ul>
<li>This approach takes the same amount of time to execute.</li>
<li>It has the same memory footprint as a generator function.</li>
<li>It has the benefit of easier re-usability (in my opinion).</li>
</ul>
<p>In comparison to <code>file_get_contents</code>: reading the same file required of 15MB of memory, whilst
this solution required only 2MB, because it only reads one line in memory at a time.</p>
<p>To round up, this is the generator solution using <code>yield</code>.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">read</span>(<span class="hl-injection">$fileName</span>) {
    <span class="hl-variable">$handle</span> = <span class="hl-property">fopen</span>(<span class="hl-variable">$fileName</span>, '<span class="hl-value">r</span>');

    <span class="hl-keyword">while</span> (!<span class="hl-property">feof</span>(<span class="hl-variable">$handle</span>)) {
        <span class="hl-keyword">yield</span> <span class="hl-property">fgets</span>(<span class="hl-variable">$handle</span>);
    }

    <span class="hl-property">fclose</span>(<span class="hl-variable">$handle</span>);
}

<span class="hl-variable">$lines</span> = <span class="hl-property">read</span>('<span class="hl-value">path_to_large_file</span>');

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$lines</span> <span class="hl-keyword">as</span> <span class="hl-variable">$line</span>) {
    <span class="hl-keyword">echo</span> <span class="hl-variable">$line</span>;
}
</pre>
 ]]></summary>

                <updated>2017-06-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Process forks ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/process-forks"/>

                <id>https://www.stitcher.io/blog/process-forks</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <pre><span class="hl-keyword">function</span> <span class="hl-property">async</span>(<span class="hl-injection"><span class="hl-type">Process</span> $process</span>) : <span class="hl-type">Process</span> {
    <span class="hl-property">socket_create_pair</span>(<span class="hl-property">AF_UNIX</span>, <span class="hl-property">SOCK_STREAM</span>, 0, <span class="hl-variable">$sockets</span>);
    [<span class="hl-variable">$parentSocket</span>, <span class="hl-variable">$childSocket</span>] = <span class="hl-variable">$sockets</span>;

    <span class="hl-keyword">if</span> ((<span class="hl-variable">$pid</span> = <span class="hl-property">pcntl_fork</span>()) == 0) {
        <span class="hl-property">socket_close</span>(<span class="hl-variable">$childSocket</span>);
        <span class="hl-property">socket_write</span>(<span class="hl-variable">$parentSocket</span>, <span class="hl-property">serialize</span>(<span class="hl-variable">$process</span>-&gt;<span class="hl-property">execute</span>()));
        <span class="hl-property">socket_close</span>(<span class="hl-variable">$parentSocket</span>);
        <span class="hl-keyword">exit</span>;
    }

    <span class="hl-property">socket_close</span>(<span class="hl-variable">$parentSocket</span>);

    <span class="hl-keyword">return</span> <span class="hl-variable">$process</span>
        -&gt;<span class="hl-property">setStartTime</span>(<span class="hl-property">time</span>())
        -&gt;<span class="hl-property">setPid</span>(<span class="hl-variable">$pid</span>)
        -&gt;<span class="hl-property">setSocket</span>(<span class="hl-variable">$childSocket</span>);
}

<span class="hl-keyword">function</span> <span class="hl-property">wait</span>(<span class="hl-injection"><span class="hl-type">array</span> $processes</span>) : <span class="hl-type">array</span> {
    <span class="hl-variable">$output</span> = [];

    <span class="hl-keyword">while</span> (<span class="hl-property">count</span>(<span class="hl-variable">$processes</span>)) {
        <span class="hl-keyword">foreach</span> (<span class="hl-variable">$processes</span> <span class="hl-keyword">as</span> <span class="hl-variable">$key</span> =&gt; <span class="hl-variable">$process</span>) {
            <span class="hl-variable">$processStatus</span> = <span class="hl-property">pcntl_waitpid</span>(<span class="hl-variable">$process</span>-&gt;<span class="hl-property">getPid</span>(), <span class="hl-variable">$status</span>, <span class="hl-property">WNOHANG</span> | <span class="hl-property">WUNTRACED</span>);

            <span class="hl-keyword">if</span> (<span class="hl-variable">$processStatus</span> == <span class="hl-variable">$process</span>-&gt;<span class="hl-property">getPid</span>()) {
                <span class="hl-variable">$output</span>[] = <span class="hl-property">unserialize</span>(<span class="hl-property">socket_read</span>(<span class="hl-variable">$process</span>-&gt;<span class="hl-property">getSocket</span>(), 4096));
                <span class="hl-property">socket_close</span>(<span class="hl-variable">$process</span>-&gt;<span class="hl-property">getSocket</span>());
                <span class="hl-variable">$process</span>-&gt;<span class="hl-property">triggerSuccess</span>();

                <span class="hl-keyword">unset</span>(<span class="hl-variable">$processes</span>[<span class="hl-variable">$key</span>]);
            } <span class="hl-keyword">else</span> <span class="hl-keyword">if</span> (<span class="hl-variable">$processStatus</span> == 0) {
                <span class="hl-keyword">if</span> (<span class="hl-variable">$process</span>-&gt;<span class="hl-property">getStartTime</span>() + <span class="hl-variable">$process</span>-&gt;<span class="hl-property">getMaxRunTime</span>() &lt; <span class="hl-property">time</span>() <span class="hl-operator">||</span> <span class="hl-property">pcntl_wifstopped</span>(<span class="hl-variable">$status</span>)) {
                    <span class="hl-keyword">if</span> (!<span class="hl-property">posix_kill</span>(<span class="hl-variable">$process</span>-&gt;<span class="hl-property">getPid</span>(), <span class="hl-property">SIGKILL</span>)) {
                        <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">\Exception</span>(&quot;<span class="hl-value">Failed to kill {$process-&gt;getPid()}: </span>&quot; . <span class="hl-property">posix_strerror</span>(<span class="hl-property">posix_get_last_error</span>()));
                    }
                    
                    <span class="hl-keyword">unset</span>(<span class="hl-variable">$processes</span>[<span class="hl-variable">$key</span>]);
                }
            } <span class="hl-keyword">else</span> {
                <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">\Exception</span>(&quot;<span class="hl-value">Could not reliably manage process {$process-&gt;getPid()}</span>&quot;);
            }
        }
        
        <span class="hl-keyword">if</span> (!<span class="hl-property">count</span>(<span class="hl-variable">$processes</span>)) {
            <span class="hl-keyword">break</span>;
        }

        <span class="hl-property">usleep</span>(100000);
    }

    <span class="hl-keyword">return</span> <span class="hl-variable">$output</span>;
}
</pre>
<p>The <code>Process</code> class, used to pass data in a defined way.</p>
<pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Process</span>
{
    <span class="hl-keyword">protected</span> <span class="hl-property">$pid</span>;
    <span class="hl-keyword">protected</span> <span class="hl-property">$name</span>;
    <span class="hl-keyword">protected</span> <span class="hl-property">$socket</span>;
    <span class="hl-keyword">protected</span> <span class="hl-property">$successCallback</span>;
    <span class="hl-keyword">protected</span> <span class="hl-property">$startTime</span>;
    <span class="hl-keyword">protected</span> <span class="hl-property">$maxRunTime</span> = 300;
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">abstract</span> <span class="hl-keyword">function</span> <span class="hl-property">execute</span>();

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">onSuccess</span>(<span class="hl-injection"><span class="hl-type">callable</span> $callback</span>) : <span class="hl-type">Process</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">successCallback</span> = <span class="hl-variable">$callback</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">triggerSuccess</span>() {
        <span class="hl-keyword">if</span> (!<span class="hl-variable">$this</span>-&gt;<span class="hl-property">successCallback</span>) {
            <span class="hl-keyword">return</span> <span class="hl-keyword">null</span>;
        }

        <span class="hl-keyword">return</span> <span class="hl-property">call_user_func_array</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">successCallback</span>, [<span class="hl-variable">$this</span>]);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setPid</span>(<span class="hl-injection">$pid</span>) : <span class="hl-type">Process</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pid</span> = <span class="hl-variable">$pid</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getPid</span>() {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">pid</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setSocket</span>(<span class="hl-injection">$socket</span>) : <span class="hl-type">Process</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">socket</span> = <span class="hl-variable">$socket</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getSocket</span>() {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">socket</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setName</span>(<span class="hl-injection"><span class="hl-type">string</span> $name</span>) : <span class="hl-type">Process</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">name</span> = <span class="hl-variable">$name</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getName</span>() : <span class="hl-type">string</span> {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">name</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setStartTime</span>(<span class="hl-injection">$startTime</span>) {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">startTime</span> = <span class="hl-variable">$startTime</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getStartTime</span>() {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">startTime</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">setMaxRunTime</span>(<span class="hl-injection"><span class="hl-type">int</span> $maxRunTime</span>) : <span class="hl-type">Process</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">maxRunTime</span> = <span class="hl-variable">$maxRunTime</span>;

        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getMaxRunTime</span>() : <span class="hl-type">int</span> {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">maxRunTime</span>;
    }
}
</pre>
<p>A concrete Process implementation.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">MyProcess</span> <span class="hl-keyword">extends</span> <span class="hl-type">Process</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">execute</span>() {
        <span class="hl-property">sleep</span>(1);
        
        <span class="hl-keyword">return</span> <span class="hl-keyword">true</span>;
    }
}
</pre>
<p>And bringing it all together.</p>
<pre><span class="hl-variable">$processA</span> = <span class="hl-property">async</span>(<span class="hl-keyword">new</span> <span class="hl-type">MyProcess</span>());
<span class="hl-variable">$processB</span> = <span class="hl-property">async</span>(<span class="hl-keyword">new</span> <span class="hl-type">MyProcess</span>());

<span class="hl-variable">$output</span> = <span class="hl-property">wait</span>([<span class="hl-variable">$processA</span>, <span class="hl-variable">$processB</span>]);

<span class="hl-property">print_r</span>(<span class="hl-variable">$output</span>);
<span class="hl-keyword">die</span>('<span class="hl-value">Done!</span>');
</pre>
 ]]></summary>

                <updated>2017-06-09T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Performance 101: building the better web ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/performance-101-building-the-better-web"/>

                <id>https://www.stitcher.io/blog/performance-101-building-the-better-web</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>Today we're looking into web performance. I'll share some useful links to articles and tutorials written by people with a lot of professional experience on the topic. I am writing from the perspective of a developer who brought pieces of this knowledge into practice. I've learned some lessons along the way, which you can learn from too.</p>
<p>If you want to reach out, to talk about performance, or with additions to this post, you can always reach me <a href="mailto:brendt@stitcher.io">via email</a>.</p>
<p>Without further ado, let's dive into the mystical subject of web performance. We'll start discussing the mindset you should have when building performant websites. Then we'll move on to a lot of practical examples, and links to other learning resources.</p>
<h3 id="performance-mindset"><a href="#performance-mindset" class="heading-anchor">#</a> Performance mindset</h3>
<p>If there's one thing you should take away from this post, it's the mindset every web developer should have. The industry builds tools, frameworks and systems to make the life of developers easier. All the while forgetting what web development actually is about. We're not making artisanal pieces of art anymore (maybe we never were?). We're generally aiming for fast development and quick results. We're forgetting about what matters in the end: the website and its visitors.</p>
<p>This post is meant for people with that mindset; people who want to become the best developer they can be. Always pushing yourself to the next level for a better end result. If you're a web developer who relates to this, understanding performance is one of the most important pillars to build upon.</p>
<p>That's it for the philosophical part of this post. Of course I'm completely ignoring the business side of the IT world. I'm not talking about money, time or scope here. I'm talking about improving your own development skills so that you could use that knowledge and experience in spare time projects or for real clients and work.</p>
<h3 id="web-basics:-html"><a href="#web-basics:-html" class="heading-anchor">#</a> Web basics: HTML</h3>
<p>One of the key components to understand and improve web performance is to know how the browser renders HTML. There's a lot more to it than you might think, and understanding these steps makes you reason completely differently about your own code. Google has the best crash course on the topic: <a target="_blank" href="https://developers.google.com/web/fundamentals/performance/">https://developers.google.com/web/fundamentals/performance/</a>, especially the "critical rendering path" section opened my eyes.</p>
<p>Another important concept to understand is static HTML pages. In the end, they are what's served to the user. There's no need to generate pages on the fly, while the user is waiting to see the result. Dynamic websites abuse the user's time for the sake of easy development. Now I'm not saying dynamic websites are bad. What I do say is that every dynamic system should have the technology in place to exclude the dynamic phase from the request/response cycle. More on that topic later. If you're into real static websites, <a target="_blank" href="https://www.staticgen.com/">https://staticgen.com</a> is a good place to find the right tool for your needs.</p>
<p>Moving on to responsive images: possibly the number one optimisation when it comes to bandwidth usage. The responsive images spec is designed to address the issue of large images, or render blocking JavaScript workarounds. It's completely backwards compatible (I'm talking to you Edge), and has a good chance of improving your website's loading time: <a target="_blank" href="https://responsiveimages.org/">https://responsiveimages.org</a>.</p>
<h3 id="backend-development"><a href="#backend-development" class="heading-anchor">#</a> Backend development</h3>
<p>I've already mentioned dynamic websites in the previous section. They are of course a must in the modern web; but you should think about which pages need to render things on the fly, and which could be cacheable. There are many layers of caching possible on the server side. We'll discuss eg. Varnish cache later in this post. Caching your backend code will highly depend on the kind of language and framework you're using. The most important thing to mention about caching is that you shouldn't view your cache as a layer "on top" of your application. It should be an integral part of all the code you write.</p>
<p>As a PHP developer, I'm used to the strict request/response lifecycle every PHP web application goes through. There are also a lot of other languages which provide the same logic for web applications. This approach is very easy to reason about, but it means the application has to be bootstrapped from scratch for every single request. Libraries like <a target="_blank" href="http://reactphp.org/">ReactPHP</a> or <a target="_blank" href="https://github.com/amphp/amp">AMP</a> address this issue by enabling the developer to handle multiple requests from a single bootstrapped application. Asynchronous and parallel applications add a lot of complexity at first, and might be very difficult to wrap your head around. But it might very well mean a huge decrease in response time.</p>
<h3 id="server-side"><a href="#server-side" class="heading-anchor">#</a> Server side</h3>
<p>Returning to the topic of caching, there's a lot that can be done server side. First of all there are caching headers which you should definitely implement: <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control">https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control</a>.</p>
<p>Second, you should serve content that's ready to be served. Use a CDN and Varnish in front of your real server. This way you're able to serve images, content pages, etc. immediately, having been already generated before. One of the dangers of using a so called "proxy" like Varnish is that many developers might see it as that "layer on top of your own application". In reality, you'll need to communicate a lot with Varnish from within your own application. You can read more about Varnish here: <a target="_blank" href="https://varnish-cache.org/">https://varnish-cache.org</a>.</p>
<p>The benefit of your own server? It's <strong>your server</strong>. You have control over the resources used and available. Don't put extra load on the client, when you could let your server take care of it. This is of course a very simplified way of thinking about resources. But it's always possible to upgrade your server's hardware, when you have no control over the hardware clients are using.</p>
<p>And lastely, if you haven't implemented HTTP/2 yet: implement HTTP/2! Not sure why? This might give you an idea: <a target="_blank" href="https://www.sitepoint.com/what-is-http2/">https://sitepoint.com/what-is-http2</a>.</p>
<h3 id="frontend-development"><a href="#frontend-development" class="heading-anchor">#</a> Frontend development</h3>
<p><strong>Disclaimer:</strong> I'm a backend web developer. I have written, and still write lots of CSS and JavaScript code, but I'm not in any way a professional when it comes to frontend web development. So I'll only use common sense and reasoning to share a few concepts of performance improvement.</p>
<p>You should think what resources a page really needs. If that particular page only needs 5 kilobytes out of 100 kilobytes of CSS, then don't load the other 95 kilobytes! The same goes for JavaScript.</p>
<p>Also think about inlining the important resources in your HTML pages, at least while HTTP/2 server push hasn't gone mainstream yet.</p>
<p>A good place to go from here would be Tim Kadlec's blog: <a target="_blank" href="https://timkadlec.com/">https://timkadlec.com</a>.</p>
<h3 id="in-summary"><a href="#in-summary" class="heading-anchor">#</a> In summary</h3>
<ul>
<li>Think performance-first.</li>
<li>Understand how HTML is loaded and rendered.</li>
<li>Serve content that's ready to be served.</li>
<li>Don't abuse the user's time by dynamically rendering on the fly when it's not needed.</li>
<li>Improve the request/response cycle server-side.</li>
<li>Put the load on your server, not the client.</li>
<li>Don't view caching as a layer on top, but rather as an integrated part of your application.</li>
<li>Set browser caching headers, use CDNs and take a look at Varnish.</li>
<li>Don't load all minified CSS or JS when you only need 10% of it on that page.</li>
</ul>
<p>Lot's of things to think about. This is my personal checklist I try to keep in mind when developing websites, both professionally and in my spare time. Like I said at the beginning of this post, you shouldn't always do everything just because. But you should understand these concepts, and know when it's appropriate to use them. By doing so, you're contributing to the better web.</p>
 ]]></summary>

                <updated>2017-05-30T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Array objects ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/array-objects-with-fixed-types"/>

                <id>https://www.stitcher.io/blog/array-objects-with-fixed-types</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <pre><span class="hl-keyword">abstract</span> <span class="hl-keyword">class</span> <span class="hl-type">Collection</span> <span class="hl-keyword">implements</span><span class="hl-type"> </span>\ArrayAccess, \Iterator
{
    <span class="hl-keyword">private</span> <span class="hl-property">$position</span>;

    <span class="hl-keyword">private</span> <span class="hl-property">$array</span> = [];

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>() {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span> = 0;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">current</span>() {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>];
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection">$offset</span>) {
        <span class="hl-keyword">return</span> <span class="hl-keyword">isset</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>]) <span class="hl-operator">?</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>] : <span class="hl-keyword">null</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetSet</span>(<span class="hl-injection">$offset, $value</span>) {
        <span class="hl-keyword">if</span> (<span class="hl-property">is_null</span>(<span class="hl-variable">$offset</span>)) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[] = <span class="hl-variable">$value</span>;
        } <span class="hl-keyword">else</span> {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>] = <span class="hl-variable">$value</span>;
        }
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetExists</span>(<span class="hl-injection">$offset</span>) {
        <span class="hl-keyword">return</span> <span class="hl-keyword">isset</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>]);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetUnset</span>(<span class="hl-injection">$offset</span>) {
        <span class="hl-keyword">unset</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>]);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">next</span>() {
        ++<span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">key</span>() {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">valid</span>() {
        <span class="hl-keyword">return</span> <span class="hl-keyword">isset</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>]);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">rewind</span>() {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span> = 0;
    }
}
</pre>
<p>A concrete implementation of the <code>Collection</code> class.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">TypeCollection</span> <span class="hl-keyword">extends</span> <span class="hl-type">Collection</span> 
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetSet</span>(<span class="hl-injection">$offset, $value</span>) {
        <span class="hl-keyword">if</span> (!<span class="hl-variable">$value</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Type</span>) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">\InvalidArgumentException</span>(&quot;<span class="hl-value">Value must be of type `Type`.</span>&quot;);
        }
    
        <span class="hl-keyword">parent</span>::<span class="hl-property">offsetSet</span>(<span class="hl-variable">$offset</span>, <span class="hl-variable">$value</span>);
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection">$offset</span>): <span class="hl-type">?Type</span> {
        <span class="hl-keyword">return</span> <span class="hl-keyword">parent</span>::<span class="hl-property">offsetGet</span>(<span class="hl-variable">$offset</span>);
    }
    
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">current</span>(): <span class="hl-type">Type</span> {
        <span class="hl-keyword">return</span> <span class="hl-keyword">parent</span>::<span class="hl-property">current</span>();
    }
}
</pre>
<p>Using the <code>TypeCollection</code> can be done like this.</p>
<pre><span class="hl-variable">$collection</span> = <span class="hl-keyword">new</span> <span class="hl-type">TypeCollection</span>();
<span class="hl-variable">$collection</span>[] = <span class="hl-keyword">new</span> <span class="hl-type">Type</span>();

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$collection</span> <span class="hl-keyword">as</span> <span class="hl-variable">$item</span>) {
    <span class="hl-property">var_dump</span>(<span class="hl-variable">$item</span>);
}
</pre>
 ]]></summary>

                <updated>2017-05-25T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Stitcher beta 1 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/stitcher-beta-1"/>

                <id>https://www.stitcher.io/blog/stitcher-beta-1</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>The first beta release of Stitcher has arrived. Together with a lot of bugfixes, the website has been given some more love.</p>
<h3 id="installation"><a href="#installation" class="heading-anchor">#</a> Installation</h3>
<p>The installation package, <code>pageon/stitcher</code>, now loads the beta version by default. If you're running an existing project, your should also require the beta version now:</p>
<pre>composer require pageon/stitcher-core @beta
</pre>
<h3 id="changelog"><a href="#changelog" class="heading-anchor">#</a> Changelog</h3>
<ul>
<li>Add empty array fallback in <code>FilterAdapter</code> to prevent undefined index error.</li>
<li>Improved plugin initialisation support. The temporary <code>init</code> function isn't required anymore, the constructor can now be used.</li>
<li>Make the adapter factory extensible.</li>
<li>Improve the CollectionAdapter by adding the <code>browse</code> variable. This variable can be used to browse the detail pages.
It has a <code>next</code> and <code>prev</code> key which contains the next and previous entry, if there are any.</li>
<li>Moved <code>Brendt\Stitcher\SiteParser</code> to <code>Brendt\Stitcher\Parser\Site\SiteParser</code> and refactored its service definition.</li>
<li>Added <code>Brendt\Stitcher\Parser\Site\PageParser</code> to parse a single page, which is no longer the responsibility of <code>SiteParser</code>.</li>
<li>Bugfix for general meta configuration overriding other meta values.</li>
</ul>
 ]]></summary>

                <updated>2017-05-20T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ PHP Generics and why we need them ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/php-generics-and-why-we-need-them"/>

                <id>https://www.stitcher.io/blog/php-generics-and-why-we-need-them</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In today's blog post we'll explore some common problems with arrays in PHP. All the problems and issues listed could be solved with a pending RFC which adds generics to PHP. We won't explore in too much detail what generics are, but at the end of this read, you should have a good idea as to why they are useful, and why we really want them in PHP. So without further ado, let's dive into the subject.</p>
<p><div class="ad-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7ICK3W&placement=stitcherio" id="_carbonads_js"></script>
</div></p>
<p>Imagine you have a collection of blog posts, loaded from a data source.</p>
<pre><span class="hl-variable">$posts</span> = <span class="hl-variable">$blogModel</span>-&gt;<span class="hl-property">find</span>();
</pre>
<p>Now you want to loop over every post, and do <em>something</em> with its data; let's say, the <code>id</code>.</p>
<pre><span class="hl-keyword">foreach</span> (<span class="hl-variable">$posts</span> <span class="hl-keyword">as</span> <span class="hl-variable">$post</span>) {
    <span class="hl-variable">$id</span> = <span class="hl-variable">$post</span>-&gt;<span class="hl-property">getId</span>();
    
    <span class="hl-comment">// Do something</span>
}
</pre>
<p>This is a scenario that happens often.
And it's this scenario we'll explore to discuss why generics are awesome,
and why the PHP community desperately needs them.</p>
<p>Let's take a look at the problems of the above approach.</p>
<h2 id="data-integrity"><a href="#data-integrity" class="heading-anchor">#</a> Data integrity</h2>
<p>In PHP, an array is a collection of… things.</p>
<pre><span class="hl-variable">$posts</span> = [
    '<span class="hl-value">foo</span>',
    <span class="hl-keyword">null</span>,
    <span class="hl-type">self</span>::<span class="hl-property">BAR</span>,
    <span class="hl-keyword">new</span> <span class="hl-type">Post</span>('<span class="hl-value">Lorem</span>'),
];
</pre>
<p>Looping over this array of posts would result in a fatal error.</p>
<pre>PHP Fatal error:  Uncaught Error: 
Call to a member function getId() on string
</pre>
<p>We're calling <code>-&gt;getId()</code> on the string <code>'foo'</code>. Not done. When looping over an array, we want to be sure that
every value is of a certain type. We could do something like this.</p>
<pre><span class="hl-keyword">foreach</span> (<span class="hl-variable">$posts</span> <span class="hl-keyword">as</span> <span class="hl-variable">$post</span>) {
    <span class="hl-keyword">if</span> (! <span class="hl-variable">$post</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Post</span>) {
        <span class="hl-keyword">continue</span>;
    }

    <span class="hl-variable">$id</span> = <span class="hl-variable">$post</span>-&gt;<span class="hl-property">getId</span>();
    
    <span class="hl-comment">// Do something</span>
}
</pre>
<p>This would work, but if you've written some production PHP code, you know these checks can grow quickly, and pollute
the codebase. In our example, we could verify the type of each entry in the <code>-&gt;find()</code> method on <code>$blogModel</code>.
However, that's just moving the problem from one place to another. It's a bit better though.</p>
<p>There's another problem with data integrity. Say you have a method which requires an array of <code>Post</code>s.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">handlePosts</span>(<span class="hl-injection"><span class="hl-type">array</span> $posts</span>) {
    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$posts</span> <span class="hl-keyword">as</span> <span class="hl-variable">$post</span>) {
        <span class="hl-comment">// ...</span>
    }
}
</pre>
<p>Again, we could add extra checks in this loop, but we could not guarantee that <code>$posts</code> only holds a collection of <code>Post</code> objects.</p>
<p><a target="_blank" href="http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list">As of PHP 7.0</a>, you could use the <code>...</code> operator to work around this issue.</p>
<pre><span class="hl-keyword">function</span> <span class="hl-property">handlePosts</span>(<span class="hl-injection">Post ...$posts</span>) {
    <span class="hl-keyword">foreach</span> (<span class="hl-variable">$posts</span> <span class="hl-keyword">as</span> <span class="hl-variable">$post</span>) {
        <span class="hl-comment">// ...</span>
    }
}
</pre>
<p>But the downside of this approach: you would have to call the function with an unpacked array.</p>
<pre><span class="hl-property">handlePosts</span>(...<span class="hl-variable">$posts</span>);
</pre>
<p><div class="author">
    Noticed a tpyo? You can <a href="https://github.com/brendt/stitcher.io" target="_blank" rel="noopener noreferrer">submit a PR</a> to fix it.

    If you want to stay up to date about what's happening on this blog, you can <strong>subscribe to my mailing list</strong>: send an email to
    <a href="mailto:brendt@stitcher.io">brendt@stitcher.io</a>, and I'll add you to the list.
</div>
</p>
<h2 id="performance"><a href="#performance" class="heading-anchor">#</a> Performance</h2>
<p>You can imagine it's better to know beforehand whether an array contains only elements of a certain type, rather than
manually checking the types within a loop, every, single, time.</p>
<p>We can't do benchmarks on generics, because they don't exist yet, so it's only guessing as to how they would impact performance.
It's not far-fetched to assume though, that PHP's optimised behaviour, written in C; is a better way to solve the problem than
to write lots of userland code.</p>
<h2 id="code-completion"><a href="#code-completion" class="heading-anchor">#</a> Code completion</h2>
<p>I don't know about you, but I use an IDE when writing PHP code. Code completion increases productivity immensely, so I'd also
like to use it here. When looping over posts, we want our IDE to know each <code>$post</code> is an instance of <code>Post</code>. Let's take
a look at the plain PHP implementation.</p>
<pre># BlogModel

<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">find</span>(): <span class="hl-type">array</span> {
    <span class="hl-comment">// return ...</span>
}
</pre>
<p>As of PHP 7.0, return types were added, and in PHP 7.1 they were refined with nullables and void. But there's no way
our IDE can know what's inside the array. So we're falling back to PHPDoc.</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@return</span> <span class="hl-type">Post[]</span>
 */</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">find</span>(): <span class="hl-type">array</span> {
    <span class="hl-comment">// return ...</span>
}
</pre>
<p>When using a "generic" implementation of e.g. a model class, type hinting the <code>-&gt;find()</code> method might not be possible.
So we're stuck with type hinting the <code>$posts</code> variable, in our code.</p>
<pre><span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">Post[]</span> <span class="hl-variable">$posts</span> */</span>
<span class="hl-variable">$posts</span> = <span class="hl-variable">$blogModel</span>-&gt;<span class="hl-property">find</span>();
</pre>
<p>Both the uncertainty of what's exactly in an array, the performance and maintenance impact because of scattered code,
and the inconvenience when writing those extra checks, makes me long for a better solution.</p>
<p>That solution, in my opinion is <a target="_blank" href="https://wiki.php.net/rfc/generics">generics</a>. I won't explain in detail what generics
do, you can read the RFC to know that. But I will give you an example of how generics could solve these issues, guaranteeing
the developer would always have the correct data in a collection.</p>
<p><strong>Big note</strong>: generics do not exist in PHP, yet. The RFC targeted PHP 7.1, and has no further information about the
future. The following code is based on the <a target="_blank" href="http://php.net/manual/en/class.iterator.php">the Iterator interface</a>
and <a target="_blank" href="http://php.net/manual/en/class.arrayaccess.php">the ArrayAccess interface</a>, which both exist as of PHP 5.0.
At the end, we'll dive into a generics example, which is dummy code.</p>
<p>First we'll create a <code>Collection</code> class which works in PHP 5.0+. This class implements <code>Iterator</code> to be able to
loop over its items, and <code>ArrayAccess</code> to be able to use array-like syntax to add and access items in the
collection.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">Collection</span> <span class="hl-keyword">implements</span><span class="hl-type"> Iterator, ArrayAccess
</span>{
    <span class="hl-keyword">private</span> <span class="hl-type">int</span> <span class="hl-property">$position</span>;

    <span class="hl-keyword">private</span> <span class="hl-type">array</span> <span class="hl-property">$array</span> = [];

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">__construct</span>() {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span> = 0;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">current</span>(): <span class="hl-type">mixed</span> {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>];
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">next</span>(): <span class="hl-type">void</span> {
        ++<span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">key</span>(): <span class="hl-type">int</span> {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">valid</span>(): <span class="hl-type">bool</span> {
        <span class="hl-keyword">return</span> <span class="hl-property">array_key_exists</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>, <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">rewind</span>(): <span class="hl-type">void</span> {
        <span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span> = 0;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetExists</span>(<span class="hl-injection">$offset</span>): <span class="hl-type">bool</span> {
        <span class="hl-keyword">return</span> <span class="hl-property">array_key_exists</span>(<span class="hl-variable">$offset</span>, <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection">$offset</span>): <span class="hl-type">mixed</span> {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>] ?? <span class="hl-keyword">null</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetSet</span>(<span class="hl-injection">$offset, $value</span>): <span class="hl-type">void</span> {
        <span class="hl-keyword">if</span> (<span class="hl-property">is_null</span>(<span class="hl-variable">$offset</span>)) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[] = <span class="hl-variable">$value</span>;
        } <span class="hl-keyword">else</span> {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>] = <span class="hl-variable">$value</span>;
        }
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetUnset</span>(<span class="hl-injection">$offset</span>): <span class="hl-type">void</span> {
        <span class="hl-keyword">unset</span>(<span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>]);
    }
}
</pre>
<p>Now we can use the class like this.</p>
<pre><span class="hl-variable">$collection</span> = <span class="hl-keyword">new</span> <span class="hl-type">Collection</span>();
<span class="hl-variable">$collection</span>[] = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(1);

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$collection</span> <span class="hl-keyword">as</span> <span class="hl-variable">$item</span>) {
    <span class="hl-keyword">echo</span> &quot;<span class="hl-value">{$item-&gt;getId()}\n</span>&quot;;
}
</pre>
<p>Note that with this simple implementation, there's no guarantee that <code>$collection</code> only holds <code>Post</code> object. For example, adding a string would work fine, but would break our loop.</p>
<pre><span class="hl-variable">$collection</span>[] = '<span class="hl-value">abc</span>';

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$collection</span> <span class="hl-keyword">as</span> <span class="hl-variable">$item</span>) {
    <span class="hl-comment">// This fails</span>
    <span class="hl-keyword">echo</span> &quot;<span class="hl-value">{$item-&gt;getId()}\n</span>&quot;;
}
</pre>
<p>With PHP as it is now, we could fix this problem by creating a <code>PostCollection</code> class.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">PostCollection</span> <span class="hl-keyword">extends</span> <span class="hl-type">Collection</span>
{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">current</span>() : <span class="hl-type">?Post</span> {
        <span class="hl-keyword">return</span> <span class="hl-keyword">parent</span>::<span class="hl-property">current</span>();
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection">$offset</span>) : <span class="hl-type">?Post</span> {
        <span class="hl-keyword">return</span> <span class="hl-keyword">parent</span>::<span class="hl-property">offsetGet</span>(<span class="hl-variable">$offset</span>);
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetSet</span>(<span class="hl-injection">$offset, $value</span>) {
        <span class="hl-keyword">if</span> (! <span class="hl-variable">$value</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">Post</span>) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">InvalidArgumentException</span>(&quot;<span class="hl-value">value must be instance of Post.</span>&quot;);
        }

        <span class="hl-keyword">parent</span>::<span class="hl-property">offsetSet</span>(<span class="hl-variable">$offset</span>, <span class="hl-variable">$value</span>);
    }
}
</pre>
<p>Now only <code>Post</code> objects can be added to our collection.</p>
<pre><span class="hl-variable">$collection</span> = <span class="hl-keyword">new</span> <span class="hl-type">PostCollection</span>();
<span class="hl-variable">$collection</span>[] = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(1);

<span class="hl-variable">$collection</span>[] = '<span class="hl-value">abc</span>';

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$collection</span> <span class="hl-keyword">as</span> <span class="hl-variable">$item</span>) {
    <span class="hl-keyword">echo</span> &quot;<span class="hl-value">{$item-&gt;getId()}\n</span>&quot;;
}
</pre>
<p>It works! Even without generics! There's only one issue, you might be able to guess it. This is not scalable. You need a
separate implementation for every type of collection, even though the only difference between those classes would be the type. Also note that IDEs and static analysers will be able to correctly determine the type, based on the return type of <code>offsetGet</code> in <code>PostCollection</code>.</p>
<p>You could probably make the subclasses even more convenient to create, by "abusing"
<a href="http://php.net/manual/en/language.oop5.late-static-bindings.php">late static binding</a> and PHP's reflection API. But
you'd still need to create a class, for every type available.</p>
<h2 id="glorious-generics"><a href="#glorious-generics" class="heading-anchor">#</a> Glorious generics</h2>
<p>With all that in mind, let's just take a look at the code we would be able to write if generics were implemented in PHP.
This would be <strong>one class</strong> which could be used for every type. For your convenience, I'll only be writing the changes
compared to the previous <code>Collection</code> class, so keep that in mind.</p>
<pre><span class="hl-keyword">class</span> <span class="hl-type">GenericCollection</span>&lt;<span class="hl-property">T</span>&gt; <span class="hl-keyword">implements</span><span class="hl-type"> Iterator, ArrayAccess
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">current</span>() : <span class="hl-type">?T</span> {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$this</span>-&gt;<span class="hl-property">position</span>];
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetGet</span>(<span class="hl-injection">$offset</span>) : <span class="hl-type">?T</span> {
        <span class="hl-keyword">return</span> <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>] ?? <span class="hl-keyword">null</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">offsetSet</span>(<span class="hl-injection">$offset, $value</span>) {
        <span class="hl-keyword">if</span> (! <span class="hl-variable">$value</span> <span class="hl-keyword">instanceof</span> <span class="hl-type">T</span>) {
            <span class="hl-keyword">throw</span> <span class="hl-keyword">new</span> <span class="hl-type">InvalidArgumentException</span>(&quot;<span class="hl-value">value must be instance of {T}.</span>&quot;);
        }

        <span class="hl-keyword">if</span> (<span class="hl-property">is_null</span>(<span class="hl-variable">$offset</span>)) {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[] = <span class="hl-variable">$value</span>;
        } <span class="hl-keyword">else</span> {
            <span class="hl-variable">$this</span>-&gt;<span class="hl-property">array</span>[<span class="hl-variable">$offset</span>] = <span class="hl-variable">$value</span>;
        }
    }

    <span class="hl-comment">// public function __construct() ...</span>
    <span class="hl-comment">// public function next() ...</span>
    <span class="hl-comment">// public function key() ...</span>
    <span class="hl-comment">// public function valid() ...</span>
    <span class="hl-comment">// public function rewind() ...</span>
    <span class="hl-comment">// public function offsetExists($offset) ...</span>
}
</pre>
<pre><span class="hl-variable">$collection</span> = <span class="hl-keyword">new</span> <span class="hl-type">GenericCollection</span>&lt;Post&gt;();
<span class="hl-variable">$collection</span>[] = <span class="hl-keyword">new</span> <span class="hl-type">Post</span>(1);

<span class="hl-comment">// This would throw the InvalidArgumentException.</span>
<span class="hl-variable">$collection</span>[] = '<span class="hl-value">abc</span>';

<span class="hl-keyword">foreach</span> (<span class="hl-variable">$collection</span> <span class="hl-keyword">as</span> <span class="hl-variable">$item</span>) {
    <span class="hl-keyword">echo</span> &quot;<span class="hl-value">{$item-&gt;getId()}\n</span>&quot;;
}
</pre>
<p>And that's it! We're using <code>T</code> as a dynamic type, which can be checked before runtime. And again, the <code>GenericCollection</code>
class would be usable for every type, always.</p>
<hr />
 ]]></summary>

                <updated>2017-05-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Stitcher alpha 5 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/stitcher-alpha-5"/>

                <id>https://www.stitcher.io/blog/stitcher-alpha-5</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>This is the last alpha version of Stitcher. The next release will be beta for the first time, and only bugfixes and improvements will be added from now on. Alpha 5 adds the last important pieces for Stitcher to be feature-complete before a stable 1.0 release. The most important things to note are the plugin support, improved command feedback and the internal use of the service container.</p>
<p>You can read about the upcoming plugin support in <a href="/blog/simplest-plugin-support">this blogpost</a>. Furthermore, I'm already working on the first plugin to support a REST API. Next step is a web interface to manage your content. For developers, Stitcher 1.0 will of course be completely useable without any plugins.</p>
<p>It's important to note that this update has <strong>a breaking change</strong> which existing Stitcher projects should take into account.</p>
<h3 id="installation"><a href="#installation" class="heading-anchor">#</a> Installation</h3>
<pre>composer <span class="hl-keyword">require</span> pageon/stitcher-core 1.0.0-alpha5
</pre>
<h3 id="update---breaking-changes"><a href="#update---breaking-changes" class="heading-anchor">#</a> Update - breaking changes</h3>
<p>A last big refactor has been done to support more extensions in the future. This means both the <code>Console</code> and the <code>DevController</code>
now live in a different namespace. You'll need an updated version of <code>stitcher</code> and <code>index.php</code>. This can be done with the
following commands.</p>
<pre>rm ./stitcher
rm ./dev/index.php
cp vendor/pageon/stitcher-core/install/stitcher ./stitcher
cp vendor/pageon/stitcher-core/install/dev/index.php ./dev/index.php

# Remove the cache dir, this might be another directory depending on your configuration.
rm -r .cache/
</pre>
<h3 id="changelog"><a href="#changelog" class="heading-anchor">#</a> Changelog</h3>
<ul>
<li>Add plugin support!</li>
<li>Add PHP 7.0 support.</li>
<li>Add Command tests for Router commands and Generate command.</li>
<li>Improved meta support.</li>
<li>Improved generate command feedback.</li>
<li>Refactor the use of the dependency container, enabling future extensions. (See breaking changes).</li>
<li>Use stable version of <code>pageon/html-meta</code>.</li>
<li>Fix folder parser bug with nested folders.</li>
<li>Fix with Sass compiler import paths. The Sass compiler can now also look directly in <code>src/css</code>. This is useful when doing includes and IDE auto-completion.</li>
<li>Fix global meta tags not being loaded.</li>
<li>Fix for meta tags on detail pages not correctly set.</li>
</ul>
 ]]></summary>

                <updated>2017-05-01T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ The simplest plugin support ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/simplest-plugin-support"/>

                <id>https://www.stitcher.io/blog/simplest-plugin-support</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p><em>Stitcher's plugin support is available as of <a href="/blog/stitcher-alpha-5">stitcher 1.0.0-alpha5</a>.</em></p>
<p>In this post, you'll read about Stitcher's plugin system. It might get a bit technical, but is definitely worth the read.</p>
<p>Stitcher plugins are built on top of two powerful components which already exist in many modern projects.</p>
<ul>
<li>Composer's auto loading</li>
<li>Symfony's service container</li>
</ul>
<p>Using these two components, a plugin is no more than a composer package, telling Stitcher it should add its own classes and parameters to the existing services. It's a wonderfully simple concept, and it works like a charm. Like almost everything in Stitcher: the simpler, the better. Let's take a look at an example.</p>
<h3 id="myplugin"><a href="#myplugin" class="heading-anchor">#</a> MyPlugin</h3>
<p>This is what a plugin's folder structure could look like.</p>
<pre>MyPlugin/
	├── src/
	│   ├── My/
	│   │    ├── MyPlugin.php
	│   │    └── Service.php
	├── config.yml
	├── services.yml
	├── composer.json
	└── README.md
</pre>
<p>The only requirement for a package to be "a plugin" is a class implementing the <code>Brendt\Stitcher\Plugin\Plugin</code> interface. In this example, that would be <code>My\MyPlugin</code>. When this class can be autoloaded with composer, your plugin is ready!</p>
<h3 id="plugin-interface"><a href="#plugin-interface" class="heading-anchor">#</a> Plugin interface</h3>
<p>The <code>Plugin</code> interface requires you to only implement three methods. These methods tell Stitcher where the <code>services.yml</code> and <code>config.yml</code> files are located and how to initialise the plugin. Any other binding with Stitcher is done via the service container.</p>
<pre><span class="hl-keyword">namespace</span> <span class="hl-type">My</span>;

<span class="hl-keyword">use</span> <span class="hl-type">Brendt\Stitcher\Plugin\Plugin</span>;

<span class="hl-keyword">class</span> <span class="hl-type">MyPlugin</span> <span class="hl-keyword">implements</span><span class="hl-type"> Plugin
</span>{
    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">init</span>() {
        <span class="hl-keyword">return</span>;
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getConfigPath</span>() {
        <span class="hl-keyword">return</span> <span class="hl-property">__DIR__</span> . '<span class="hl-value">/plugin.config.yml</span>';
    }

    <span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">getServicesPath</span>() {
        <span class="hl-keyword">return</span> <span class="hl-property">__DIR__</span> . '<span class="hl-value">/plugin.services.yml</span>';
    }
}
</pre>
<h3 id="init-method"><a href="#init-method" class="heading-anchor">#</a> <code>init</code> method</h3>
<p>The <code>init</code> method is called after all plugin config is loaded. This method can be used as a hook to add plugin configuration to existing services. An example would be adding a command to the console application.</p>
<pre><span class="hl-comment">/**
 * <span class="hl-value">@return</span> <span class="hl-type">void</span>
 */</span>
<span class="hl-keyword">public</span> <span class="hl-keyword">function</span> <span class="hl-property">init</span>() {
    <span class="hl-comment">/** <span class="hl-value">@var</span> <span class="hl-type">Console</span> <span class="hl-variable">$console</span> */</span>
    <span class="hl-variable">$console</span> = <span class="hl-type">App</span>::<span class="hl-property">get</span>('<span class="hl-value">app.console</span>');

    <span class="hl-variable">$console</span>-&gt;<span class="hl-property">add</span>(<span class="hl-type">App</span>::<span class="hl-property">get</span>('<span class="hl-value">my.plugin.command.my.cmd</span>'));
}
</pre>
<h3 id="plugin.config.yml"><a href="#plugin.config.yml" class="heading-anchor">#</a> plugin.config.yml</h3>
<p>The name doesn't matter as long as its a yaml file. This file works exactly the same as other config files: key-value pairs can be added and will be available as parameters in the service container. Keys can be nested, but will be flattened when loaded. One thing to note is that plugins cannot override existing parameters.</p>
<p>Your plugin parameters can of course be overridden from within a Stitcher project.</p>
<pre><span class="hl-comment"># ./vendor/MyPlugin/plugin.services.yml</span>

my.<span class="hl-keyword">plugin</span>:
    <span class="hl-keyword">parameter</span><span class="hl-property">:</span> test
</pre>
<h3 id="plugin.services.yml"><a href="#plugin.services.yml" class="heading-anchor">#</a> plugin.services.yml</h3>
<p>Again, the name doesn't matter, but the root element must be named <code>services</code> as per Symfony's requirements. You could also add <code>parameters</code> here.</p>
<pre><span class="hl-comment"># ./vendor/MyPlugin/plugin.services.yml</span>

<span class="hl-keyword">services</span><span class="hl-property">:</span>
    my.plugin.my.<span class="hl-keyword">service</span>:
        <span class="hl-keyword">class</span><span class="hl-property">:</span> My\Service
        <span class="hl-keyword">arguments</span><span class="hl-property">:</span> <span class="hl-property">[</span>'<span class="hl-value">%my.plugin.parameter%</span>', '<span class="hl-value">%directories.src%</span>', '<span class="hl-value">@stitcher</span>'<span class="hl-property">]</span>
</pre>
<p>As you can see, Stitcher services and parameters are available, as well as your own.</p>
<h3 id="loading-a-plugin"><a href="#loading-a-plugin" class="heading-anchor">#</a> Loading a plugin</h3>
<p>Finally, a plugin must be loaded into your project for it to be active. The <code>plugins</code> parameter in your project's config file is used for doing that.</p>
<pre><span class="hl-comment"># ./config.yml</span>

<span class="hl-keyword">plugins</span><span class="hl-property">:</span>
    <span class="hl-property">-</span> My\MyPlugin
</pre>
<p>That's it!</p>
<h2 id="future-possibilities"><a href="#future-possibilities" class="heading-anchor">#</a> Future possibilities</h2>
<p>This plugin system is so simple, yet it opens the possibility to add all kinds of functionality to a Stitcher project. It's an important step towards some of my own ideas; custom themes and other applications (API and CMS); and we'll discover more of its true strength in the future.</p>
<p>The most important thing for me is its simplicity. When looking at plugin systems in other applications, you'll often find complex setups like a virtual directory structure, a custom plugin loader, dirty file naming conventions, own package managers, etc. I wanted to use existing and proven technologies to build on top on, and keep the system as clean as possible. I believe this approach is a step towards the right direction.</p>
 ]]></summary>

                <updated>2017-04-27T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Stitcher alpha 4 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/stitcher-alpha-4"/>

                <id>https://www.stitcher.io/blog/stitcher-alpha-4</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>A new alpha release has arrived for Stitcher!</p>
<p>This release brings a lot of optimizations and bugfixes to many parts of Stitcher. The biggest changes are found in <code>brendt/responsive-images</code>, in which a lot of bugfixes and extra options are added. Furthermore, there's one change reverted, namely the asynchronous support for image rendering. This functionality relied on several <code>amphp</code> development packages, and broke with almost every update. Async support might be re-added in the future, but for now it's disabled.</p>
<p>One of the biggest new features is the support for custom htaccess headers and with that, HTTP2 server push! This feature has been added and is tested, but not yet used in any real projects. So there's more testing to do before declaring it "stable". You can use it in almost any template function by added the <code>push=true</code> parameter.</p>
<p>Stitcher also uses <code>papgeon/html-meta</code> now, and will build on top of this library more and more in the future.</p>
<p>One final new feature is the addition of the <code>cdn</code> config parameter. This parameter takes an array of files, located in the source directory, and will copy them on-the-fly or during compile-time to the public directory. This way you can expose folders or files directly, without parsing them through Stitcher.</p>
<h3 id="installation"><a href="#installation" class="heading-anchor">#</a> Installation</h3>
<p>The installation package, <code>pageon/stitcher</code>, still comes with <code>1.0.0-alpha3</code> by default. Feel free to manually update the composer requirement to <code>1.0.0-alpha4</code>. The default version will change as soon as HTTP/2 server push is fully tested.</p>
<p>Some people might need to run <code>composer dump-autoload -o</code> one more time when updating to alpha4.</p>
<h3 id="future-updates"><a href="#future-updates" class="heading-anchor">#</a> Future updates</h3>
<p>Before this update, Stitcher was always re-tagged on the fly when new things were added. From now on, tags will only be added after a certain feature set is complete. By doing so, updating Stitcher won't break things as much as it used to do. Keep in mind Stitcher is still in alpha phase, so breaking changes will happen now and then. There's still a small feature set to be added before a first beta release will be available. Slowly but surely, we're getting there.</p>
 ]]></summary>

                <updated>2017-04-21T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Static site generators vs. caching ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/static_sites_vs_caching"/>

                <id>https://www.stitcher.io/blog/static_sites_vs_caching</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>What's the difference between static site generators and caching you ask?</p>
<p>A short answer might be: there is no technical benefit between both. But the mindset behind the two is completely different.</p>
<p>I think the topic is too interesting to leave it like that. Let's talk about caching.</p>
<p>For many years now, we've been creating systems which help us build websites. Many of those systems are built around the idea of "dynamic websites". Instead of writing HTML and CSS pages; we've designed systems which can load information from a data source (say for example, a MySQL database); parse that data into so called "templates" (these are like blueprints for HTML pages); and finally send the rendered HTML to the client. Of course, there is more than just HTML and CSS to a website, but that's a topic for another day.</p>
<p>Now imagine you've got many visitors on your website, each of them visiting the same page. Rendering that page for every visit would require more server resources than to render the page once, and send that output to everyone asking it. That's a cached page. You could also cache other parts of the application. For example: not always perform the same database query, but rather cache the result of that query and reuse that over and over again.</p>
<p>Evidently, caching is way more than what I just described. My try at a general definition for caching on the web would be something like this.</p>
<blockquote>
<p>Once a resource intensive operation is done, remember the outcome. The next time the same operation is requested, you can just give the result instead of doing that operation again.</p>
</blockquote>
<p>Caching is a very powerful tool which <strong>wraps around</strong> your system, enabling it to be much more performant.</p>
<p>Stitcher, and all static site generators, are the opposite. These tools don't <em>wrap around</em> a system. Rather, their core <strong>is</strong> the HTML output. All other things needed by developers to smoothly build websites, are <strong>plugged in</strong> into that core. What's the downside? You'll have to re-render parts of your website before they are visible to the visitor. A tedious task. Luckily computers are good at performing the same tedious tasks over and over again. Re-rendering your website isn't really a bother when you have the right tools available.</p>
<p>Another "downside" of static websites? It requires a bit more thought of the developer. But when could that a bad thing?</p>
<p>So static websites do have their downsides. But take a look at the things you're able to "plug in" that HTML rendering core:</p>
<ul>
<li>
<a href="/blog/tackling_responsive_images-part_1">Image optimisation</a>: enabling the developer to use the responsive images specification to its full extent, without any work.</li>
<li>SASS precompiling: I'm not a frontend developer, but these guys tell me that's a must.</li>
<li>Pagination, overviews and detail pages.</li>
<li>Parse MarkDown, YAML and JSON into templates and use those templates like in any dynamic system.</li>
<li>JavaScript and CSS minifying: very important for website performance.</li>
<li>Things like ordering and filtering data sets.</li>
</ul>
<p>Some important things are still missing in Stitcher though.</p>
<ul>
<li>Form support: although Stitcher will not include form handling at its core. That will be a separate module.</li>
<li>Frontend filtering of data sets: technically this is possible, but it might have huge performance costs depending on the amount of filters. I will be working on it in the future though.</li>
<li>Content management: this is also possible, but not from within Stitcher's core. It would be a separate module acting as a client to modify a Stitcher project.</li>
</ul>
<p>To be clear: I don't think static site generators are the best solution for all websites. But there are lots of cases which could benesfit from using a static site generator over of a dynamic system and caching. I view many caching systems as like putting a bandaid on top of a wound, but not <em>stitching</em> the wound (pun intended). Don't forget that clearing caches is one of the most difficult parts of software development. But we should also be realistic: the static website approach mainly targets small to medium websites, not complex web applications.</p>
<p>So if you want to give it a go, be sure to check out a static site generator, there are many!</p>
<ul>
<li>
<a target="_blank" href="https://jekyllrb.com/">Jekyll</a>
</li>
<li>
<a target="_blank" href="http://gohugo.io/">Hugo</a>
</li>
<li>
<a target="_blank" href="https://github.com/pageon/stitcher-core">Stitcher</a>
</li>
<li>
<a target="_blank" href="https://sculpin.io/">Sculpin</a>
</li>
</ul>
 ]]></summary>

                <updated>2017-03-02T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Image optimizers ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/image_optimizers"/>

                <id>https://www.stitcher.io/blog/image_optimizers</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>I've been working lately on image optimisation in Stitcher. As a try-out, I've added <a href="https://github.com/psliwa/image-optimizer">this library</a> to the responsive images module.</p>
<p>Enabling the optimizer is done by updating Stitcher (1.0.0-alpha2), and adding the following parameter in <code>config.yml</code>.</p>
<pre><span class="hl-keyword">engines</span><span class="hl-property">:</span>
    <span class="hl-keyword">optimizer</span><span class="hl-property">:</span> true
</pre>
 ]]></summary>

                <updated>2017-02-26T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Tackling responsive images - part 2 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/tackling_responsive_images-part_2"/>

                <id>https://www.stitcher.io/blog/tackling_responsive_images-part_2</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>In my <a href="/blog/tackling_responsive_images-part_1">previous post</a>, I wrote about the idea behind integrating responsive images and Stitcher. A pretty robust library came to be. You could throw it any image, and it would generate a set of variations of that images, scaled down for multiple devices. It returned an object, which Stitcher parsed into a template variable. In templates, the following is now possible.</p>
<pre>&lt;<span class="hl-keyword">img</span> <span class="hl-property">src</span>=&quot;{$image.src}&quot; <span class="hl-property">srcset</span>=&quot;{$image.srcset}&quot; <span class="hl-property">sizes</span>=&quot;{$image.sizes}&quot; /&gt;
</pre>
<p>If you would like to read the source code instead of this post, <a href="https://github.com/brendt/responsive-images">here you go</a>.</p>
<p>Like I wrote earlier, the first version of the scaling down algorithm was based on the width of images. It worked, but it wasn't solving the actual problem: optimizing bandwidth usage. The real solution was in downscaling images based on their filesizes. The problem there: how could you know the dimensions of an image, when you know the desired filesize. This is where high school maths came into play. I was actually surprised how much fun I had figuring out this "formula". I haven't been in school for a few years, and I was rather happy I could use some basic maths skills again!</p>
<p>This is what I did:</p>
<pre>filesize = 1.000.000
width = 1920
ratio = 9 / 16
height = ratio * width

area = width * height
 &lt;=&gt; area = width * width * ratio

pixelprice = filesize / area
 &lt;=&gt; filesize = pixelprice * area
 &lt;=&gt; filesize = pixelprice * (width * width * ratio)
 &lt;=&gt; width * width * ratio = filesize / pixelprice
 &lt;=&gt; width ^ 2 = (filesize / pixelprice) / ratio
 &lt;=&gt; width = sqrt((filesize / pixelprice) / ratio)
</pre>
<p>So given a constant <code>pixelprice</code>, I can calculate the required width an image needs to have a specified filesize. Here's the thing though: <code>pixelprice</code> is an approximation of what one pixel in this image costs. That's because not all pixels are worth the same amount of bytes. It heavily depends on which image codecs are used. It is however the best I could do for now, and whilst I might add some more logic in the future, I'd like to try this algorithm out for a while.</p>
<p>So now the Responsive Factory scales down images by filesize instead of width. A much better metric when you're trying to reduce bandwidth usage. This is how the library is used in Stitcher:</p>
<pre><span class="hl-keyword">use</span> <span class="hl-type">Brendt\Image\Config\DefaultConfigurator</span>;
<span class="hl-keyword">use</span> <span class="hl-type">Brendt\Image\ResponsiveFactory</span>;

<span class="hl-variable">$config</span> = <span class="hl-keyword">new</span> <span class="hl-type">DefaultConfigurator</span>([
    '<span class="hl-value">driver</span>'      =&gt; <span class="hl-type">Config</span>::<span class="hl-property">get</span>('<span class="hl-value">engines.image</span>'),
    '<span class="hl-value">publicPath</span>'  =&gt; <span class="hl-type">Config</span>::<span class="hl-property">get</span>('<span class="hl-value">directories.public</span>'),
    '<span class="hl-value">sourcePath</span>'  =&gt; <span class="hl-type">Config</span>::<span class="hl-property">get</span>('<span class="hl-value">directories.src</span>'),
    '<span class="hl-value">enableCache</span>' =&gt; <span class="hl-type">Config</span>::<span class="hl-property">get</span>('<span class="hl-value">caches.image</span>'),
]);

<span class="hl-variable">$responsiveFactory</span> = <span class="hl-keyword">new</span> <span class="hl-type">ResponsiveFactory</span>(<span class="hl-variable">$config</span>);
</pre>
<p>All images in Stitcher go through this factory, the factory will generate x-amount of variations of the image, and the browser decides which one it will download. Its pretty cool, and I hope it will help websites to serve more optimized images, while a developer can still focus on the most important parts of his project.</p>
 ]]></summary>

                <updated>2017-02-18T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Tackling responsive images - part 1 ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/tackling_responsive_images-part_1"/>

                <id>https://www.stitcher.io/blog/tackling_responsive_images-part_1</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>One of the main goals when I started with Stitcher was heavily optimized images. Looking at the <a href="http://httparchive.org/trends.php">HTTP Archive</a> stats, it's clear we're doing something wrong. Luckily, the <a href="http://responsiveimages.org/">Responsive images spec</a> has been made by a lot of smart people to counter the image problem. My goal was to implement this spec in Stitcher in a way that was easy enough for developers to use it to its full extent. We're not completely there yet, but we're close. In this blogpost I want to talk about the challenges I faced creating this library. And if you're more into code then into reading a blog post, <a href="https://github.com/brendt/responsive-images">here you go</a>.</p>
<p>To be clear: the goal of the responsive images spec is to reduce bandwidth used when downloading images. Images nowadays require so much bandwidth. When you think about it, it's insane to load an image which is 2000 pixels wide, when the image on screen is only 500 pixels wide. That's the issue the spec addresses, and that's the issue I wanted to solve in Stitcher.</p>
<p>So I want one image to go in, x-amount of the same image with varying sizes coming out, and let the browser decide which image is the best to load. How could I downscale that source image? That was the most important question I wanted answered. All other problems like accessebility in templates and how to expose the generated image files, were concerns of Stitcher itself.</p>
<p>My first take on downscaling images was the following:</p>
<p>Take the source image and a set of configuration parameters. These parameters would decide the maximum amount of image variations and the minimum width of the image. Eg. I want a maximum of ten images, with the smallest image being 300 pixels wide. Now the algorithm would loop a maximum of 10 times, always creating an image which is 10% smaller in width than the previous one.</p>
<p>You might already see this is not the optimal approach. After all: we're trying to reduce bandwidth used when loading images. There is no guarantee an image which is downscaled 10%, is also reduced in size. Much depends on which image codecs are used, and what's in the image itself. But by using this approach early on, I was able to implement this "image factory" with Stitcher. Next I would be working on optimizing the algorithm, but for the time being I could tackle the Stitcher integration.</p>
<h2 id="linking-with-stitcher"><a href="#linking-with-stitcher" class="heading-anchor">#</a> Linking with Stitcher</h2>
<p>Letting Stitcher know about responsive images was both easy and difficult at the same time. The basic framework was already there. So I could easily create an image provider which used the responsive factory, and returned an array representation of the image. The template syntax looks like this:</p>
<pre>&lt;<span class="hl-keyword">img</span> <span class="hl-property">src</span>=&quot;{$image.src}&quot; <span class="hl-property">srcset</span>=&quot;{$image.srcset}&quot; <span class="hl-property">sizes</span>=&quot;{$image.sizes}&quot; /&gt;
</pre>
<p>Unfortunately, there is no way to automate the sizes part, unless you start crawling all CSS and basically implement a browser engine in PHP. My solution for this part is pre-defined sets of sizes. That's still a work in progress though, I'm not sure yet how to make it easy enough to use. For now, I'm just manually specifying sizes when writing template code.</p>
<p>But the tricky part wasn't the sizes, neither the srcset. It was handling paths and URLs. I've noticed this throughout the whole Stitcher framework: creating the right paths and URLs (correct amount of slashes, correct root directory etc.) is actually quite the pain to manage. I'm convinced by now I need some kind of helper which always renders the correct paths and URLs. It's on my todo list.</p>
<p>That's it for this blogpost, next up I'll be writing about optimizing the image algorithm.</p>
 ]]></summary>

                <updated>2017-02-17T00:00:00+00:00</updated>
            </entry>
                                <entry>
                <title><![CDATA[ Which editor to choose? ]]></title>

                <link rel="alternate" href="https://stitcher.io/blog/which-editor-to-choose"/>

                <id>https://www.stitcher.io/blog/which-editor-to-choose</id>

                <author>
                    <name><![CDATA[ Brent Roose ]]></name>
                </author>

                <summary type="html"><![CDATA[ <p>So many editors to choose from! Which one is the best for you?
I can already tell you that you won’t find the answer here. But maybe I can list some pros and cons.
We’ll be looking at Sublime Text, Github’s Atom, Adobe’s Brackets and Microsoft’s Visual Studio Code.
All of these editors are based on the same core concepts, some of which Sublime made extremely popular.
But there are some big and subtle differences.</p>
<h2 id="out-of-the-box-features"><a href="#out-of-the-box-features" class="heading-anchor">#</a> Out of the box features</h2>
<p>All four editors are multi platform, have the command palette and fuzzy finder we’ve grown accustomed to.
It’s important to keep in mind that Sublime and Atom are primarily focussed on packages to provide functionality,
while Brackets and Visual Studio Code provide a more all-in-one solution from the start.
More about packages later, here are the most important differences out of the box.</p>
<p><strong>Visual Studio Code</strong> comes with built-in GIT support, a task runner and a linter.
You can start to code without having to set up anything.
It’s focussed on Node and ASP.NET development, which is reflected in the tools provided.
But you can use it for any other language.</p>
<p><strong>Sublime Text</strong> provides a lot of themes from the start,
has a built in project manager and offers many customisable keybindings and commands to do text manipulation.
There are however a lot of packages you’ll want to download immediately.</p>
<p><strong>Atom</strong> has a package manager shipped by default.
Atom’s file tree sidebar has some very nice features such as GIT support and file manipulation (see below).
There’s also a live MarkDown editor which is really neat.
But like Sublime, you’ll want to install extra packages from the start.</p>
<p><strong>Brackets</strong> has an awesome live preview feature which just blew my mind.
Brackets is focussed on front-end web development and provides very good tools to do so.
It also comes with a linter, debugger, inline editor and Photoshop integration.
There’s an extension manager available too. (That’s the Adobe version of packages, more about those later).</p>
<p>I felt Visual Studio Code and Brackets were really just plug-and-play from the start.
Both Sublime and Atom require a lot of tweaking to set everything up for the best coding experience.
This isn’t a bad thing, but in this category, Visual Studio Code and Brackets are the best.</p>
<hr />
<p>
    <img src="/resources/img/static/editors/1.png" class="editor-badge"/>
</p>
<hr />
<h2 id="packages"><a href="#packages" class="heading-anchor">#</a> Packages</h2>
<p>Packages (or extensions, thanks Adobe), give you access to a lot of extra features.</p>
<p><strong>Brackets</strong> has an extension manager which is rather slow and bulky and has an “Adobe feel” to it.
You can easily install packages from a local source, URL or an online repository.
The extension manager lacks however good package documentation.</p>
<p>In <strong>Sublime</strong>, you’ll need Package Control if you want to easily install other packages.
There’s a very wide variety of packages available there.
Chances are that you’ll be able to do that one thing you like with an existing package.
Browsing packages is a bit of a pain from the command palette though.
There are many small undocumented packages which makes it often a guess as to what a package really does.
The online documentation isn’t user friendly either. It’s mostly a huge pile of text per package.</p>
<p><strong>Atom</strong> shines when it comes to packages. It has a built-in package manager which works directly with GitHub.
Not only are there a lot of packages available, there’s also a very high standard on documentation.
You’ll be able to see screenshots, keybinding references and even animated GIFs explaining how a package works and what it does.
All from within Atom. It’s super easy to update packages and Atom will tell you when a package is outdated or uses deprecated code.
It shouldn’t surprise you that Atom itself is actually a collection of these same packages.</p>
<p><strong>Visual Studio Code</strong> as of VSC V0.10.1 there’s extension support, which looks a lot like Sublime’s Package Control.
Because of the recent popularity of Visual Studio Code, there's a big plugin system rising.</p>
<p>Atom is a winner when it comes to packages.
The whole system is built upon the package manager, and there’s a big community behind it.
That should be no surprise, knowing that GitHub is creating this editor.</p>
<hr />
<p>
    <img src="/resources/img/static/editors/2.png" class="editor-badge"/>
</p>
<hr />
<h2 id="file-tree"><a href="#file-tree" class="heading-anchor">#</a> File tree</h2>
<p>You might find it odd I list the file tree as a category.
From experience though, I feel the tree is one of the most important features which can really work with or work against you.
You might not use the file tree at all, but a lot of people do.
So I felt it was right to talk about it here.</p>
<p><strong>Sublime Text</strong> is fast and this is also reflected in the tree.
It lacks however some important functionality related to file manipulation from the tree.</p>
<p><strong>Brackets</strong> has a very bulky and slow tree. Opening folders and files takes a notable time.
It also offers only the bare minimal tools like Sublime:
new files and folders, renaming, deleting and revealing/searching files.</p>
<p><strong>Visual Studio Code</strong> doesn’t have a lot more tools than Brackets or Sublime,
but it allows you to move files inside the tree, which is a big help.
There are some minor points though. Visual Studio Code doesn’t show tabs, but uses the tree pane to show open files.
It makes this pane become cluttered and makes it difficult to find the open file you’re looking for.
It’s also not possible to scroll sideways.
But you can use the same pane as a search and debugger view, which is space efficient.</p>
<p><strong>Atom</strong> has a lot of tree functionality: there are simple tools like copy/paste,
but also cut, duplicate, rename etc.
You can also move files by dragging them.
Atom furthermore integrates GIT project status in the file tree.
The tree might feel a bit slower than Sublime or Visual Studio Code though.</p>
<p>Both Atom and Sublime have great file tree features, and both lack some.
Sublime can’t be beaten by speed, but Atom offers a lot more functionality.
Many people don’t use the tree view in Sublime,
but together with Atom’s GIT status you’ll get a good project overview by just looking at the tree.</p>
<hr />
<p>
    <img src="/resources/img/static/editors/3.png" class="editor-badge"/>
</p>
<hr />
<h2 id="performance"><a href="#performance" class="heading-anchor">#</a> Performance</h2>
<p>Performance is one of the most important metrics.
All of these editors are performant for sure, but each has its own small differences.</p>
<p><strong>Atom</strong> lacks in this category.
There are two major issues: startup time and big files.
Atom is built upon web technologies (HTML, CSS and JavaScript).
It has some major advantages, but takes a while longer to load.
It’s however only the startup, and still considerably faster than any IDE.
Once everything is loaded, Atom is as fast as Brackets. On the other side, big file loading time is a disaster.
Atom will open files once you’ve selected them in the tree view.
It’s easy to miss click a minified file, which will make Atom hang for several seconds or even minutes.</p>
<p><strong>Visual Studio Code</strong> is a bit faster than Atom and Brackets,
it works as you might expect from a Microsoft product: not slow, but also not the fastest.</p>
<p><strong>Brackets</strong> is comparable to Atom, but the slow and bulky tree view makes everything feel slower.</p>
<p><strong>Sublime</strong> is by far the winner here.
It’s lightning fast all the time, and can’t be beaten by any other editor.
Atom and Brackets loose this competition, but are still a lot faster than full blown IDEs.
Another aspect to keep in mind is the amount of packages you’re using.
Atom actually tells you how much milliseconds each package adds to startup time.
Sublime is also subject to this: the more packages the slower.
But without any doubt: Sublime shines in the field of performance.</p>
<hr />
<p>
    <img src="/resources/img/static/editors/4.png" class="editor-badge"/>
</p>
<hr />
<h2 id="configuration"><a href="#configuration" class="heading-anchor">#</a> Configuration</h2>
<p><strong>Sublime</strong>, <strong>Brackets</strong> and <strong>Visual Studio Code</strong> offer an easy JSON config file for settings and keybindings.
Brackets and Visual Studio Code even open a two column layout when editing settings, one with the defaults and one with your own.
A small but convenient feature.</p>
<p><strong>Atom</strong> however excels at customisability with its own stylesheet and startup script which can be hacked in any way you want.
It has a built-in keybinding debugger, the Chrome developer tools, works with CoffeeScript (JS) and CSS.
You don’t need to learn another language to customise Atom, it’s built upon web technologies.
Furthermore, each package has its own configuration page with a lot of documentation and sometimes input fields to set parameters.</p>
<hr />
<p>
    <img src="/resources/img/static/editors/5.png" class="editor-badge"/>
</p>
<hr />
<p>That was a lot of information! Some of the most important things summarized:</p>
<p><strong>Visual Studio Code</strong> is focused on Node and ASP.NET development.
It isn’t very customisable but has the Microsoft IDE feel to it.
It’s an easy plug and play setup.
Files are not shown in tabs, which makes it feel a bit unorganised,
but I think that this is a preference and a developer can get used to this method of work.</p>
<p><strong>Sublime Text</strong> has a lot of power. It’s fast and reliable.
There are a lot of packages to customise your development environment,
but they are often not very well documented. Sublime starts out as a text editor,
but can be made the perfect, performant IDE with time and effort.</p>
<p><strong>Brackets</strong> has some awesome front-end web development features like live previews, linters and PSD integration.
The main downside is that it feels a bit slow, especially the file tree.</p>
<p><strong>Atom</strong> is built on web technologies and its packages.
It’s offers a very nice interface for packages and configuration and is “hackable to the core”.
It has some quirks still with performance, but there’s a very active community working on it.
Its customisability makes Atom accessible for a wide variety of programmers with their own workflow.</p>
 ]]></summary>

                <updated>2015-08-24T00:00:00+00:00</updated>
            </entry>
            </feed>
