<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thomas Emad</title>
    <description>The latest articles on DEV Community by Thomas Emad (@thomas_emad).</description>
    <link>https://dev.to/thomas_emad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3784175%2F5825e38f-a56f-4fd0-b9ae-9b469e73b58b.png</url>
      <title>DEV Community: Thomas Emad</title>
      <link>https://dev.to/thomas_emad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thomas_emad"/>
    <language>en</language>
    <item>
      <title>How AST Powers Modern Frameworks — And a Wild Idea for Blade</title>
      <dc:creator>Thomas Emad</dc:creator>
      <pubDate>Fri, 20 Mar 2026 16:50:25 +0000</pubDate>
      <link>https://dev.to/thomas_emad/how-ast-powers-modern-frameworks-and-a-wild-idea-for-blade-1ka3</link>
      <guid>https://dev.to/thomas_emad/how-ast-powers-modern-frameworks-and-a-wild-idea-for-blade-1ka3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu42qfx3pl1ecdga07431.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu42qfx3pl1ecdga07431.png" alt="Banner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We talked last time about &lt;strong&gt;Blaze&lt;/strong&gt; and how it makes improvements — and if you think about it, we said it relies on the concept of &lt;strong&gt;AST (Abstract Syntax Tree)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the same approach that &lt;strong&gt;Vue.js&lt;/strong&gt;, &lt;strong&gt;Svelte&lt;/strong&gt;, and &lt;strong&gt;Angular&lt;/strong&gt; use. So let's dig into it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Frameworks Exist
&lt;/h2&gt;

&lt;p&gt;The whole idea starts from wanting a different way to write code than the traditional approach — just to keep things cleaner and more expressive. That's basically the core purpose of frameworks.&lt;/p&gt;

&lt;p&gt;Since the code you write isn't understood directly by the browser, it goes through a &lt;strong&gt;compile&lt;/strong&gt; step, which transforms it into optimized JavaScript. During compilation, the AST is created — a Tree that represents and simplifies the structure of your code.&lt;/p&gt;

&lt;p&gt;The AST concept applies to &lt;em&gt;almost everything&lt;/em&gt; in the template, even something as simple as a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 4 Stages of AST Processing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Lexical Analysis (Tokenization)
&lt;/h3&gt;

&lt;p&gt;The code is broken down into an &lt;strong&gt;array of tokens&lt;/strong&gt; — small meaningful units the compiler can walk through one by one.&lt;/p&gt;

&lt;p&gt;For example, a function call like &lt;code&gt;isAdmin(1)&lt;/code&gt; becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type: function,    value: isAdmin
type: punctuation, value: (
type: int,         value: 1
type: punctuation, value: )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it — just a structured array of everything in your code, split apart and labeled.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Parsing
&lt;/h3&gt;

&lt;p&gt;The token array is used to build a &lt;strong&gt;Tree&lt;/strong&gt; — this is your AST. Each node in the tree represents a piece of your code with its full context and relationships.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to &lt;em&gt;see&lt;/em&gt; what an AST actually looks like, check out &lt;a href="https://astexplorer.net/" rel="noopener noreferrer"&gt;AST Explorer&lt;/a&gt; — it's a great visual tool.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  3. Optimization via AST Traversal
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens. The compiler &lt;strong&gt;walks through the tree&lt;/strong&gt; branch by branch — a process called &lt;strong&gt;AST Traversal&lt;/strong&gt;. Think of it like a journey through the structure of your code.&lt;/p&gt;

&lt;p&gt;One common traversal method is &lt;strong&gt;Depth-First Search (DFS)&lt;/strong&gt;, which itself has variants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-order&lt;/strong&gt; → Root → Left → Right&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-order&lt;/strong&gt; → Left → Root → Right&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-order&lt;/strong&gt; → Left → Right → Root&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During traversal, the compiler makes decisions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; with no dynamic content? → Mark it as &lt;strong&gt;static&lt;/strong&gt;, skip it in re-renders&lt;/li&gt;
&lt;li&gt;Something reactive or data-bound? → Attach a &lt;strong&gt;flag&lt;/strong&gt; so it gets tracked and updated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what allows some frameworks to &lt;strong&gt;reduce or eliminate their reliance on the Virtual DOM&lt;/strong&gt; entirely, while others (like Vue) still use it — but in a smarter, more targeted way.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Code Generation
&lt;/h3&gt;

&lt;p&gt;Finally, the optimized AST is used to generate the actual JavaScript that runs in the browser. The framework then uses this output to &lt;strong&gt;construct the real DOM&lt;/strong&gt; efficiently.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Wild Blade Idea
&lt;/h2&gt;

&lt;p&gt;Here's the part I find genuinely interesting — and maybe a little ambitious.&lt;/p&gt;

