Mastering Clean Code in PHP: Key Lessons from My Coding Journey

mdarifulhaque

MD ARIFUL HAQUE

Posted on September 25, 2024

Mastering Clean Code in PHP: Key Lessons from My Coding Journey

"Mastering Clean Code in PHP: Key Lessons from My Coding Journey" focuses on practical, hands-on rules and examples to help PHP developers write clean, maintainable, and efficient code. Here, we'll break down these essential rules into digestible parts, each accompanied by an example.

1. Meaningful Names

  • Rule: Use clear and descriptive names for variables, functions, and classes.
  • Why: This makes your code easier to understand and maintain.

Example:

   // BAD:
   $x = 25;
   function d($a, $b) {
       return $a + $b;
   }

   // GOOD:
   $age = 25;
   function calculateSum($firstNumber, $secondNumber) {
       return $firstNumber + $secondNumber;
   }
Enter fullscreen mode Exit fullscreen mode

Description:

  • Avoid one-letter variables like $x or $d. Instead, use descriptive names like $age or calculateSum.
  • Clear names make your intent explicit, helping both current and future developers understand the purpose of your code.

2. Single Responsibility Principle (SRP)

  • Rule: A function or class should have only one reason to change, meaning it should only do one thing.
  • Why: This makes your code more modular and easier to refactor.

Example:

   // BAD:
   class Order {
       public function calculateTotal() {
           // logic to calculate total
       }

       public function sendInvoiceEmail() {
           // logic to send email
       }
   }

   // GOOD:
   class Order {
       public function calculateTotal() {
           // logic to calculate total
       }
   }

   class InvoiceMailer {
       public function sendInvoiceEmail() {
           // logic to send email
       }
   }
Enter fullscreen mode Exit fullscreen mode

Description:

  • In the BAD example, the Order class is responsible for both calculating the total and sending an email. This violates SRP because it has two responsibilities.
  • In the GOOD example, we separate concerns by creating an InvoiceMailer class responsible for email tasks, making each class easier to manage and update.

3. Keep Functions Small

  • Rule: Functions should do one thing and do it well. Break large functions into smaller ones.
  • Why: Small functions are easier to understand, test, and maintain.

Example:

   // BAD:
   function processOrder($order) {
       // Validate order
       if (!$this->validateOrder($order)) {
           return false;
       }

       // Calculate total
       $total = $this->calculateTotal($order);

       // Send invoice
       $this->sendInvoiceEmail($order);

       return true;
   }

   // GOOD:
   function processOrder($order) {
       if (!$this->isOrderValid($order)) {
           return false;
       }

       $this->finalizeOrder($order);
       return true;
   }

   private function isOrderValid($order) {
       return $this->validateOrder($order);
   }

   private function finalizeOrder($order) {
       $total = $this->calculateTotal($order);
       $this->sendInvoiceEmail($order);
   }
Enter fullscreen mode Exit fullscreen mode

Description:

  • In the BAD example, the processOrder function is trying to do everything: validation, calculation, and sending an invoice.
  • In the GOOD example, we break down tasks into smaller, more focused methods (isOrderValid, finalizeOrder), improving readability and reusability.

4. Avoid Magic Numbers and Strings

  • Rule: Replace "magic" numbers and strings with named constants.
  • Why: This improves readability and makes the code easier to modify.

Example:

   // BAD:
   if ($user->age > 18) {
       echo "Eligible";
   }

   // GOOD:
   define('MINIMUM_AGE', 18);

   if ($user->age > MINIMUM_AGE) {
       echo "Eligible";
   }
Enter fullscreen mode Exit fullscreen mode

Description:

  • In the BAD example, the number 18 is a "magic number". You don’t know what it represents until you analyze the context.
  • In the GOOD example, using MINIMUM_AGE makes the intent clear and allows you to change the value in one place without searching the codebase.

5. DRY (Don't Repeat Yourself)

  • Rule: Avoid duplicating code. Reuse functions or classes wherever possible.
  • Why: Duplicated code is harder to maintain and more prone to bugs.

Example:

   // BAD:
   $total = $itemPrice * $quantity;
   $finalPrice = $total - ($total * $discountRate);

   $cartTotal = $cartItemPrice * $cartQuantity;
   $finalCartPrice = $cartTotal - ($cartTotal * $cartDiscountRate);

   // GOOD:
   function calculateFinalPrice($price, $quantity, $discountRate) {
       $total = $price * $quantity;
       return $total - ($total * $discountRate);
   }

   $finalPrice = calculateFinalPrice($itemPrice, $quantity, $discountRate);
   $finalCartPrice = calculateFinalPrice($cartItemPrice, $cartQuantity, $cartDiscountRate);
Enter fullscreen mode Exit fullscreen mode

Description:

  • In the BAD example, the price calculation logic is duplicated.
  • In the GOOD example, we create a reusable function calculateFinalPrice to avoid repetition and make the code more maintainable.

6. Use Guard Clauses to Reduce Nesting

  • Rule: Instead of deeply nested if statements, return early to simplify the structure.
  • Why: Guard clauses eliminate unnecessary nesting, making code cleaner and easier to follow.

Example:

   // BAD:
   function processPayment($amount) {
       if ($amount > 0) {
           if ($this->isPaymentMethodAvailable()) {
               if ($this->isUserLoggedIn()) {
                   // Process payment
               }
           }
       }
   }

   // GOOD:
   function processPayment($amount) {
       if ($amount <= 0) {
           return;
       }
       if (!$this->isPaymentMethodAvailable()) {
           return;
       }
       if (!$this->isUserLoggedIn()) {
           return;
       }

       // Process payment
   }
Enter fullscreen mode Exit fullscreen mode

Description:

  • In the BAD example, the logic is deeply nested, making it harder to read.
  • In the GOOD example, guard clauses are used to return early if conditions aren’t met, flattening the structure and making the code cleaner.

7. Comment on Why, Not What

  • Rule: Write comments to explain why something is happening, not what is happening (which should be clear from the code).
  • Why: Comments should provide value beyond the obvious, helping to explain the intent and reasoning behind the code.

Example:

   // BAD:
   // Increment age by 1
   $age++;

   // GOOD:
   // User's birthday has passed, increase age by 1
   $age++;
Enter fullscreen mode Exit fullscreen mode

Description:

  • The BAD comment simply restates what the code does, which is obvious from the code itself.
  • The GOOD comment explains why we are incrementing the age, adding meaningful context.

8. Refactor for Clarity

  • Rule: Continuously refactor to improve code clarity and simplicity.
  • Why: Clean code is achieved through constant refactoring to ensure that it is always readable, efficient, and maintainable.

Example:

   // Before Refactoring:
   function getDiscountedPrice($price, $isHoliday) {
       if ($isHoliday) {
           return $price * 0.9;
       } else {
           return $price;
       }
   }

   // After Refactoring:
   function getDiscountedPrice($price, $isHoliday) {
       return $isHoliday ? $price * 0.9 : $price;
   }
Enter fullscreen mode Exit fullscreen mode

Description:

  • Refactoring transforms long-winded code into more concise, elegant versions without losing clarity. In this example, we simplified an if-else structure using a ternary operator.

These essential rules—derived from the journey of coding cleanly in PHP—make your code more readable, maintainable, and scalable. By applying these principles consistently, you ensure that your code is easy to understand and modify over time, regardless of the complexity of your projects.

💖 💪 🙅 🚩
mdarifulhaque
MD ARIFUL HAQUE

Posted on September 25, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related