<?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: Denzyl Dick </title>
    <description>The latest articles on DEV Community by Denzyl Dick  (@denzyldick).</description>
    <link>https://dev.to/denzyldick</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F60385%2F7c9cf11a-8c24-410b-85bd-6bb32b93434b.jpeg</url>
      <title>DEV Community: Denzyl Dick </title>
      <link>https://dev.to/denzyldick</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/denzyldick"/>
    <language>en</language>
    <item>
      <title>How I made it impossible to write spaghetti code. Part 2</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sun, 06 Sep 2026 14:01:02 +0000</pubDate>
      <link>https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-part-2-317b</link>
      <guid>https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-part-2-317b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is the part(3) of a series. I suggest you read parts &lt;a href="https://dev.to/denzyldick/the-beginning-of-my-php-static-analyzer-in-rust-5bp8"&gt;1&lt;/a&gt; and &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt; before this one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In part &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt;, I made sure that the test passed correctly. The focus now is how we traverse a block of code inside its scope. We should be able to increase the variables in the formula at the right moment.&lt;/p&gt;

&lt;p&gt;If you have read part &lt;a href="https://dev.to/denzyldick/the-beginning-of-my-php-static-analyzer-in-rust-5bp8"&gt;1&lt;/a&gt;, you know that we need to implement the validate function that is mandatory in the trait &lt;code&gt;Rule&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Rule&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;E009&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;php_parser_rs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;project&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Suggestion&lt;/span&gt;&lt;span class="o"&gt;&amp;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;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;In part &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt; we have learned that :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nodes are like the conditional statement: if, else, while, for, etc.&lt;br&gt;&lt;br&gt;
Edges are the paths that can be taken.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;validate&lt;/code&gt; function will be executed for every statement in a source code. In the source code below, there are 32 lines of code.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Index&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;tooComplex&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$b&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="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$a&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="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

          &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$a&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;Phanalist&lt;/a&gt; needs a way to detect when we are in the function's scope with the name &lt;code&gt;tooComplex().&lt;/code&gt; With pattern matching, it is super easy to detect if the statement is either: &lt;code&gt;if&lt;/code&gt;,&lt;code&gt;else&lt;/code&gt;,&lt;code&gt;etc..&lt;/code&gt; The first statement that I want to match for is &lt;code&gt;class Index{&lt;/code&gt; and from there, we will continue down the tree. If you think the same way as I do you know that I will be using recursion to calculate the cyclomatic complexity. After we have matched the scope of the &lt;code&gt;tooComplex()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;impl&lt;/span&gt; &lt;span class="nx"&gt;Rule&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;E009&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;php_parser_rs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;Suggestion&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mut&lt;/span&gt; &lt;span class="nx"&gt;suggestions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="na"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mut&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Graph&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;member&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="nx"&gt;member&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;ClassMember&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;ConcreteMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concretemethod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="nx"&gt;concretemethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="nx"&gt;MethodBody&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="na"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="na"&gt;left_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="nx"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="na"&gt;right_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                   &lt;span class="c1"&gt;/// HERE !!&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="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;suggestions&lt;/span&gt;
    &lt;span class="p"&gt;}}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;If you aren't familiar with pattern matching, it's kind of a switch keyword on steroids. Look for the Look for &lt;code&gt;/// HERE !!&lt;/code&gt; in the above code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nx"&gt;MethodBody&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="nl"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="nx"&gt;left_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="nx"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="nx"&gt;right_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="c1"&gt;/// HERE 1&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;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;As you can see we have four parameters that we can use. The ones we are looking for are the statements. The type of this parameter is &lt;code&gt;Vec&amp;lt;Statement&amp;gt;&lt;/code&gt; meaning it can be anything.&lt;/p&gt;

&lt;p&gt;Let's use the &lt;code&gt;Graph&lt;/code&gt; we previously created in part &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the source code below, &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;Phanalist&lt;/a&gt; calls a function with &lt;code&gt;let graph = calculate _cyclomatic_complexity();&lt;/code&gt; This function will return a struct of the type &lt;code&gt;Graph&lt;/code&gt;. The first parameter passed is &lt;code&gt;statements.clone()&lt;/code&gt;. This function uses recursion to traverse down the tree. In part 4 I will explain the recursion we were thinking about.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_cyclomatic_complexity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                        &lt;span class="nx"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                                        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;mut&lt;/span&gt; &lt;span class="nx"&gt;graph&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="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;suggestions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Suggestion&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This method body is too complex. Make it easier to understand.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="nx"&gt;concretemethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;E009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_string&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;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Graph&lt;/code&gt; struct has the &lt;code&gt;calculate&lt;/code&gt; function we previously used to calculate the cyclomatic complexity. My threshold is always ten, so I will be using that.&lt;/p&gt;

&lt;p&gt;If the value exceeds ten, I push the &lt;code&gt;Suggestion&lt;/code&gt; onto the vector. The vector of &lt;code&gt;Suggestion&lt;/code&gt; is the value returned to the validate function's caller.&lt;/p&gt;

&lt;h1&gt;
  
  
  Recursion
&lt;/h1&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6u5ehsa4raomxcobxak.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6u5ehsa4raomxcobxak.png" alt=" " width="287" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In computer science, recursion is a method of solving a computational problem where the solution depends on solutions to smaller instances of the same problem. Recursion solves such recursive problems using functions that call themselves from within their code. &lt;a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;If you are a PHP developer, you know that a developer can make many more mistakes in PHP. In the future, the list of Rules will continue to grow into something more useful.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;Contribution is always welcome if you have a mistake you would like to add to &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;Phanalist&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/how-i-made-it-impossible-to-write-spaghetti-code-part-2-560hz?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication-footer" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>php</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why is unserializing an object in PHP a bad idea?</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sun, 06 Sep 2026 14:00:03 +0000</pubDate>
      <link>https://dev.to/denzyldick/why-is-unserializing-an-object-in-php-a-bad-idea-213o</link>
      <guid>https://dev.to/denzyldick/why-is-unserializing-an-object-in-php-a-bad-idea-213o</guid>
      <description>&lt;p&gt;Serializing in PHP is a way of converting a PHP object into a string. This string can be used in various ways, such as storing it in a database or passing it to another function. The PHP documentation says this is handy when passing PHP values around without losing their type and structure. But I have never had that problem before. Maybe I’m not seeing 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="cp"&gt;&amp;lt;?php&lt;/span&gt;&lt;span class="nv"&gt;$test&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;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="nv"&gt;$test&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="s2"&gt;"Denzyl"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$test&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="c1"&gt;/// Output: O:4:"User":1:{s:4:"name";s:6:"Denzyl";}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;So, let's digest the string. The &lt;code&gt;o&lt;/code&gt; stands for Object, and the following number is the length of the object's name. The two letters &lt;code&gt;s&lt;/code&gt; stand for string and the length of the string's name.  &lt;/p&gt;

&lt;p&gt;When you need to convert the string back into PHP, call the &lt;code&gt;unserialize&lt;/code&gt; function and pass the string as a parameter.&lt;/p&gt;