&lt;p&gt;What if we applied this entire pipeline to &lt;strong&gt;Blade&lt;/strong&gt; (Laravel's templating engine), properly — not just as a performance trick, but as a real compilation layer?&lt;/p&gt;

&lt;p&gt;At that point, it wouldn't just be about performance. We could build on top of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Morph diffing&lt;/strong&gt; — compare a Virtual Tree against the Real DOM and do surgical updates instead of full replacements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time attributes&lt;/strong&gt; — tag an element so the browser sends a request to the server, and PHP responds with &lt;em&gt;only the changed data&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Potentially a much lighter alternative to pulling in a full JS framework for dynamic UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is this basically what &lt;strong&gt;HTMX&lt;/strong&gt; does? Kind of. Is the Morph piece already in &lt;strong&gt;Alpine.js&lt;/strong&gt;? Also yes. But applying it &lt;em&gt;natively at the Blade level&lt;/em&gt;, with PHP-aware compilation — that's a different story.&lt;/p&gt;

&lt;p&gt;I don't know exactly how to implement it. Maybe it ends up in the bin like most late-night ideas. But I think it's worth writing down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🔗 &lt;a href="https://astexplorer.net/" rel="noopener noreferrer"&gt;AST Explorer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;a href="https://www.geeksforgeeks.org/dsa/depth-first-search-or-dfs-for-a-graph/" rel="noopener noreferrer"&gt;Depth-First Search — GeeksForGeeks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;a href="https://www.geeksforgeeks.org/compiler-design/parse-tree-in-compiler-design/" rel="noopener noreferrer"&gt;Parse Tree in Compiler Design — GeeksForGeeks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;a href="https://www.twilio.com/en-us/blog/developers/tutorials/building-blocks/abstract-syntax-trees" rel="noopener noreferrer"&gt;Abstract Syntax Trees — Twilio Blog&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>datastructures</category>
      <category>algorithms</category>
      <category>framework</category>
      <category>php</category>
    </item>
    <item>
      <title>Exploring an AST-Based Template Engine in PHP — Thoughts?</title>
      <dc:creator>Thomas Emad</dc:creator>
      <pubDate>Wed, 18 Mar 2026 15:50:07 +0000</pubDate>
      <link>https://dev.to/thomas_emad/exploring-an-ast-based-template-engine-in-php-thoughts-4g98</link>
      <guid>https://dev.to/thomas_emad/exploring-an-ast-based-template-engine-in-php-thoughts-4g98</guid>
      <description>&lt;p&gt;I’ve been exploring an idea and would really like to hear different perspectives on it.&lt;/p&gt;

&lt;p&gt;What if a PHP template engine (like Blade) moved from being string-based to an AST-driven pipeline (lexer → parser → AST), so it actually understands the structure of the template instead of just compiling it?&lt;/p&gt;

&lt;p&gt;The thought is that this could produce a tree representation of the view (some kind of server-side VDOM). With that, it might be possible to clearly separate static and dynamic parts based on AST analysis.&lt;/p&gt;

&lt;p&gt;In theory, instead of re-rendering the full HTML on every request, the server could work at a node level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;identify which parts are dynamic&lt;/li&gt;
&lt;li&gt;track them as nodes in a tree&lt;/li&gt;
&lt;li&gt;and update only those parts when data changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Something conceptually similar to how virtual DOM works in frameworks like Vue, but driven from the server side.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dynamic variables could be detected at compile time&lt;/li&gt;
&lt;li&gt;certain values could be marked as “live”&lt;/li&gt;
&lt;li&gt;the browser could request only those live parts (e.g. via small, specific requests)&lt;/li&gt;
&lt;li&gt;and the response would update only the affected nodes (kind of like DOM morphing instead of full re-render)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m not saying this is practical or better — I’m still trying to understand the trade-offs and limitations.&lt;/p&gt;

&lt;p&gt;I’d really appreciate your thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this approach make sense in a server-driven (PHP) context?&lt;/li&gt;
&lt;li&gt;Are there similar ideas or implementations I should look into?&lt;/li&gt;
&lt;li&gt;What challenges do you immediately see (performance, state, complexity, etc.)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just looking for an open technical discussion.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>deeplearning</category>
      <category>systemdesign</category>
      <category>php</category>
    </item>
    <item>
      <title>DTO Design Pattern: Is It Over-Engineered?</title>
      <dc:creator>Thomas Emad</dc:creator>
      <pubDate>Wed, 18 Mar 2026 14:06:00 +0000</pubDate>
      <link>https://dev.to/thomas_emad/dto-design-pattern-is-it-over-engineered-29cl</link>
      <guid>https://dev.to/thomas_emad/dto-design-pattern-is-it-over-engineered-29cl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7rjrrwbymt00tpy0r6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7rjrrwbymt00tpy0r6b.png" alt="Banner" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some people, when they try to explain DTOs, make it too simple just to be easy to understand — but they focus only on the explanation itself.&lt;/p&gt;

&lt;p&gt;That makes it easy to understand, but anyone will ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why should I use it?&lt;/li&gt;
&lt;li&gt;Can't I just use the normal way? Isn't this over-engineering?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\DTO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDTO&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when we want to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$userDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userDTO&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anyone will say: &lt;em&gt;Why am I using a DTO? I can just do this:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// $request-&amp;gt;validate()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And anyway, &lt;code&gt;$fillable&lt;/code&gt; will protect me from mass assignment.&lt;/p&gt;

&lt;p&gt;And to be honest with you: &lt;strong&gt;You are right.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Case: Big Data and Layers
&lt;/h2&gt;

&lt;p&gt;Now, let's see a real-world case.&lt;/p&gt;

&lt;p&gt;If we have big data and we transfer it across many layers, we usually use arrays. Just look at the &lt;code&gt;$history&lt;/code&gt; structure in this example.&lt;/p&gt;

&lt;p&gt;I use the same structure for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HolidayShift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PublicHoliday&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Errands&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Leaves&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OvertimeRequest&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some items may be &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, or may not exist at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getHolidayHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$timeManagement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$overtime_schedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$work_schedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$publicHolidays&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$holiday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$publicHolidays&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$holiday&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;between&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$holiday&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;start_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$holiday&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end_date&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$latesSignInMinutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;calculateLateSignIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$work_schedule&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$earlyLeaving&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;calculateEarlyLeaving&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$work_schedule&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'absent'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'type'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'holiday'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'date'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'item'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$holiday&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'attend_item'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'data'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="s1"&gt;'sign_in'&lt;/span&gt;                        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sign_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'sign_out'&lt;/span&gt;                       &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sign_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'late'&lt;/span&gt;                           &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$latesSignInMinutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'late_deducted_percent'&lt;/span&gt;          &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'early_leaving_deducted_percent'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'early_leaving'&lt;/span&gt;                  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;checkFromFingerprintOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$timeManagement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$earlyLeaving&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="s1"&gt;'deducted_percent'&lt;/span&gt;               &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'overtime'&lt;/span&gt;                       &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'amount_overtime'&lt;/span&gt;                &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;presentPublicHolidays&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPresentPublicHolidayAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nv"&gt;$overtime_schedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nv"&gt;$contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;
                    &lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'absent'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'type'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'holiday'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'date'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'attend_item'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you see the potential problems here?&lt;/p&gt;

&lt;p&gt;From a coding perspective, we can make it work without errors. But realistically, we are never 100% sure.&lt;/p&gt;

&lt;p&gt;Of course, for big features we use testing — but in cases like this, TDD is not always realistic. So if some item does not exist, every time we use &lt;code&gt;$history&lt;/code&gt; we have to write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Can We Use DTOs Here?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AttendanceHistoryDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;absent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'holiday'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$holiday&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;attend_item&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AttendanceDataDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;sign_in&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sign_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;sign_out&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sign_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;total_late&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$latesSignInMinutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;early_leaving&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;checkFromFingerprintOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$timeManagement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$earlyLeaving&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;deducted_percent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;overtime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;amount_overtime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;presentPublicHolidays&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPresentPublicHolidayAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$overtime_schedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$attend&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;late_deducted_percent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;early_leaving_deducted_percent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, any time we use &lt;code&gt;$history&lt;/code&gt;, we don't need to worry about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the &lt;strong&gt;default values live inside the DTO itself.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling Missing Data in Real Use
&lt;/h2&gt;

&lt;p&gt;Now look at this real usage example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="o"&gt;?-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;?-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;total_late&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="o"&gt;?-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;?-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;total_late&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why am I still doing this even with DTOs?&lt;/p&gt;

&lt;p&gt;Because when you use DTOs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you write something that does not exist, your editor will warn you.&lt;/li&gt;
&lt;li&gt;PHP will throw an exception in development and testing — and that's good.&lt;/li&gt;
&lt;li&gt;But throwing exceptions in &lt;strong&gt;production&lt;/strong&gt; is not always a good idea 😅&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Right Approach: Focus on Business Needs
&lt;/h2&gt;

&lt;p&gt;There are many correct ways to use DTOs.&lt;/p&gt;

&lt;p&gt;But always &lt;strong&gt;focus on your business needs first.&lt;/strong&gt; Understand the problem, then choose the right tool.&lt;/p&gt;

&lt;p&gt;Personally, I prefer to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Write the code badly → make it normal → then ask: what is the best solution?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What do you think? 😃
&lt;/h2&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>designpatterns</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why PHP-FPM Consumes More RAM in Production Than Actual Usage?!</title>
      <dc:creator>Thomas Emad</dc:creator>
      <pubDate>Tue, 17 Mar 2026 14:04:06 +0000</pubDate>
      <link>https://dev.to/thomas_emad/why-php-fpm-consumes-more-ram-in-production-than-actual-usage-1d50</link>
      <guid>https://dev.to/thomas_emad/why-php-fpm-consumes-more-ram-in-production-than-actual-usage-1d50</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio1ci9ysxms1z1adneq3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio1ci9ysxms1z1adneq3.webp" alt="Banner" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding PHP-FPM Memory Behavior
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Quick answer:&lt;/strong&gt; PHP-FPM doesn't release memory back to the OS after allocation because memory allocation is expensive. Instead, it keeps the memory reserved for potential reuse. This isn't a memory leak — the memory remains accessible and reusable by PHP.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Understanding PHP's Memory Lifecycle
&lt;/h2&gt;

&lt;p&gt;PHP has a lifecycle similar to what you might see in frameworks like Laravel. PHP's execution goes through several phases, starting with &lt;code&gt;MINIT()&lt;/code&gt; and ending with &lt;code&gt;MSHUTDOWN()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;During &lt;code&gt;MINIT()&lt;/code&gt;, PHP allocates just enough memory to get started using &lt;code&gt;start_memory_manager&lt;/code&gt;. This initializes the allocator with a minimal baseline from the OS — around 45KB as an example.&lt;/p&gt;

&lt;p&gt;Then, during &lt;code&gt;RINIT()&lt;/code&gt; (request initialization), when your application handles a job, performs a large collection operation, or executes a resource-intensive query, PHP needs to allocate more memory (e.g., 124MB). This is when the &lt;strong&gt;Zend Memory Manager (ZMM)&lt;/strong&gt; springs into action.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Zend Memory Manager Allocates Memory
&lt;/h2&gt;

&lt;p&gt;The ZMM categorizes memory allocations into three types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small allocations:&lt;/strong&gt; Less than 3KB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large allocations:&lt;/strong&gt; Between 3KB and 2MB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Huge allocations:&lt;/strong&gt; Greater than 2MB (these come directly from the OS)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If there's no pre-allocated memory available, huge allocations use &lt;code&gt;mmap&lt;/code&gt; and are handled differently from smaller allocations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, if PHP needs memory, it might request 150MB from the ZMM, which then asks the OS to reserve that space using &lt;code&gt;mmap&lt;/code&gt;. But why 150MB when you only needed 124MB?&lt;/p&gt;

&lt;p&gt;This is called &lt;strong&gt;pre-allocation&lt;/strong&gt;. PHP requests slightly more memory than immediately needed to reduce the number of expensive &lt;code&gt;mmap&lt;/code&gt; and &lt;code&gt;munmap&lt;/code&gt; system calls to the OS. This optimization improves performance by batching memory operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens After Request Completion
&lt;/h2&gt;

&lt;p&gt;When the request finishes, &lt;code&gt;RSHUTDOWN()&lt;/code&gt; is triggered. The garbage collector kicks in, frees up the memory space, and cleans up &lt;code&gt;zvals&lt;/code&gt; (PHP's internal value structures).&lt;/p&gt;

&lt;p&gt;However — and this is the key point — &lt;strong&gt;PHP and ZMM free this memory internally but don't return it to the OS.&lt;/strong&gt; Why? Because if PHP needs memory again soon, it can reuse what's already allocated instead of requesting more from the OS. Since memory allocation is relatively expensive in terms of system resources, PHP keeps this memory reserved as a performance optimization.&lt;/p&gt;

&lt;p&gt;This means whenever PHP needs memory again, it uses what's already available rather than making new system calls. While efficient, it causes PHP to &lt;em&gt;appear&lt;/em&gt; to consume more RAM than it's actively using.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About &lt;code&gt;unset()&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;You might be thinking: &lt;em&gt;"But doesn't &lt;code&gt;unset()&lt;/code&gt; free memory in PHP?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes, &lt;code&gt;unset()&lt;/code&gt; removes references to objects and creates free blocks that can be reused — but these are typically small allocations. However, if enough memory is freed to clear an entire &lt;strong&gt;page&lt;/strong&gt; (ranging from 4KB to 2MB) and clear a complete &lt;strong&gt;chunk&lt;/strong&gt;, only then will PHP return that memory to the OS.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Implications and Best Practices
&lt;/h2&gt;

&lt;p&gt;This behavior explains why frameworks like Laravel implement features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lazy loading:&lt;/strong&gt; Defers loading resources until needed &lt;em&gt;(though don't overuse it or you'll face performance issues)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking:&lt;/strong&gt; Processes large datasets in smaller batches&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipes:&lt;/strong&gt; Streams data through transformations efficiently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These patterns help manage memory more effectively by working &lt;em&gt;with&lt;/em&gt; PHP's memory management behavior rather than against it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;PHP-FPM's higher-than-expected RAM consumption in production &lt;strong&gt;isn't a bug or a memory leak&lt;/strong&gt; — it's an intentional optimization. By keeping allocated memory reserved rather than constantly requesting and releasing it from the OS, PHP reduces expensive system calls and improves overall performance. Understanding this behavior helps you better monitor and optimize your PHP applications in production environments.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>ram</category>
      <category>resources</category>
    </item>
    <item>
      <title>How Blaze Could Change Blade Component Rendering in Laravel</title>
      <dc:creator>Thomas Emad</dc:creator>
      <pubDate>Sun, 15 Mar 2026 17:42:45 +0000</pubDate>
      <link>https://dev.to/thomas_emad/how-blaze-could-change-blade-component-rendering-in-laravel-272o</link>
      <guid>https://dev.to/thomas_emad/how-blaze-could-change-blade-component-rendering-in-laravel-272o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82gwbqklqb1cwqf59mm6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82gwbqklqb1cwqf59mm6.png" alt="banner for banchmark"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently, there has been an interesting trend in modern tooling: moving work from runtime to compile time to improve performance.&lt;/p&gt;

&lt;p&gt;We can see this direction in multiple tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vite 8 now moving toward Rolldown built by Rust&lt;/li&gt;
&lt;li&gt;Continuous improvements in Inertia.js&lt;/li&gt;
&lt;li&gt;A new idea around Laravel Blade components called Blaze&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we'll explore the idea behind Blaze and why it could improve Blade component rendering.&lt;/p&gt;




&lt;h2&gt;
  
  
  First: How Blade Works
&lt;/h2&gt;

&lt;p&gt;Before talking about Blaze, we need to remember how Laravel Blade works.&lt;/p&gt;

&lt;p&gt;In Laravel, Blade is a templating engine that allows developers to write directives such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@if ($condition)
    &amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt;
@endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But HTML does not understand &lt;code&gt;@if&lt;/code&gt; or &lt;code&gt;@php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the first time a page is loaded, Laravel runs the Blade compiler which transforms Blade directives into plain PHP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After compilation, Laravel stores the compiled result inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;storage/framework/views
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the next time the page is requested, Laravel simply loads the compiled PHP file instead of recompiling the Blade template.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Blade Files Grow
&lt;/h2&gt;

&lt;p&gt;Imagine your &lt;code&gt;dashboard.blade.php&lt;/code&gt; becomes larger and contains multiple UI parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Charts&lt;/li&gt;
&lt;li&gt;Employee attendance&lt;/li&gt;
&lt;li&gt;Calendar&lt;/li&gt;
&lt;li&gt;Widgets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will most likely start using Blade components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-charts :data="$data" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Laravel encounters this component, it resolves it internally. A simplified version of the process looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
 → Create Component
 → Render View
 → Return HTML
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnpta7w588oybqg8wb1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnpta7w588oybqg8wb1o.png" alt="convert file for blade component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This process happens during &lt;strong&gt;runtime&lt;/strong&gt;. If your page contains many components, this repeated rendering can introduce some overhead.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter Blaze
&lt;/h2&gt;

&lt;p&gt;Blaze is not a replacement for Blade. Instead, it aims to &lt;strong&gt;optimize how Blade components are rendered&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The key idea behind Blaze is something similar to folding and compilation. Instead of repeatedly rendering components during runtime, Blaze analyzes the component structure first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building an AST
&lt;/h3&gt;

&lt;p&gt;Blaze breaks the component into nodes and constructs something similar to an &lt;strong&gt;AST (Abstract Syntax Tree)&lt;/strong&gt;. This is similar to how frameworks like Vue.js analyze templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Component
 ├─ HTML Node
 ├─ Attribute Node
 └─ Child Component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the structure is analyzed, Blaze can optimize and cache the result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating a Function
&lt;/h3&gt;

&lt;p&gt;Instead of recreating the component logic every request, Blaze generates a function representing the compiled component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compile Component
 → Generate Function
 → Cache Function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then when the page renders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call Function
 → Return HTML
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Three Possible Component Scenarios
&lt;/h2&gt;

&lt;p&gt;Blaze handles components in three main ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First time execution&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call function
 → Execute
 → Return HTML
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Repeated component usage&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Return cached result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Static components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the component is fully static (for example, an icon component), Blaze can skip compilation and directly return the HTML.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplified Blaze Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compile
 → Generate Function
 → Call Function
 → Return HTML
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core idea is simple: &lt;strong&gt;move work from runtime to compile time.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  A Broader Trend in Modern Tooling
&lt;/h2&gt;

&lt;p&gt;This idea is not unique to Blaze. Many modern tools are moving in this direction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rust-based compilers&lt;/li&gt;
&lt;li&gt;Faster bundlers&lt;/li&gt;
&lt;li&gt;More aggressive compile-time optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vite adopting Rolldown&lt;/li&gt;
&lt;li&gt;Faster compilation pipelines&lt;/li&gt;
&lt;li&gt;Smaller runtime cost&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Blaze introduces an interesting direction for improving Blade component rendering. By shifting more work into compile time, it may reduce the runtime overhead caused by repeatedly rendering components.&lt;/p&gt;

&lt;p&gt;This approach aligns with a broader trend across modern developer tooling.&lt;/p&gt;

&lt;p&gt;In the next article, we'll explore Vite and Rolldown and why the ecosystem is increasingly moving toward Rust-based tooling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/balapriya/abstract-syntax-tree-ast-explained-in-plain-english-1h38"&gt;Abstract Syntax Tree (AST) Explained in Plain English&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tighten.com/insights/blaze-under-the-hood" rel="noopener noreferrer"&gt;Blaze Under the Hood – Tighten&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laravel-news.com/livewire-blaze" rel="noopener noreferrer"&gt;Livewire Blaze – Laravel News&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Just_In_Time_Compilation" rel="noopener noreferrer"&gt;Just-In-Time Compilation – MDN Web Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Thinking Out Loud: A Workflow Engine I Built at Work This Week</title>
      <dc:creator>Thomas Emad</dc:creator>
      <pubDate>Sat, 21 Feb 2026 17:34:30 +0000</pubDate>
      <link>https://dev.to/thomas_emad/thinking-out-loud-a-workflow-engine-i-built-at-work-this-week-1gf9</link>
      <guid>https://dev.to/thomas_emad/thinking-out-loud-a-workflow-engine-i-built-at-work-this-week-1gf9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wfy0at8f4am0b7j2mu1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wfy0at8f4am0b7j2mu1.png" alt="simple flow desgin" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was thinking about something that excited me at work this week, and I wanted to share it out loud.&lt;/p&gt;

&lt;p&gt;Imagine you have a flow covering &lt;strong&gt;Sales&lt;/strong&gt;, &lt;strong&gt;Supply Chain&lt;/strong&gt;, and &lt;strong&gt;Pre-Sales&lt;/strong&gt;, all connected in a &lt;strong&gt;monolithic project&lt;/strong&gt;. The flow might start with a &lt;strong&gt;BOQ&lt;/strong&gt;, then produce a Purchase Request, then check if inventory is available — if yes, create a Quotation; if not, send a &lt;strong&gt;Request for Quotation (RFQ),&lt;/strong&gt; then collect Supplier Quotations, and eventually move to purchasing, warehousing, and delivery to the client, with many branching cases at each step.&lt;/p&gt;

&lt;p&gt;Now imagine you want to know: where did this BOQ end up?&lt;br&gt;
You’d want a Stage column on each item in the flow, so when you open a BOQ it tells you “we’re currently at Material Issue stage”, and when you open a Supplier Quotation it tells you the same. &lt;/p&gt;

&lt;p&gt;A Live Query for this would be a nightmare given how branched and deep the flow is, so the better approach is storing the stage as a database column — and this wasn’t just the easier choice, the business requirements actually needed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But here’s the problem:&lt;/strong&gt; every time the stage changes, do I have to update the entire flow at once? And in every service, do I have to embed the entire flow logic? Imagine the amount of repetition that creates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So I asked myself:&lt;/strong&gt; what if, from any point in the flow, I only need to know what came before me and pass it the update — nothing more?&lt;/p&gt;

&lt;p&gt;Inside &lt;strong&gt;PurchaseRequestService&lt;/strong&gt;, I know the step before me is BOQ and I have its ID.&lt;br&gt;
Inside &lt;strong&gt;QuotationService&lt;/strong&gt;, the step before me is Purchase Request.&lt;br&gt;
Inside &lt;strong&gt;RequestForQuotationService&lt;/strong&gt;, the step before me is also Purchase Request.&lt;/p&gt;

&lt;p&gt;If every service can say “here’s what came before me” and pass along the update data, that would be elegant.&lt;/p&gt;

&lt;p&gt;The solution came to mind from a tutorial I was studying in the morning — a video about Event-Driven Architecture (EDA) and how powerful it is in microservices. If you’re interested, it’s in Arabic, so you might want to enable subtitles or switch to Arabic, whichever works for you 🙂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtube.com/playlist?list=PLpJtaIgvI9k_Kz2x91AtekDdVvqzYfMIm&amp;amp;si=Bvfvn4RkODE4jDUF" rel="noopener noreferrer"&gt;https://youtube.com/playlist?list=PLpJtaIgvI9k_Kz2x91AtekDdVvqzYfMIm&amp;amp;si=Bvfvn4RkODE4jDUF&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDA is built on a simple concept:&lt;/strong&gt; Producer + Broker + Consumer.&lt;/p&gt;

&lt;p&gt;I basically needed to fire an event from any service, have it directed to the right service that needs updating, pass the data, and let that service update itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Losing me? Let me break it down:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When Create Purchase Request 
  -&amp;gt; Fire Event (Producer) 
  -&amp;gt; Listener (Broker) 
  -&amp;gt; Finds the right service 
  -&amp;gt; BoqService (Consumer) 
  -&amp;gt; Updates BOQ with $data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;But what if&lt;/strong&gt; we want it to keep going dynamically and propagate on its own? Simple — we return the previous step as part of the response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When Create RFQ 
  -&amp;gt; Fire Event (Producer) 
  -&amp;gt; Listener (Broker) 
  -&amp;gt; Finds the right service 
  -&amp;gt; PurchaseRequestService (Consumer) -&amp;gt; {
       Update current PR with $data
       Return previous step (BOQ) + new $data
       Fire new event with new data
     }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This needs to run through a &lt;strong&gt;queue&lt;/strong&gt; because doing it synchronously at runtime would be terrible for performance — and we don’t need the update to happen in the same second anyway. It essentially becomes a recurring event that keeps firing until it hits the zero point, which is the BOQ (where it returns null and stops). The actual zero point in our case is the Purchase Request, for business reasons &lt;strong&gt;I helped design 🙂&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s now look at how this translates to code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Event — SalesProcessEvent:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Modules\Sales\Events;

use Illuminate\Queue\SerializesModels;
use Modules\Sales\Enums\SalesProcessStepEnum;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;

class SalesProcessEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     */
    public function __construct(
      public SalesProcessStepEnum $mainStage, 
      public SalesProcessStepEnum $openStage,
      public array $data
    ) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Listener (our Broker) — SalesProcessListener:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Modules\Sales\Listeners;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Modules\Sales\Events\SalesProcessEvent;
use Modules\Sales\Strategies\Classes\SalesProcessStrategy;

class SalesProcessListener implements ShouldQueue
{
    use InteractsWithQueue;

    public function __construct(
        private SalesProcessStrategy $salesProcessStrategy
    ) {}

    public function handle(SalesProcessEvent $event): void
    {
        $mainStage = $event-&amp;gt;mainStage;
        $openStage = $this-&amp;gt;salesProcessStrategy
            -&amp;gt;setService($event-&amp;gt;openStage)
            -&amp;gt;updateStage($mainStage, $event-&amp;gt;openStage, $event-&amp;gt;data);

        if ($openStage !== null) {
            SalesProcessEvent::dispatch($mainStage, $openStage['stage'], $openStage['data']);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything here depends on &lt;strong&gt;SalesProcessStrategy&lt;/strong&gt;. If you're not familiar with the &lt;strong&gt;Strategy Pattern&lt;/strong&gt;, the course above covers it well. The short version: &lt;/p&gt;

&lt;p&gt;it takes fixed input, runs different operations depending on context, and can return different output. What changes is the process in the middle — and what controls that is the &lt;strong&gt;Strategy&lt;/strong&gt;, which &lt;strong&gt;resolves&lt;/strong&gt; the right &lt;strong&gt;Service&lt;/strong&gt; based on the &lt;strong&gt;type&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We have &lt;strong&gt;$mainStage&lt;/strong&gt; — the latest state that everyone should be updated to — and &lt;strong&gt;$openStage&lt;/strong&gt; — the service we're going to open and update. We set it via &lt;strong&gt;setService&lt;/strong&gt;, then call &lt;strong&gt;updateStage&lt;/strong&gt;. If updateStage returns another step, the listener fires a new event for that step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Strategy — SalesProcessStrategy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Modules\Sales\Strategies\Classes;

use Modules\PreSales\Services\BoqService;
use Modules\Sales\Enums\SalesProcessStepEnum;
use Modules\PreSales\Services\QuotationService;
use Modules\Sales\Services\MaterialIssueService;
use Modules\Inventory\Services\GoodsReceiptService;
use Modules\Inventory\Services\MaterialReceiptService;
use Modules\SupplyChain\Services\PurchaseOrderService;
use Modules\Inventory\Services\MaterialDispatchService;
use Modules\PreSales\Services\SupplierQuotationService;
use Modules\SupplyChain\Services\PurchaseReceiptService;
use Modules\SupplyChain\Services\PurchaseRequestService;
use Modules\PreSales\Services\RequestForQuotationService;
use Modules\Sales\Strategies\Interface\SalesProccesInterface;

class SalesProcessStrategy
{
    private ?SalesProccesInterface $service = null;

    /**
     * Set the service based on the stage.
     */
    public function setService(SalesProcessStepEnum $stage): static
    {
        $this-&amp;gt;service = match ($stage) {
            SalesProcessStepEnum::BOQ                =&amp;gt; new BoqService(),
            SalesProcessStepEnum::PURCHASE_REQUEST   =&amp;gt; new PurchaseRequestService(),
            SalesProcessStepEnum::RFQ                =&amp;gt; new RequestForQuotationService(),
            SalesProcessStepEnum::SUPPLIER_QUOTATION =&amp;gt; new SupplierQuotationService(),
            SalesProcessStepEnum::QUOTATION          =&amp;gt; new QuotationService(),
            SalesProcessStepEnum::PURCHASE_ORDER     =&amp;gt; new PurchaseOrderService(),
            SalesProcessStepEnum::PURCHASE_RECEIPT   =&amp;gt; new PurchaseReceiptService(),
            SalesProcessStepEnum::MATERIAL_RECEIPT   =&amp;gt; new MaterialReceiptService(),
            SalesProcessStepEnum::MATERIAL_ISSUE     =&amp;gt; new MaterialIssueService(),
            SalesProcessStepEnum::MATERIAL_DISPATCH  =&amp;gt; new MaterialDispatchService(),
            SalesProcessStepEnum::GOODS_RECEIPT      =&amp;gt; new GoodsReceiptService(),
            default =&amp;gt; null,
        };

        return $this;
    }

    /**
     * Update the stage.
     */
    public function updateStage(SalesProcessStepEnum $mainStage, SalesProcessStepEnum $openStage, array $data): mixed
    {
        if ($this-&amp;gt;service === null) {
            throw new \InvalidArgumentException("No service resolved for stage: {$openStage}, main stage: {$mainStage}");
        }

        return $this-&amp;gt;service-&amp;gt;updateStage($mainStage, $openStage, $data);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;setService&lt;/strong&gt; resolves the right Service based on the type and returns &lt;strong&gt;$this&lt;/strong&gt;, which lets us use &lt;strong&gt;Method Chaining&lt;/strong&gt; — a pattern used heavily in &lt;strong&gt;Laravel&lt;/strong&gt;. Look it up, you'll love it, and it's part of the Builder Pattern.&lt;/p&gt;

&lt;p&gt;The reason we typed the property as &lt;strong&gt;SalesProccesInterface&lt;/strong&gt; is to enforce a contract. Think of it like going to a &lt;strong&gt;coffee shop&lt;/strong&gt; and ordering coffee — you shouldn't get plain milk back. It might accidentally become a French coffee, but that's &lt;strong&gt;unexpected behavior&lt;/strong&gt;. We prevent that by setting clear standards through an interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Interface — SalesProccesInterface:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;?php

namespace Modules\Sales\Strategies\Interface;

use Modules\Sales\Enums\SalesProcessStepEnum;

interface SalesProccesInterface
{
    /*
     * Update the stage.
     */
    public function updateStage(SalesProcessStepEnum $mainStage, SalesProcessStepEnum $openStage, array $data): mixed;
    public function dispatchPreviousStage(SalesProcessStepEnum $mainStage, SalesProcessStepEnum $openStage, array $data): void;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;BoqService:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Modules\PreSales\Services;

use Modules\PreSales\Models\Boq;
use Modules\Sales\Enums\SalesProcessStepEnum;
use Modules\Inventory\Events\RegistrationItemCreatedEvent;
use Modules\Sales\Strategies\Interface\SalesProccesInterface;

class BoqService implements SalesProccesInterface 
{
    /**
     * Update the stage.
     */
    public function updateStage(SalesProcessStepEnum $mainStage, SalesProcessStepEnum $openStage, array $data): mixed
    {
        $boq = Boq::find($data['id']);
        if ($boq &amp;amp;&amp;amp; SalesProcessStepEnum::upThanCurrent($boq-&amp;gt;stage, $mainStage)) {
            $boq-&amp;gt;update([
                'stage' =&amp;gt; $mainStage,
            ]);
        }

        return null;
    }

    /**
     * Dispatch previous stage.
     */
    public function dispatchPreviousStage(SalesProcessStepEnum $mainStage, SalesProcessStepEnum $openStage, array $data): void {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We update the &lt;strong&gt;BOQ&lt;/strong&gt; only if two conditions are met: the BOQ exists, and &lt;strong&gt;upThanCurrent&lt;/strong&gt; confirms the new stage is actually newer and higher. This matters because the BOQ might already be at final delivery stage, &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;then something goes wrong&lt;/strong&gt; — a damaged shipment — and the client requests a new Purchase Order. In that case, the BOQ should stay as-is. We'd handle the exception separately in a Log, which is a topic for another day 🙂&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dispatchPreviousStage&lt;/strong&gt; is empty here because nothing comes before BOQ in this flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PurchaseRequestService:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Modules\SupplyChain\Services;

use Modules\PreSales\Models\Boq;
use Modules\Sales\Events\SalesProcessEvent;
use Modules\Sales\Enums\SalesProcessStepEnum;
use Modules\SupplyChain\Models\PurchaseRequest;
use Modules\SupplyChain\Enums\PurchaseRequestTypeEnum;
use Modules\Sales\Strategies\Interface\SalesProccesInterface;

class PurchaseRequestService implements SalesProccesInterface
{


    /**
     * Create a new PurchaseRequest.
     *
     * @param array $data
     * @return \Modules\SupplyChain\Models\PurchaseRequest
     */
    public function store(array $data): PurchaseRequest
    {
        $purchaseRequest = PurchaseRequest::create($data);

        $this-&amp;gt;syncPurchaseRequestItem($purchaseRequest, $data);

        $this-&amp;gt;dispatchPreviousStage(SalesProcessStepEnum::PURCHASE_REQUEST, SalesProcessStepEnum::BOQ, [
            'id'   =&amp;gt; $purchaseRequest-&amp;gt;pull_id,
        ]);

        return $purchaseRequest-&amp;gt;fresh();
    }

    /**
     * Update the stage.
     */
    public function updateStage(SalesProcessStepEnum $mainStage, SalesProcessStepEnum $openStage, array $data): mixed
    {
        $purchaseRequest = PurchaseRequest::find($data['id']);
        if ($purchaseRequest &amp;amp;&amp;amp; SalesProcessStepEnum::upThanCurrent($purchaseRequest-&amp;gt;stage, $mainStage)) {
            $purchaseRequest-&amp;gt;update([
                'stage' =&amp;gt; $mainStage,
            ]);
        }

        if ($purchaseRequest-&amp;gt;type == PurchaseRequestTypeEnum::PROJECT) {
            return [
                'stage' =&amp;gt; SalesProcessStepEnum::BOQ,
                'data' =&amp;gt; [
                    'id'   =&amp;gt; $purchaseRequest?-&amp;gt;pull_id ?? null,
                ]
            ];
        }
        return null;
    }

    /**
     * Dispatch previous stage.
     */
    public function dispatchPreviousStage(SalesProcessStepEnum $mainStage, SalesProcessStepEnum $openStage, array $data): void
    {
        SalesProcessEvent::dispatch($mainStage, $openStage, $data);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In store, &lt;strong&gt;dispatchPreviousStage&lt;/strong&gt; fires immediately when a new record is created — it's the starting fire point. It says: my current stage is PURCHASE_REQUEST, the step before me is BOQ, here's its ID, go update it.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;updateStage&lt;/strong&gt;, the service acts as a &lt;strong&gt;Consumer&lt;/strong&gt;: it updates itself, then returns the previous step's data so the *&lt;em&gt;Listener&lt;/em&gt; *knows there's another step to process and fires a new event for it. That's the recursion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You might ask:&lt;/strong&gt; why have both dispatchPreviousStage and updateStage? Because they serve different roles:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dispatchPreviousStage →&lt;/strong&gt; fires on creation (the trigger point)&lt;br&gt;
&lt;strong&gt;updateStage →&lt;/strong&gt; fires as a consumer when receiving an event, updates itself, then returns the previous step to keep the chain going&lt;/p&gt;

&lt;p&gt;This means each Service is simultaneously a &lt;strong&gt;Producer for the steps&lt;/strong&gt; that precede it, and a &lt;strong&gt;Consumer for the events coming toward it&lt;/strong&gt; — and it returns the previous step so the &lt;strong&gt;Broker&lt;/strong&gt; can keep firing until we reach the zero point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is the simplified version.&lt;/strong&gt; You could absolutely add DTOs for stronger type safety and more validation, and at that point you’d essentially have a &lt;strong&gt;Workflow Engine&lt;/strong&gt;. I can’t share the full codebase since this is just a small piece inside an ERP system at my company.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finally&lt;/strong&gt; — I’m just your junior self-taught friend who’s trying to figure things out, so feedback is always welcome.&lt;/p&gt;

&lt;p&gt;The idea is entirely my own with no AI involvement. I only used AI to fix spelling and grammar in this write-up — not in the workflow engine itself, not in the idea, not in anything else here.&lt;/p&gt;

&lt;p&gt;Take care 👋&lt;/p&gt;

</description>
      <category>software</category>
      <category>architecture</category>
      <category>laravel</category>
      <category>eventdriven</category>
    </item>
  </channel>
</rss>
