ZYVOPMulti-Platform Sync
SeriesAI NewsWhy ZyVOPJoin Discord
LoginGet Started
ZYVOPMulti-Platform Sync

The Developer Publishing Hub. Write once, publish everywhere, and make your work citation-ready with built-in SEO, AEO, and GEO discovery support. Zero reader paywalls.

Content

  • Categories
  • Tags
  • Badges
  • Leaderboard
  • Write Article
  • Newsletter

Company

  • About Us
  • Why ZyVOP
  • Developer API & CLI
  • Write for Us
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

© 2026 ZyVOP. Developer Publishing Hub.

Zero paywalls · Full content ownership
All systems operational
HomeHow I made it impossible to write spaghetti code. Part 2

How I made it impossible to write spaghetti code. Part 2

Denzyl
Denzyl
Senior Developer
September 6, 2026
3 min read
How I made it impossible to write spaghetti code. Part 2
#codequality#php#webdev#beginners
👍1
👏1
🔥1

This is the part(3) of a series. I suggest you read parts 1 and 2 before this one.

In part 2, 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.

If you have read part 1, you know that we need to implement the validate function that is mandatory in the trait Rule.

impl Rule for E009 {
    fn validate(
        &self,
        statement: &php_parser_rs::parser::ast::Statement,
    ) -> Vec<crate::project::Suggestion> {

    }}

Enter fullscreen mode Exit fullscreen mode

In part 2 we have learned that :

Nodes are like the conditional statement: if, else, while, for, etc.
Edges are the paths that can be taken.

The validate function will be executed for every statement in a source code. In the source code below, there are 32 lines of code.

<?php

class Index{

  public function tooComplex(){
    $a = 1;
    $b = 2;


    if($a > $b){
      if($b < $a){

        if($a == $b){

          while($b > $a){

          }

        }
      }
    }}}

Enter fullscreen mode Exit fullscreen mode

Phanalist needs a way to detect when we are in the function's scope with the name tooComplex(). With pattern matching, it is super easy to detect if the statement is either: if,else,etc.. The first statement that I want to match for is class Index{ 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 tooComplex() function.

impl Rule for E009 {
    fn validate(
        &self,
        statement: &php_parser_rs::parser::ast::Statement,
    ) -> Vec<crate::project::Suggestion> {
        let mut suggestions = Vec::new();
        let mut graph = Graph { n: 0, e: 0, p: 0 };
        match statement {
            Statement::Class(class) => {
                for member in &class.body.members {
                    match member {
                        ClassMember::ConcreteMethod(concretemethod) => {
                            match concretemethod.body.clone() {
                                MethodBody {
                                    comments: _,
                                    left_brace: _,
                                    statements,
                                    right_brace: _,
                                } => {
                                   /// HERE !!
                                    }
                                }
                            }
                        }
                        _ => {}
                    }
                }
            }
            _ => {}
        }
        suggestions
    }}

Enter fullscreen mode Exit fullscreen mode

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

 MethodBody {
                                    comments: _,
                                    left_brace: _,
                                    statements,
                                    right_brace: _,
                                } => {
                                    /// HERE 1

                                    }
                                }

Enter fullscreen mode Exit fullscreen mode

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 Vec<Statement> meaning it can be anything.

Let's use the Graph we previously created in part 2

In the source code below, Phanalist calls a function with let graph = calculate _cyclomatic_complexity(); This function will return a struct of the type Graph. The first parameter passed is statements.clone(). This function uses recursion to traverse down the tree. In part 4 I will explain the recursion we were thinking about.


 let graph = calculate_cyclomatic_complexity(
                                        statements.clone(),
                                        &mut graph,
                                    );
 if graph.calculate() > 10 {suggestions.push(Suggestion::from("This method body is too complex. Make it easier to understand.".to_string(),
                concretemethod.function,"E009".to_string() ));}

Enter fullscreen mode Exit fullscreen mode

The Graph struct has the calculate function we previously used to calculate the cyclomatic complexity. My threshold is always ten, so I will be using that.

If the value exceeds ten, I push the Suggestion onto the vector. The vector of Suggestion is the value returned to the validate function's caller.

Recursion

Image description

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. Wikipedia

Conclusion

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.

Thanks for reading!

Contribution is always welcome if you have a mistake you would like to add to Phanalist.

💡 TL;DR & Key Takeaways:
**TL;DR**
Part 3 extends the Rule‑trait implementation to traverse PHP AST nodes, detect the `tooComplex()` function’s scope, and recursively compute cyclomatic complexity via a node/edge graph. The `validate` method now matches class and control‑flow statements, updates graph counters, and returns suggestions for overly complex code.

- Implements `validate` for `E009` to walk each `Statement`, building a `Graph { n, e, p }` that tracks nodes, edges, and paths.
- Uses pattern matching and recursion to identify the target function (`tooComplex`) and nested control structures (`if`, `while`, etc.) for complexity analysis.
- Generates `Suggestion` objects when the computed cyclomatic complexity exceeds thresholds, enabling automated refactoring hints.

Comments (0)

Login to post a comment.

Denzyl
Denzyl

Passionate developer sharing knowledge about modern web technologies and best practices.

Subscribe to Denzyl's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.

More from Denzyl

View profile

Finding Duplicates Across Years: A DIY Workflow for Cleaning 300 GB of Photos

Finding "Duplicates Through Time": How I Cleaned Up 300GB of Photos Without Losing...

3 minSep 6

Building Siegu: A Rust‑Powered, Local‑First Photo Library with Tauri

I can't remember exactly when I started using Google Photos, but it’s been my go-to for a long time,...

5 minSep 6

From Throw-and-Pray to Predictable: Introducing Box, a Rust‑Inspired Result Type for PHP 8.1+

Most PHP developers are stuck in a cycle of "throw-and-pray" error handling. You write a method, it...

2 minSep 6

The Hidden Risks of PHP Object Unserialization and How to Avoid Them

Serializing in PHP is a way of converting a PHP object into a string. This string can be used in...

3 minSep 6

Making GitHub CI Logs Readable: Structured Output with Phanalist

Have you ever been in a situation where you made a PR or MR and waited for a couple of seconds for...

3 minSep 6