&lt;p&gt;When serializing an object, two methods are automagically being called. &lt;code&gt;__serialize()&lt;/code&gt; &amp;amp; &lt;code&gt;__sleep()&lt;/code&gt;. This will allow the class author to do something before converting the object into a string.&lt;br&gt;&lt;br&gt;
That is straight to the point. But for now, let’s focus on unserializing the string. This means converting the string into a real PHP object that can be later used at runtime in your PHP code.&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="nv"&gt;$string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'O:8:"User":1:{s:4:"name";s:6:"Denzyl";}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;unserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$string&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;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;/// Output: Denzyl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;The same functionalities also apply to unserializing. But this time, the two methods are &lt;code&gt;__unserialize()&lt;/code&gt; and &lt;code&gt;__wakeup().&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  But why is it a bad idea?
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;unserialize&lt;/code&gt; without knowing it can lead to remote code execution. That's why they say never to trust input.&lt;br&gt;&lt;br&gt;
Let's say you are lazy and you trust a random input, and you concatenate to the serialized object so you can&lt;br&gt;&lt;br&gt;
change a value inside the object. BOOM, you can be hacked.&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="nv"&gt;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="nv"&gt;$serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'O:8:"User":1:{s:4:"name";s:6:"'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'";}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter fullscreen mode Exit fullscreen mode&lt;/p&gt;

&lt;p&gt;I won't explain how to write an exploit for something like this. Some tools can automatically generate a payload for you, and you can call yourself a script kiddie(we all start somewhere). The one I know is &lt;a href="https://github.com/ambionics/phpggc" rel="noopener noreferrer"&gt;PHPGGC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To understand the exploit, you can read the OWASP &lt;a href="https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
If you didn't know this before, also read the rest of the OWASP &lt;a href="https://owasp.org/www-community/vulnerabilities/" rel="noopener noreferrer"&gt;articles&lt;/a&gt; about vulnerabilities&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I know I haven't explained how to write an exploit. I don't think I can do a better job than the articles on the internet. But now you know this, and you can do your research.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to prevent being exploited?
&lt;/h3&gt;

&lt;p&gt;Why would you want to use this? I do not know; I haven't been programming long enough(~15 years) to have the opportunity to solve a problem using serialize/unserialize.&lt;br&gt;&lt;br&gt;
My solution is too drastic. The simple answer is. &lt;strong&gt;Don't&lt;/strong&gt; use it in my PHP projects.&lt;/p&gt;

&lt;p&gt;This article is part of a series of articles in my journey of writing a &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;static analysis&lt;/a&gt; tool for PHP that can scan massive projects in a couple of minutes/seconds. And look for rules&lt;br&gt;&lt;br&gt;
that the developers want to have in their projects. At the time of writing this article, I'm working on a rule to stop&lt;br&gt;&lt;br&gt;
people from using &lt;code&gt;unserialize&lt;/code&gt;, and it should be ready for the next release. Follow the &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;project&lt;/a&gt; so that you will get notified when&lt;br&gt;&lt;br&gt;
I decided to write even more rules.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/why-is-unserializing-an-object-in-php-a-bad-idea-5sbeg?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication-footer" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>From Throw-and-Pray to Predictable: Introducing Box, a Rust‑Inspired Result Type for PHP 8.1+</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sun, 06 Sep 2026 13:59:15 +0000</pubDate>
      <link>https://dev.to/denzyldick/from-throw-and-pray-to-predictable-introducing-box-a-rust-inspired-result-type-for-php-81-kfh</link>
      <guid>https://dev.to/denzyldick/from-throw-and-pray-to-predictable-introducing-box-a-rust-inspired-result-type-for-php-81-kfh</guid>
      <description>&lt;p&gt;Most PHP developers are stuck in a cycle of "throw-and-pray" error handling.&lt;/p&gt;

&lt;p&gt;You write a method, it implicitly throws an exception somewhere deep in the stack, and you pray a try/catch block catches it before it crashes the application. The method signature tells you nothing. It’s a silent guessing game.&lt;/p&gt;

&lt;p&gt;The alternative? Returning null or false, which leads to silent failures and a total loss of error context.&lt;/p&gt;

&lt;p&gt;To solve this in my own production environments, I built Box—a modern, type-safe functional error handling library for PHP 8.1+ heavily inspired by Rust's Result type.&lt;/p&gt;

&lt;p&gt;The core philosophy is simple: If an error can happen, the codebase should force the caller to acknowledge it.&lt;/p&gt;

&lt;p&gt;By decoupling the fallible domain logic via an Item interface and passing it through Box::put(), it translates imperative throwing code into an immutable, type-safe pipeline (Result).&lt;/p&gt;

&lt;p&gt;Why this approach changes the game for complex PHP backends:&lt;br&gt;&lt;br&gt;
Honest API Contracts: Using PhpDoc generics, your IDE and static analyzers (PHPStan/Psalm) force you to handle both the Ok and Error tracks. No more forgotten catches.&lt;/p&gt;

&lt;p&gt;Railway-Oriented Programming: It introduces clean, declarative method chaining (map, flatMap, recover, tapOk) so your data pipelines remain pure and highly readable.&lt;/p&gt;

&lt;p&gt;Batch Operations Built-In: It natively handles combining independent results, short-circuiting sequential dependencies, or partitioning bulk successes/failures without messy nested if statements.&lt;br&gt;&lt;br&gt;
I’ve made the repository completely public and open-source. If you are trying to scale modern PHP systems safely, take a look at the architecture and the README documentation:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/denzyldick/box" rel="noopener noreferrer"&gt;https://github.com/denzyldick/box&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How is your team handling strict error boundaries and exception isolation in high-load PHP applications? Let's discuss below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 TL;DR &amp;amp; Key Takeaways:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
**TL;DR:** PHP’s common “throw‑and‑pray” pattern hides errors and forces developers to guess exception handling, while returning null/false discards context. The open‑source **Box** library (PHP 8.1+) introduces a Rust‑inspired &lt;code&gt;Result\&lt;/code&gt; type that enforces compile‑time error acknowledgment, enabling clean, type‑safe pipelines and built‑in batch handling.  &lt;/p&gt;

&lt;p&gt;- **Honest API contracts:** PhpDoc generics let IDEs and static analysers require explicit handling of both success (&lt;code&gt;Ok\&lt;/code&gt;) and failure (&lt;code&gt;Error\&lt;/code&gt;) paths.&lt;br&gt;&lt;br&gt;
- **Railway‑oriented programming:** Immutable method chaining (&lt;code&gt;map\&lt;/code&gt;, &lt;code&gt;flatMap\&lt;/code&gt;, &lt;code&gt;recover\&lt;/code&gt;, &lt;code&gt;tapOk\&lt;/code&gt;) keeps data pipelines pure and readable.&lt;br&gt;&lt;br&gt;
- **Built‑in batch operations:** Native support for combining, short‑circuiting, and partitioning multiple results eliminates tangled nested conditionals.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/how-i-handle-my-errors-in-php-9yg93?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication-footer" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>symfony</category>
      <category>backend</category>
    </item>
    <item>
      <title>Building Siegu: A Local-First, P2P Google Photos Alternative in Rust &amp; Tauri</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sun, 06 Sep 2026 13:57:18 +0000</pubDate>
      <link>https://dev.to/denzyldick/building-siegu-a-local-first-p2p-google-photos-alternative-in-rust-tauri-56cp</link>
      <guid>https://dev.to/denzyldick/building-siegu-a-local-first-p2p-google-photos-alternative-in-rust-tauri-56cp</guid>
      <description>&lt;p&gt;I can't remember exactly when I started using Google Photos, but it’s been my go-to for a long time, probably since it was released. It is one of the most useful pieces of software I've ever used. However, in 2021, I became a father, which completely changed how I used it and made me question if I could keep relying on it. I started taking far more pictures and videos than I ever had before. A couple of months later, the sheer volume of media forced me to start paying for extra Google Photos storage.&lt;/p&gt;

&lt;p&gt;Around that time, I questioned why I was paying to store pictures I took myself. I started digging around for another solution to avoid those storage fees. I realized that across all my devices in the office (Android phones, tablets, a laptop, and a desktop), I already had plenty of storage. Each device had a minimum of 500GB, which was more than enough to hold all my media. I also had a DigitalOcean droplet used for random coding projects, but going that route meant paying for another server and dealing with a complex setup, so I skipped it.&lt;/p&gt;

&lt;p&gt;Next, I looked into alternatives like rsync, Immich, Syncthing, and similar tools. Immich is great software with a solid UI, but the rest were still too complicated for my needs. I wanted the exact same "install and forget" experience that Google Photos provides. Setting those up took too much time, and I didn't love the UI/UX on most of them. If I had enough coffee and time, I could probably have made them work, but where is the fun in that? I decided to build my own solution so I could do whatever I wanted.&lt;/p&gt;

&lt;p&gt;Here is what I wanted to accomplish without spending money or waiting too long:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Sync all files across all my devices.&lt;/li&gt;
&lt;li&gt;  Analyze all the files to extract useful information.&lt;/li&gt;
&lt;li&gt;  Provide a simple UI that even a five-year-old could use.&lt;/li&gt;
&lt;li&gt;  Ensure photo searches are fast.&lt;/li&gt;
&lt;li&gt;  Keep the user experience non-technical.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google Photos sometimes takes too long to load old memories, but its best feature is how easy it is to find a picture based on a location or person. I wanted that exact same functionality.&lt;/p&gt;

&lt;p&gt;So, I grabbed my coffee, put on my geeky hat, and started researching how to build this. This was before ChatGPT, so I had to do it the old-fashioned way by reading articles and extracting the bits and bytes.&lt;/p&gt;

&lt;p&gt;After a couple of brainstorming sessions, I nailed down my tech stack. Naturally, I chose Rust because it seemed cool. I also came across Tauri right around the time their team started the project. For syncing, I discovered the WebRTC protocol. It seemed perfect for allowing devices to communicate without a centralized server.&lt;/p&gt;

&lt;p&gt;I eventually realized that wasn't entirely true; you still need a centralized way (a signaling server) for devices to find each other. I tried using QR codes to solve this, but it was too complicated. Not every device has a camera, meaning users would eventually have to enter IP addresses manually, which violated my "non-technical" rule.&lt;/p&gt;

&lt;p&gt;Around that time, I figured out how to extract metadata from pictures and used &lt;code&gt;jwalk&lt;/code&gt; to recursively walk directories. My proof of concept was working.&lt;/p&gt;

&lt;p&gt;Then I hit a roadblock: Tauri didn't support mobile yet. I waited for months. One random day, I saw an article about running a Tauri application on mobile. I grabbed my laptop, jumped in, and actually got an app running on my phone. Official mobile support wasn't fully there yet, so I had to wait again until the Tauri team officially released it, which they eventually did.&lt;/p&gt;

&lt;p&gt;When that day came, I started working on the project on and off in my free time. Things moved slowly. WebRTC was complicated, and extracting information from the pictures was a headache. But then the software industry shifted, and AI tools arrived. After initially feeling like I was cheating myself by using AI, I got over it once I saw how fast I was solving problems and creating things.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: I only used Gemini to fix this article, not to generate it 🚀)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I decided the QR-code signaling method was definitely too complex. Instead, I discovered mDNS, which allowed me to find other devices on my local network without overcomplicating things. It was difficult to implement, but I got it working.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgzx3eqll7ytvrpcytlc9.png"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc5kjp6sy1jl4yb6t8iyr.png" alt="Siegu Linked Devices" width="799" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That left one problem: what if I'm not at home? I realized I still needed a signaling server. I decided to vibe-code a separate project in Go, making it easy to host on my own server using a simple Docker Compose setup. I originally wrote it in Rust, but I wanted to give myself the opportunity to use Go after a couple of years. I currently use OpenCode with the Big Pickle model, and it gets the job done.&lt;/p&gt;

&lt;p&gt;Next came the complicated part: picking the right models to analyze all my media. I ended up building a pipeline to run several distinct local models against every file. As of right now, Siegu handles &lt;strong&gt;Smart Search&lt;/strong&gt; (finding objects and scenes), &lt;strong&gt;Face Grouping&lt;/strong&gt;, and a &lt;strong&gt;Text Finder&lt;/strong&gt; for things like receipts. The best part? It all runs locally. The Face Grouping model is only 2MB, and the Smart Search model is 350MB, meaning it stays entirely on-device.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F94mpfc3cl0o5277vypzi.png"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkhje09nydsaa427f44bs.png" alt="Siegu AI Models" width="799" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My only current issue is my hardware. I use a ThinkPad E14, which defaults to the CPU instead of the GPU. I know about OpenVINO, but I don't fully understand it yet. I'm going to try to fix this before the 1.0 release. It takes around 40+ hours to analyze about 4,000 pictures and videos that I extracted from a Google Takeout export. And I didn't even extract everything yet, so when I'm done, I will probably need to buy new hardware.&lt;/p&gt;

&lt;p&gt;If you're still reading, I know I'm just yapping now. But I got it to work, and the day I no longer have to pay to look at my own pictures is coming soon.&lt;/p&gt;

&lt;p&gt;The project is called &lt;em&gt;Siegu&lt;/em&gt;, which means "blind" in Papiamentu, the language of Curaçao (that tiny island in the World Cup). Some people will point out that it won't work behind certain firewalls or without a TURN server, but if that's your situation, then you just can't use it. That sounds like a "you" problem.&lt;/p&gt;

&lt;p&gt;The project is open source and available on GitHub: &lt;a href="https://github.com/denzyldick/siegu" rel="noopener noreferrer"&gt;https://github.com/denzyldick/siegu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My next article will be for the 1.0 release. Right now, it's just me, Big Pickle, and sometimes Codex building this, so it takes time.&lt;/p&gt;

&lt;p&gt;I also expect a lot of issues with this. I only have a Linux box and an Android device, but I want to support everything eventually. So when you fork it, please open GitHub issues for anything that isn't working—because it probably won't run without a few problems! If you are interested, you know what to do: just fork it! :D&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/building-siegu-a-local-first-p2p-google-photos-alternative-in-rust-tauri-nunx8?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication-footer" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>webrtc</category>
      <category>sqlite</category>
    </item>
    <item>
      <title>Finding "Duplicates Through Time"</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sun, 06 Sep 2026 13:56:11 +0000</pubDate>
      <link>https://dev.to/denzyldick/finding-duplicates-through-time-2ajj</link>
      <guid>https://dev.to/denzyldick/finding-duplicates-through-time-2ajj</guid>
      <description>&lt;h2&gt;
  
  
  Finding "Duplicates Through Time": How I Cleaned Up 300GB of Photos Without Losing Quality
&lt;/h2&gt;

&lt;p&gt;Lately, I have been playing around with my personal photo and video library (around 300GB of files, spanning 10+ years of memories). I had a specific type of problem: I needed to save space on my SSD, but I did not want to pay any third-party cloud provider for extra storage.&lt;/p&gt;

&lt;p&gt;To make things trickier, I was traveling in a remote location without any electronics stores nearby. Buying an external hard drive was out of the question. I had my laptop, tablet, and smartphone. Together, they had enough cumulative storage, but my laptop drive was suffocating.&lt;/p&gt;

&lt;p&gt;What if I just made the library smaller?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compression Route (and a Nod to Middle-Out)
&lt;/h2&gt;

&lt;p&gt;There are different ways to make files smaller, and the most obvious route is compression.&lt;/p&gt;

&lt;p&gt;Whenever compression comes up in software engineering, I am always surprised by how many developers have not seen HBO's &lt;em&gt;Silicon Valley&lt;/em&gt;. If you have not watched it yet, take a break and go check it out. Great show.&lt;/p&gt;

&lt;p&gt;In the real world, though, lossy re-encoding means sacrificing quality. When dealing with a decade of personal memories, heavy compression feels like the wrong compromise. You do not want high-resolution vacation shots turning into pixelated JPEGs just to save a few gigabytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: Deleting Big Files (The Easy Part)
&lt;/h2&gt;

&lt;p&gt;My next thought was simple: prune the clutter and remove the massive files.&lt;/p&gt;

&lt;p&gt;Finding large video files was easy enough. A quick shell command or custom script sorted everything by size, allowing me to offload old movies and raw video dumps.&lt;/p&gt;

&lt;p&gt;That gave me some breathing room, but it hit a wall quickly. Depending on how your library is structured, video pruning only works up to a certain point. The core of my storage problem was thousands of individual photographs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Aha!" Moment: Burst Mode &amp;amp; Over-Shooting
&lt;/h2&gt;

&lt;p&gt;A couple of days later, a friend asked me to send her a picture we took when we visited the Empire State Building in New York.&lt;/p&gt;

&lt;p&gt;When I opened my library, I realized something: she asked for one picture, but I had taken seven nearly identical shots.&lt;/p&gt;

&lt;p&gt;I always do this on holiday so people can choose the best angle or expression. A quick burst of 5 to 10 photos, just to capture one good moment.&lt;/p&gt;

&lt;p&gt;That was the lightbulb moment:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How can I programmatically find all the "short burst" photos across 10+ years of media?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Or phrased better: &lt;em&gt;How do I detect duplicates through time?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Siegu
&lt;/h2&gt;

&lt;p&gt;This problem led me to start building &lt;strong&gt;siegu&lt;/strong&gt;, a local tool designed to tackle time-clustered, visually similar photos across massive personal libraries.&lt;/p&gt;

&lt;p&gt;Instead of looking for exact byte-for-byte duplicates (which standard deduplication tools do via MD5 or SHA256 hashes), &lt;code&gt;siegu&lt;/code&gt; approaches the problem using two dimensions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Temporal Proximity (Time Windows):&lt;/strong&gt; Grouping photos shot within seconds or milliseconds of each other using EXIF metadata (&lt;code&gt;DateTimeOriginal&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Visual Similarity (Perceptual Hashing):&lt;/strong&gt; Comparing photos within those candidate windows using perceptual hashes (like &lt;code&gt;pHash&lt;/code&gt; or &lt;code&gt;dHash&lt;/code&gt;) to see if they depict the same scene, regardless of minor lighting changes or slight hand movements.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By combining timestamps with perceptual hashing, you do not waste CPU cycles comparing a picture from 2014 in New York with a picture from 2022 in Tokyo. You only analyze candidate groups that were actually taken in short bursts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;In Part 2, I will dive deep under the hood: breaking down the Rust implementation, showing how &lt;code&gt;siegu&lt;/code&gt; extracts EXIF metadata concurrently, and walking through the exact perceptual hashing algorithm used to flag burst duplicates.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What is &lt;a href="https://github.com/denzyldick/siegu" rel="noopener noreferrer"&gt;Siegu&lt;/a&gt;?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/finding-duplicates-through-time-a0b03?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication-footer" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Finding "Duplicates Through Time"</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sun, 06 Sep 2026 01:47:18 +0000</pubDate>
      <link>https://dev.to/denzyldick/finding-duplicates-through-time-2c56</link>
      <guid>https://dev.to/denzyldick/finding-duplicates-through-time-2c56</guid>
      <description>&lt;h2&gt;
  
  
  Finding "Duplicates Through Time": How I Cleaned Up 300GB of Photos Without Losing Quality
&lt;/h2&gt;

&lt;p&gt;Lately, I have been playing around with my personal photo and video library (around 300GB of files, spanning 10+ years of memories). I had a specific type of problem: I needed to save space on my SSD, but I did not want to pay any third-party cloud provider for extra storage.&lt;/p&gt;

&lt;p&gt;To make things trickier, I was traveling in a remote location without any electronics stores nearby. Buying an external hard drive was out of the question. I had my laptop, tablet, and smartphone. Together, they had enough cumulative storage, but my laptop drive was suffocating.&lt;/p&gt;

&lt;p&gt;What if I just made the library smaller?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compression Route (and a Nod to Middle-Out)
&lt;/h2&gt;

&lt;p&gt;There are different ways to make files smaller, and the most obvious route is compression.&lt;/p&gt;

&lt;p&gt;Whenever compression comes up in software engineering, I am always surprised by how many developers have not seen HBO's &lt;em&gt;Silicon Valley&lt;/em&gt;. If you have not watched it yet, take a break and go check it out. Great show.&lt;/p&gt;

&lt;p&gt;In the real world, though, lossy re-encoding means sacrificing quality. When dealing with a decade of personal memories, heavy compression feels like the wrong compromise. You do not want high-resolution vacation shots turning into pixelated JPEGs just to save a few gigabytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: Deleting Big Files (The Easy Part)
&lt;/h2&gt;

&lt;p&gt;My next thought was simple: prune the clutter and remove the massive files.&lt;/p&gt;

&lt;p&gt;Finding large video files was easy enough. A quick shell command or custom script sorted everything by size, allowing me to offload old movies and raw video dumps.&lt;/p&gt;

&lt;p&gt;That gave me some breathing room, but it hit a wall quickly. Depending on how your library is structured, video pruning only works up to a certain point. The core of my storage problem was thousands of individual photographs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Aha!" Moment: Burst Mode &amp;amp; Over-Shooting
&lt;/h2&gt;

&lt;p&gt;A couple of days later, a friend asked me to send her a picture we took when we visited the Empire State Building in New York.&lt;/p&gt;

&lt;p&gt;When I opened my library, I realized something: she asked for one picture, but I had taken seven nearly identical shots.&lt;/p&gt;

&lt;p&gt;I always do this on holiday so people can choose the best angle or expression. A quick burst of 5 to 10 photos, just to capture one good moment.&lt;/p&gt;

&lt;p&gt;That was the lightbulb moment:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How can I programmatically find all the "short burst" photos across 10+ years of media?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Or phrased better: &lt;em&gt;How do I detect duplicates through time?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Siegu
&lt;/h2&gt;

&lt;p&gt;This problem led me to start building &lt;strong&gt;siegu&lt;/strong&gt;, a local tool designed to tackle time-clustered, visually similar photos across massive personal libraries.&lt;/p&gt;

&lt;p&gt;Instead of looking for exact byte-for-byte duplicates (which standard deduplication tools do via MD5 or SHA256 hashes), &lt;code&gt;siegu&lt;/code&gt; approaches the problem using two dimensions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Temporal Proximity (Time Windows):&lt;/strong&gt; Grouping photos shot within seconds or milliseconds of each other using EXIF metadata (&lt;code&gt;DateTimeOriginal&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual Similarity (Perceptual Hashing):&lt;/strong&gt; Comparing photos within those candidate windows using perceptual hashes (like &lt;code&gt;pHash&lt;/code&gt; or &lt;code&gt;dHash&lt;/code&gt;) to see if they depict the same scene, regardless of minor lighting changes or slight hand movements.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By combining timestamps with perceptual hashing, you do not waste CPU cycles comparing a picture from 2014 in New York with a picture from 2022 in Tokyo. You only analyze candidate groups that were actually taken in short bursts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;In Part 2, I will dive deep under the hood: breaking down the Rust implementation, showing how &lt;code&gt;siegu&lt;/code&gt; extracts EXIF metadata concurrently, and walking through the exact perceptual hashing algorithm used to flag burst duplicates.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What is &lt;a href="https://github.com/denzyldick/siegu" rel="noopener noreferrer"&gt;Siegu&lt;/a&gt;?&lt;/p&gt;

</description>
      <category>software</category>
      <category>tools</category>
    </item>
    <item>
      <title>Building Siegu: A Local-First, P2P Google Photos Alternative in Rust &amp; Tauri</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Thu, 30 Jul 2026 08:43:05 +0000</pubDate>
      <link>https://dev.to/denzyldick/how-i-replaced-google-photos-44nb</link>
      <guid>https://dev.to/denzyldick/how-i-replaced-google-photos-44nb</guid>
      <description>&lt;p&gt;I can't remember exactly when I started using Google Photos, but it’s been my go-to for a long time, probably since it was released. It is one of the most useful pieces of software I've ever used. However, in 2021, I became a father, which completely changed how I used it and made me question if I could keep relying on it. I started taking far more pictures and videos than I ever had before. A couple of months later, the sheer volume of media forced me to start paying for extra Google Photos storage.&lt;/p&gt;

&lt;p&gt;Around that time, I questioned why I was paying to store pictures I took myself. I started digging around for another solution to avoid those storage fees. I realized that across all my devices in the office (Android phones, tablets, a laptop, and a desktop), I already had plenty of storage. Each device had a minimum of 500GB, which was more than enough to hold all my media. I also had a DigitalOcean droplet used for random coding projects, but going that route meant paying for another server and dealing with a complex setup, so I skipped it.&lt;/p&gt;

&lt;p&gt;Next, I looked into alternatives like rsync, Immich, Syncthing, and similar tools. Immich is great software with a solid UI, but the rest were still too complicated for my needs. I wanted the exact same "install and forget" experience that Google Photos provides. Setting those up took too much time, and I didn't love the UI/UX on most of them. If I had enough coffee and time, I could probably have made them work, but where is the fun in that? I decided to build my own solution so I could do whatever I wanted.&lt;/p&gt;

&lt;p&gt;Here is what I wanted to accomplish without spending money or waiting too long:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Sync all files across all my devices.&lt;/li&gt;
&lt;li&gt;  Analyze all the files to extract useful information.&lt;/li&gt;
&lt;li&gt;  Provide a simple UI that even a five-year-old could use.&lt;/li&gt;
&lt;li&gt;  Ensure photo searches are fast.&lt;/li&gt;
&lt;li&gt;  Keep the user experience non-technical.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google Photos sometimes takes too long to load old memories, but its best feature is how easy it is to find a picture based on a location or person. I wanted that exact same functionality.&lt;/p&gt;

&lt;p&gt;So, I grabbed my coffee, put on my geeky hat, and started researching how to build this. This was before ChatGPT, so I had to do it the old-fashioned way by reading articles and extracting the bits and bytes.&lt;/p&gt;

&lt;p&gt;After a couple of brainstorming sessions, I nailed down my tech stack. Naturally, I chose Rust because it seemed cool. I also came across Tauri right around the time their team started the project. For syncing, I discovered the WebRTC protocol. It seemed perfect for allowing devices to communicate without a centralized server.&lt;/p&gt;

&lt;p&gt;I eventually realized that wasn't entirely true; you still need a centralized way (a signaling server) for devices to find each other. I tried using QR codes to solve this, but it was too complicated. Not every device has a camera, meaning users would eventually have to enter IP addresses manually, which violated my "non-technical" rule.&lt;/p&gt;

&lt;p&gt;Around that time, I figured out how to extract metadata from pictures and used &lt;code&gt;jwalk&lt;/code&gt; to recursively walk directories. My proof of concept was working.&lt;/p&gt;

&lt;p&gt;Then I hit a roadblock: Tauri didn't support mobile yet. I waited for months. One random day, I saw an article about running a Tauri application on mobile. I grabbed my laptop, jumped in, and actually got an app running on my phone. Official mobile support wasn't fully there yet, so I had to wait again until the Tauri team officially released it, which they eventually did.&lt;/p&gt;

&lt;p&gt;When that day came, I started working on the project on and off in my free time. Things moved slowly. WebRTC was complicated, and extracting information from the pictures was a headache. But then the software industry shifted, and AI tools arrived. After initially feeling like I was cheating myself by using AI, I got over it once I saw how fast I was solving problems and creating things.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: I only used Gemini to fix this article, not to generate it 🚀)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I decided the QR-code signaling method was definitely too complex. Instead, I discovered mDNS, which allowed me to find other devices on my local network without overcomplicating things. It was difficult to implement, but I got it working.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgzx3eqll7ytvrpcytlc9.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgzx3eqll7ytvrpcytlc9.png" alt="Siegu Linked Devices" width="799" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That left one problem: what if I'm not at home? I realized I still needed a signaling server. I decided to vibe-code a separate project in Go, making it easy to host on my own server using a simple Docker Compose setup. I originally wrote it in Rust, but I wanted to give myself the opportunity to use Go after a couple of years. I currently use OpenCode with the Big Pickle model, and it gets the job done.&lt;/p&gt;

&lt;p&gt;Next came the complicated part: picking the right models to analyze all my media. I ended up building a pipeline to run several distinct local models against every file. As of right now, Siegu handles &lt;strong&gt;Smart Search&lt;/strong&gt; (finding objects and scenes), &lt;strong&gt;Face Grouping&lt;/strong&gt;, and a &lt;strong&gt;Text Finder&lt;/strong&gt; for things like receipts. The best part? It all runs locally. The Face Grouping model is only 2MB, and the Smart Search model is 350MB, meaning it stays entirely on-device.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F94mpfc3cl0o5277vypzi.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F94mpfc3cl0o5277vypzi.png" alt="Siegu AI Models" width="799" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My only current issue is my hardware. I use a ThinkPad E14, which defaults to the CPU instead of the GPU. I know about OpenVINO, but I don't fully understand it yet. I'm going to try to fix this before the 1.0 release. It takes around 40+ hours to analyze about 4,000 pictures and videos that I extracted from a Google Takeout export. And I didn't even extract everything yet, so when I'm done, I will probably need to buy new hardware. &lt;/p&gt;

&lt;p&gt;If you're still reading, I know I'm just yapping now. But I got it to work, and the day I no longer have to pay to look at my own pictures is coming soon.&lt;/p&gt;

&lt;p&gt;The project is called &lt;em&gt;Siegu&lt;/em&gt;, which means "blind" in Papiamentu, the language of Curaçao (that tiny island in the World Cup). Some people will point out that it won't work behind certain firewalls or without a TURN server, but if that's your situation, then you just can't use it. That sounds like a "you" problem.&lt;/p&gt;

&lt;p&gt;The project is open source and available on GitHub: &lt;a href="https://github.com/denzyldick/siegu" rel="noopener noreferrer"&gt;https://github.com/denzyldick/siegu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My next article will be for the 1.0 release. Right now, it's just me, Big Pickle, and sometimes Codex building this, so it takes time. &lt;/p&gt;

&lt;p&gt;I also expect a lot of issues with this. I only have a Linux box and an Android device, but I want to support everything eventually. So when you fork it, please open GitHub issues for anything that isn't working—because it probably won't run without a few problems! If you are interested, you know what to do: just fork it! :D&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>webrtc</category>
      <category>sqlite</category>
    </item>
    <item>
      <title>How I handle my errors in PHP</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Mon, 25 May 2026 03:19:19 +0000</pubDate>
      <link>https://dev.to/denzyldick/how-i-handle-my-errors-in-php-4j31</link>
      <guid>https://dev.to/denzyldick/how-i-handle-my-errors-in-php-4j31</guid>
      <description>&lt;p&gt;Most PHP developers are stuck in a cycle of "throw-and-pray" error handling.&lt;/p&gt;

&lt;p&gt;You write a method, it implicitly throws an exception somewhere deep in the stack, and you pray a try/catch block catches it before it crashes the application. The method signature tells you nothing. It’s a silent guessing game.&lt;/p&gt;

&lt;p&gt;The alternative? Returning null or false, which leads to silent failures and a total loss of error context.&lt;/p&gt;

&lt;p&gt;To solve this in my own production environments, I built Box—a modern, type-safe functional error handling library for PHP 8.1+ heavily inspired by Rust's Result type.&lt;/p&gt;

&lt;p&gt;The core philosophy is simple: If an error can happen, the codebase should force the caller to acknowledge it.&lt;/p&gt;

&lt;p&gt;By decoupling the fallible domain logic via an Item interface and passing it through Box::put(), it translates imperative throwing code into an immutable, type-safe pipeline (Result).&lt;/p&gt;

&lt;p&gt;Why this approach changes the game for complex PHP backends:&lt;br&gt;
Honest API Contracts: Using PhpDoc generics, your IDE and static analyzers (PHPStan/Psalm) force you to handle both the Ok and Error tracks. No more forgotten catches.&lt;/p&gt;

&lt;p&gt;Railway-Oriented Programming: It introduces clean, declarative method chaining (map, flatMap, recover, tapOk) so your data pipelines remain pure and highly readable.&lt;/p&gt;

&lt;p&gt;Batch Operations Built-In: It natively handles combining independent results, short-circuiting sequential dependencies, or partitioning bulk successes/failures without messy nested if statements.&lt;br&gt;
I’ve made the repository completely public and open-source. If you are trying to scale modern PHP systems safely, take a look at the architecture and the README documentation:&lt;br&gt;
👉 &lt;a href="https://github.com/denzyldick/box" rel="noopener noreferrer"&gt;https://github.com/denzyldick/box&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How is your team handling strict error boundaries and exception isolation in high-load PHP applications? Let's discuss below.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>symfony</category>
      <category>backend</category>
    </item>
    <item>
      <title>Why is unserializing an object in PHP a bad idea?</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Thu, 18 Jul 2024 20:39:42 +0000</pubDate>
      <link>https://dev.to/denzyldick/why-is-unserializing-an-object-in-php-a-bad-idea-3odl</link>
      <guid>https://dev.to/denzyldick/why-is-unserializing-an-object-in-php-a-bad-idea-3odl</guid>
      <description>&lt;p&gt;Serializing in PHP is a way of converting a PHP object into a string. This string can be used in various ways, such as storing it in a database or passing it to another function. The PHP documentation says this is handy when passing PHP values around without losing their type and structure. But I have never had that problem before. Maybe I’m not seeing 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="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nv"&gt;$test&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;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$test&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="s2"&gt;"Denzyl"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$test&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;/// Output: O:4:"User":1:{s:4:"name";s:6:"Denzyl";}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, let's digest the string. The &lt;code&gt;o&lt;/code&gt; stands for Object, and the following number is the length of the object's name. The two letters  &lt;code&gt;s&lt;/code&gt; stand for string and the length of the string's name.&lt;br&gt;&lt;br&gt;
When you need to convert the string back into PHP, call the &lt;code&gt;unserialize&lt;/code&gt; function and pass the string as a parameter.&lt;/p&gt;

&lt;p&gt;When serializing an object, two methods are automagically being called. &lt;code&gt;__serialize()&lt;/code&gt; &amp;amp; &lt;code&gt;__sleep()&lt;/code&gt;. This will allow the class author to do something before converting the object into a string.&lt;br&gt;
That is straight to the point. But for now, let’s focus on unserializing the string. This means converting the string into a real PHP object that can be later used at runtime in your PHP code.&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="nv"&gt;$string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'O:8:"User":1:{s:4:"name";s:6:"Denzyl";}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;unserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$string&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;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;/// Output: Denzyl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same functionalities also apply to unserializing. But this time, the two methods are &lt;code&gt;__unserialize()&lt;/code&gt; and &lt;code&gt;__wakeup().&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  But why is it a bad idea?
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;unserialize&lt;/code&gt; without knowing it can lead to remote code execution. That's why they say never to trust input. &lt;br&gt;
Let's say you are lazy and you trust a random input, and you concatenate to the serialized object so you can &lt;br&gt;
change a value inside the object. BOOM, you can be hacked.&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="nv"&gt;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nv"&gt;$serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'O:8:"User":1:{s:4:"name";s:6:"'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'";}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I won't explain how to write an exploit for something like this. Some tools can automatically generate a payload for you, and you can call yourself a script kiddie(we all start somewhere). The one I know is &lt;a href="https://github.com/ambionics/phpggc" rel="noopener noreferrer"&gt;PHPGGC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To understand the exploit, you can read the OWASP &lt;a href="https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection" rel="noopener noreferrer"&gt;article&lt;/a&gt;. &lt;br&gt;
If you didn't know this before, also read the rest of the OWASP &lt;a href="https://owasp.org/www-community/vulnerabilities/" rel="noopener noreferrer"&gt;articles&lt;/a&gt; about vulnerabilities&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I know I haven't explained how to write an exploit. I don't think I can do a better job than the articles on the internet. But now you know this, and you can do your research.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to prevent being exploited?
&lt;/h3&gt;

&lt;p&gt;Why would you want to use this? I do not know; I haven't been programming long enough(~15 years) to have the opportunity to solve a problem using serialize/unserialize. &lt;br&gt;
My solution is too drastic. The simple answer is. &lt;strong&gt;Don't&lt;/strong&gt; use it in my PHP projects. &lt;/p&gt;

&lt;p&gt;This article is part of a series of articles in my journey of writing a &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;static analysis&lt;/a&gt; tool for PHP that can scan massive projects in a couple of minutes/seconds. And look for rules&lt;br&gt;
that the developers want to have in their projects. At the time of writing this article, I'm working on a rule to stop &lt;br&gt;
people from using &lt;code&gt;unserialize&lt;/code&gt;, and it should be ready for the next release. Follow the &lt;a href="https://github.com/denzyldick/phanalist" rel="noopener noreferrer"&gt;project&lt;/a&gt; so that you will get notified when&lt;br&gt;
I decided to write even more rules. &lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Improve your CI output.</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sat, 18 May 2024 20:10:54 +0000</pubDate>
      <link>https://dev.to/denzyldick/improve-your-ci-output-2eg</link>
      <guid>https://dev.to/denzyldick/improve-your-ci-output-2eg</guid>
      <description>&lt;p&gt;Have you ever been in a situation where you made a PR or MR and waited for a couple of seconds for the output of the CI pipeline? But something went wrong, and you can't see the issue in the blink of an eye. And you get annoyed that you must read a few logs to discover the problem? &lt;/p&gt;

&lt;p&gt;It's a scenario that many of us have likely encountered at some point.&lt;/p&gt;

&lt;p&gt;This article teaches how to improve your CI output. I will use Github.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is part of a series about a static analysis tool I've worked on for over a year. It's called &lt;a href="https://github.com/denzyldick/phanalist"&gt;Phanalist&lt;/a&gt;. Please check it out and hit the star button. Thank you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How can I improve the CI output in Github? When running your CI tools, you probably output everything to STDOUT and view the content in the log viewer.&lt;/p&gt;

&lt;p&gt;Something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jkmm3hl8flza7socosu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jkmm3hl8flza7socosu.png" alt="Image description" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output format text in Phanalist is not so bad. It's readable because of the table layout. But why stop there? &lt;/p&gt;

&lt;p&gt;Microsoft is not so evil anymore, and Github has solved that problem I've already. What we will be using is what they call &lt;code&gt;SARIF&lt;/code&gt;. It stands&lt;br&gt;
for Static Analysis Results Interchange Format. It's a specification for understanding the output of static analysis tools. That is how the tools can display information in the code scanning section under the security tab on a repository. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzibtgelhhm0kyx8x1yys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzibtgelhhm0kyx8x1yys.png" alt="Image description" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Phanalist to have a chance to be adopted by more people, this is a must feature that should be implemented first. Then, I can focus on adding more rules to the tool. &lt;/p&gt;

&lt;p&gt;For context, &lt;a href="https://gitub.com/denzyldick/phanalist"&gt;Phanalist&lt;/a&gt; consists of rules implemented by the contributors. Every rule has a detailed explanation of what you are doing wrong and guides you in the right direction so you can fix it. &lt;/p&gt;

&lt;p&gt;The tools under the code scanning section use a Github action called &lt;code&gt;github/codeql-action/upload-sarif&lt;/code&gt;. This action uploads a &lt;code&gt;.sarif&lt;/code&gt; file to GitHub. Remember that you will need the right permissions to upload a file from the Github workflow. After uploading, Github will validate the file's content, and if there are any errors, they will be displayed in the logs. If everything goes well, you will have more issues to fix under the security tab. &lt;/p&gt;

&lt;p&gt;The tools you use should have a &lt;code&gt;Sarif&lt;/code&gt; output. At the time of writing, I do not know if the popular static analysis tools in the PHP ecosystem support Sarif, but if not, you can help them with that. &lt;/p&gt;

&lt;p&gt;But &lt;a href="https://github.com/denzyldick/phanalist"&gt;Phanalist&lt;/a&gt; supports that format. It can output information in three formats: &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;, and &lt;code&gt;sarif&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;phanalist &lt;span class="nt"&gt;--src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--output-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sarif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://json.schemastore.org/sarif-2.1.0-rtm.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"driver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phanalist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"informationUri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/denzyldick/phanalist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e0009"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"shortDescription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Method is too complex"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phanalist"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"artifacts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/complex.php"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Method is too complex."&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"locations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"physicalLocation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"artifactLocation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/complex.php"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"startLine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"startColumn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ruleId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"no-unused-vars"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ruleIndex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I won't explain Sarif in detail in this article; the people behind it have already done an excellent job.&lt;/p&gt;

&lt;p&gt;The next step is to upload this output to Github using the &lt;code&gt;github/codeql-action/upload-sarif&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sarif&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;upload-sarif&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Rust toolchain&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions-rs/toolchain@v1.0.6&lt;/span&gt; &lt;span class="c1"&gt;#@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minimal&lt;/span&gt;
          &lt;span class="na"&gt;toolchain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;
          &lt;span class="na"&gt;override&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo run --release -- --src=. --output-format=sarif | tee results.sarif&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload SARIF file&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;results.sarif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After executing this workflow, the result will be displayed in the security tab under code scanning. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmo3430915c3cossaims.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmo3430915c3cossaims.png" alt="Code scanning" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The rules in Phanalist also consist of detailed explanations written in Markdown, which are backed into the executable binary. This comes in very handy when scanning code. In &lt;code&gt;Sarif,&lt;/code&gt; you can specify a Markdown for the result found when you ran your tool.&lt;/p&gt;

&lt;p&gt;If I click and open one of the warnings, I will be greeted with a detailed explanation. Including the file and location that is causing the issue.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxj6yxra96lf87w4a0pzq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxj6yxra96lf87w4a0pzq.png" alt="Detailed explanation" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75rajcv2fob5chr3xbim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75rajcv2fob5chr3xbim.png" alt="Detailed explanation" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you learned something useful and can now improve your CI output. &lt;/p&gt;

</description>
      <category>php</category>
      <category>opensource</category>
      <category>codequality</category>
    </item>
    <item>
      <title>How I made it impossible to write spaghetti code. Part 2</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Mon, 22 Jan 2024 18:33:00 +0000</pubDate>
      <link>https://dev.to/denzyldick/traversing-an-ast-of-php-source-code-2kee</link>
      <guid>https://dev.to/denzyldick/traversing-an-ast-of-php-source-code-2kee</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is the part(3) of a series. I suggest you read parts &lt;a href="https://dev.to/denzyldick/the-beginning-of-my-php-static-analyzer-in-rust-5bp8"&gt;1&lt;/a&gt; and &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt; before this one. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In part &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt;, I made sure that the test passed correctly. The focus now is how we traverse a block of code inside its scope. We should be able to increase the variables in the formula at the right moment. &lt;/p&gt;

&lt;p&gt;If you have read part &lt;a href="https://dev.to/denzyldick/the-beginning-of-my-php-static-analyzer-in-rust-5bp8"&gt;1&lt;/a&gt;, you know that we need to implement the validate function that is mandatory in the trait &lt;code&gt;Rule&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Rule&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;E009&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;php_parser_rs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;project&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Suggestion&lt;/span&gt;&lt;span class="o"&gt;&amp;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In part &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt; we have learned that :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nodes are like the conditional statement: if, else, while, for, etc.&lt;br&gt;
Edges are the paths that can be taken. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;validate&lt;/code&gt; function will be executed for every statement in a source code. In the source code below, there are 32 lines of code.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Index&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;tooComplex&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$b&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="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$a&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="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

          &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$a&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="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;&lt;a href="https://github.com/denzyldick/phanalist"&gt;Phanalist&lt;/a&gt; needs a way to detect when we are in the function's scope with the name &lt;code&gt;tooComplex().&lt;/code&gt; With pattern matching, it is super easy to detect if the statement is either: &lt;code&gt;if&lt;/code&gt;,&lt;code&gt;else&lt;/code&gt;,&lt;code&gt;etc..&lt;/code&gt; The first statement that I want to match for is &lt;code&gt;class Index{&lt;/code&gt; and from there, we will continue down the tree. If you think the same way as I do you know that I will be using recursion to calculate the cyclomatic complexity. After we have matched the scope of the &lt;code&gt;tooComplex()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Rule&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;E009&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;php_parser_rs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;project&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Suggestion&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;suggestions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Graph&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&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;e&lt;/span&gt;&lt;span class="p"&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;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;member&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="py"&gt;.body.members&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;member&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nn"&gt;ClassMember&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;ConcreteMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concretemethod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;concretemethod&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="n"&gt;MethodBody&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="n"&gt;left_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="n"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="n"&gt;right_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                   &lt;span class="cd"&gt;/// HERE !!&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="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;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="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;suggestions&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;If you aren't familiar with pattern matching, it's kind of a switch keyword on steroids. Look for the                                Look for &lt;code&gt;/// HERE !!&lt;/code&gt; in the above code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt; &lt;span class="n"&gt;MethodBody&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="n"&gt;left_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="n"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                    &lt;span class="n"&gt;right_brace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="cd"&gt;/// HERE 1&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;As you can see we have four parameters that we can use. The ones we are looking for are the statements. The type of this parameter is &lt;code&gt;Vec&amp;lt;Statement&amp;gt;&lt;/code&gt; meaning it can be anything.&lt;/p&gt;

&lt;p&gt;Let's use the &lt;code&gt;Graph&lt;/code&gt; we previously created in part &lt;a href="https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4"&gt;2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the source code below, &lt;a href="https://github.com/denzyldick/phanalist"&gt;Phanalist&lt;/a&gt; calls a function with &lt;code&gt;let graph  = calculate _cyclomatic_complexity();&lt;/code&gt; This function will return a struct of the type &lt;code&gt;Graph&lt;/code&gt;. The first parameter passed is &lt;code&gt;statements.clone()&lt;/code&gt;. This function uses recursion to traverse down the tree. In part 4 I will explain the recursion we were thinking about.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
 &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_cyclomatic_complexity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                        &lt;span class="n"&gt;statements&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                                        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;graph&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="n"&gt;graph&lt;/span&gt;&lt;span class="nf"&gt;.calculate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;suggestions&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Suggestion&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This method body is too complex. Make it easier to understand."&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;concretemethod&lt;/span&gt;&lt;span class="py"&gt;.function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"E009"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&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;The &lt;code&gt;Graph&lt;/code&gt; struct has the &lt;code&gt;calculate&lt;/code&gt; function we previously used to calculate the cyclomatic complexity. My threshold is always ten, so I will be using that.&lt;/p&gt;

&lt;p&gt;If the value exceeds ten, I push the &lt;code&gt;Suggestion&lt;/code&gt; onto the vector. The vector of &lt;code&gt;Suggestion&lt;/code&gt; is the value returned to the validate function's caller. &lt;/p&gt;

&lt;h1&gt;
  
  
  Recursion
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwj5yh9nh4jtfjnie3ncf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwj5yh9nh4jtfjnie3ncf.png" alt="Image description" width="287" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In computer science, recursion is a method of solving a computational problem where the solution depends on solutions to smaller instances of the same problem. Recursion solves such recursive problems using functions that call themselves from within their code. &lt;a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;If you are a PHP developer, you know that a developer can make many more mistakes in PHP. In the future, the list of Rules will continue to grow into something more useful.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;Contribution is always welcome if you have a mistake you would like to add to &lt;a href="https://github.com/denzyldick/phanalist"&gt;Phanalist&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>php</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How I made it impossible to write spaghetti code.</title>
      <dc:creator>Denzyl Dick </dc:creator>
      <pubDate>Sun, 21 Jan 2024 00:48:50 +0000</pubDate>
      <link>https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4</link>
      <guid>https://dev.to/denzyldick/how-i-made-it-impossible-to-write-spaghetti-code-dg4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part 2 of a series of my static analyzer for PHP. If you did not read part &lt;a href="https://dev.to/denzyldick/the-beginning-of-my-php-static-analyzer-in-rust-5bp8"&gt;1&lt;/a&gt;, I suggest you to read it first. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A long time ago, I went to a development user group, and one of the talks was about cyclomatic complexity. At that time, I thought, what a cool name. If you already know the meaning of that cool name. Congrats, you are probably 1 of those developers who can detect lousy code without reading it. By seeing the indentation's shape, you can smell the bad code. &lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo1n1vk543d8cz6ftb64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo1n1vk543d8cz6ftb64.png" alt="Bad code with too many identatio" width="720" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Cyclomatic definition:&lt;/strong&gt;&lt;br&gt;
Used to describe the number of circuits in a network; equal to the number of edges minus the number of nodes plus the number of graphs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ok, breathe. If we translate the definitions into code, it will be something like this. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fugeaorf0204fpyhyuq6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fugeaorf0204fpyhyuq6a.png" alt="Bad code example" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nodes are like the conditional statement: &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;else&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, etc.&lt;br&gt;
Edges are the paths that can be taken. There are two paths in the code on lines &lt;code&gt;4&lt;/code&gt; and &lt;code&gt;14&lt;/code&gt;. One of the two can be taken if the variable defined on line &lt;code&gt;3&lt;/code&gt; has the value of &lt;code&gt;Hola&lt;/code&gt;; in this case, the first path will be taken. But in this example, the value of the &lt;code&gt;$a&lt;/code&gt; is &lt;code&gt;Helloworld&lt;/code&gt; so the second path will be taken. In the control flow graph below, you can view a better representation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feehbcsl5fsphsjk3klw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feehbcsl5fsphsjk3klw2.png" alt="Control flow graph" width="800" height="787"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, right; what is the complexity of that cool name I previously told you about? &lt;/p&gt;

&lt;p&gt;The code above is a small example, but imagine you have a method that has 100 lines of code. Then, the complexity of the code will increase drastically.&lt;/p&gt;
&lt;h2&gt;
  
  
  Calculate the complexity
&lt;/h2&gt;

&lt;p&gt;The equation for calculating the cyclomatic complexity is: &lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;M&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;N&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;E&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;This formula is also known as McCabe's Cyclomatic Complexity (MCC) and is widely used to measure the complexity of a program by analyzing its control flow structure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;N&lt;/code&gt; stands for the number of nodes, and &lt;code&gt;E&lt;/code&gt; stands for the number of edges. The &lt;code&gt;2P&lt;/code&gt; stands for two multiplied by the number of exit nodes. In our example, this will translate into: &lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;5&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;8&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;9&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mord"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;So, I started this blog by saying I can prevent myself from writing spaghetti code. If you did not read part &lt;a href="https://dev.to/denzyldick/the-beginning-of-my-php-static-analyzer-in-rust-5bp8"&gt;1&lt;/a&gt; of this series, you might not know I'm working on a static analyzer for PHP. The project's name is phanalist, and it's available on &lt;a href="https://github.com/denzyldick/phanalist"&gt;github&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In the following paragraph, we will see how &lt;a href="https://github.com/denzyldick/phanalist"&gt;phanalist&lt;/a&gt; can calculate the cyclomatic complexity of the scope of a method. Before creating Phanalist, I always kept the cyclomatic complexity of the methods I wrote in my mind. And if I see that the complexity is higher than 10. I always try to refactor the method, making it easier to understand. &lt;/p&gt;

&lt;p&gt;How does &lt;a href="https://github.com/denzyldick/phanalist"&gt;phanalist&lt;/a&gt; calculate the cyclomatic complexity? Let's start by implementing the equation above. We will start by creating a struct named Graph. This struct will have the three variables from the equation(n, e, and p).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Graph&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i64&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;blockquote&gt;
&lt;p&gt;This struct will be passed around when traversing the abstract syntax tree.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;M&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;N&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;E&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;When traversing the AST, we can increase the variables at the right moment. After that, I used the MCC equation to calculate the cyclomatic complexity of our example code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Graph&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;i64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.e&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.p&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="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Graph&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="nf"&gt;.calculate&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;5&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;In part &lt;a href="https://dev.to/denzyldick/the-beginning-of-my-php-static-analyzer-in-rust-5bp8"&gt;1&lt;/a&gt;, I explained how to navigate the abstract syntax tree and how Phanalist generates one. If you missed it, I suggest you read that before reading the next part of the series.&lt;/p&gt;

&lt;p&gt;In part &lt;a href="https://dev.to/denzyldick/traversing-an-ast-of-php-source-code-2kee"&gt;3&lt;/a&gt; of this series. I will explain how we traverse the AST when calculating the cyclomatic complexity. &lt;/p&gt;

</description>
      <category>php</category>
      <category>rust</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
