January 19, 2025

Most Common Mistakes That PHP Developers Make

January 19, 2025

Most Common Mistakes That PHP Developers Make

Learn essential PHP best practices and avoid common pitfalls. Master modern PHP development.

Introduction

As PHP continues to evolve with modern features and best practices, it’s crucial for developers to write clean, efficient, and maintainable code.

In this comprehensive guide, we’ll explore most common mistakes that PHP developers make and learn how to avoid them. 

Whether you’re a beginner or an experienced developer, these insights will help you write better PHP code.

PHP Best Practices: Common Mistakes and How to Fix Them

Best Practice

MISTAKE 1: Loose comparisons leading to unexpected behavior

// Bad
function isUserActive($status) {
    if ($status == true) {  // '1', 1, true, 'true' all evaluate to true
        return true;
    }
    return false;
}

// Good
function isUserActive(bool $status): bool {
    return $status === true;
}

MISTAKE 2: Not handling array access safely

// Bad
function getUserName($user) {
    return $user['name'];  // Crashes if 'name' doesn't exist
}

// Good
function getUserName(array $user): string {
    return $user['name'] ?? 'Unknown';  // Null coalesce operator
}

MISTAKE 3: Inefficient string concatenation in loops

// Bad
function buildReport(array $items): string {
    $report = '';
    foreach ($items as $item) {
        $report = $report . $item->description;  // Creates new string each time
    }
    return $report;
}

// Good
function buildReport(array $items): string {
    $reports = [];
    foreach ($items as $item) {
        $reports[] = $item->description;
    }
    return implode('', $reports);
}

MISTAKE 4: Not using proper SQL parameter binding

// Bad
function findUser($db, $userId) {
    return $db->query("SELECT * FROM users WHERE id = " . $userId);  // SQL injection risk
}

// Good
function findUser(PDO $db, int $userId): ?array {
    $stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$userId]);
    return $stmt->fetch(PDO::FETCH_ASSOC);
}

MISTAKE 5: Not handling file operations safely

// Bad
function readConfig($filename) {
    $content = file_get_contents($filename);  // No error handling
    return json_decode($content);
}

// Good
function readConfig(string $filename): array {
    if (!file_exists($filename)) {
        throw new RuntimeException("Config file not found: $filename");
    }
    
    $content = file_get_contents($filename);
    if ($content === false) {
        throw new RuntimeException("Failed to read config file: $filename");
    }
    
    $data = json_decode($content, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new RuntimeException("Invalid JSON in config file: " . json_last_error_msg());
    }
    
    return $data;
}

MISTAKE 6: Not using proper type declarations

// Bad
function calculateTotal($price, $quantity) {
    return $price * $quantity;
}

// Good
function calculateTotal(float $price, int $quantity): float {
    return $price * $quantity;
}

MISTAKE 7: Misusing error suppression operator

// Bad
function getImageSize($filename) {
    return @getimagesize($filename);  // Suppresses errors silently
}

// Good
function getImageSize(string $filename): ?array {
    if (!file_exists($filename)) {
        return null;
    }
    
    $size = getimagesize($filename);
    return $size !== false ? $size : null;
}

MISTAKE 8: Not using namespaces properly

// Bad - Global namespace pollution
class User {}
class Order {}

// Good
namespace App\Models;

class User {}

namespace App\Orders;

class Order {}

MISTAKE 9: Poor exception handling

// Bad
function processOrder($order) {
    try {
        // Process order
    } catch (Exception $e) {
        error_log($e->getMessage());  // Generic catch-all
    }
}

// Good
function processOrder(Order $order): void {
    try {
        // Process order
    } catch (DatabaseException $e) {
        // Handle database specific errors
        throw new OrderProcessingException("Database error while processing order", 0, $e);
    } catch (ValidationException $e) {
        // Handle validation specific errors
        throw new OrderProcessingException("Validation failed for order", 0, $e);
    }
}

MISTAKE 10: Not using constructor property promotion (PHP 8.0+)

// Bad
class Customer {
    private string $name;
    private string $email;
    
    public function __construct(string $name, string $email) {
        $this->name = $name;
        $this->email = $email;
    }
}

// Good
class Customer {
    public function __construct(
        private string $name,
        private string $email,
    ) {}
}

MISTAKE 11: Not using null safe operator (PHP 8.0+)

// Bad
function getCountryName($user) {
    if ($user !== null && 
        $user->getAddress() !== null && 
        $user->getAddress()->getCountry() !== null) {
        return $user->getAddress()->getCountry()->getName();
    }
    return null;
}

// Good
function getCountryName(?User $user): ?string {
    return $user?->getAddress()?->getCountry()?->getName();
}

MISTAKE 12: Inefficient array operations

// Bad
function findUser(array $users, string $email): ?array {
    foreach ($users as $user) {
        if ($user['email'] === $email) {
            return $user;
        }
    }
    return null;
}

// Good
function findUser(array $users, string $email): ?array {
    return array_filter(
        $users,
        fn($user) => $user['email'] === $email
    )[0] ?? null;
}

MISTAKE 13: Not using array destructuring

// Bad
function processCoordinates($point) {
    $x = $point[0];
    $y = $point[1];
    return sqrt($x * $x + $y * $y);
}

// Good
function processCoordinates(array $point): float {
    [$x, $y] = $point;
    return sqrt($x * $x + $y * $y);
}

MISTAKE 14: Poor date handling

// Bad
function isUserActive($lastLoginTimestamp) {
    return (time() - $lastLoginTimestamp) < (30 * 24 * 60 * 60);
}

// Good
function isUserActive(DateTime $lastLogin): bool {
    $thirtyDaysAgo = new DateTime('-30 days');
    return $lastLogin > $thirtyDaysAgo;
}

MISTAKE 15: Not using match expression (PHP 8.0+)

// Bad
function getStatusMessage($status) {
    switch ($status) {
        case 'pending':
            return 'Order is pending';
        case 'processing':
            return 'Order is being processed';
        case 'completed':
            return 'Order has been completed';
        default:
            return 'Unknown status';
    }
}

// Good
function getStatusMessage(string $status): string {
    return match($status) {
        'pending' => 'Order is pending',
        'processing' => 'Order is being processed',
        'completed' => 'Order has been completed',
        default => 'Unknown status',
    };
}

MISTAKE 16: Not using named arguments (PHP 8.0+)

// Bad
function createUser($name, $email, $age = null, $country = null) {
    // Have to remember argument order
    return new User($name, $email, null, 'US');
}

// Good
function createUser(
    string $name,
    string $email,
    ?int $age = null,
    ?string $country = null
): User {
    return new User(
        name: $name,
        email: $email,
        age: $age,
        country: $country ?? 'US'
    );
}

MISTAKE 17: Poor validation practices

// Bad
function validateEmail($email) {
    return strpos($email, '@') !== false;
}

// Good
function validateEmail(string $email): bool {
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

MISTAKE 18: Inefficient file handling

// Bad
function processLargeFile($filename) {
    $content = file_get_contents($filename); // Loads entire file into memory
    $lines = explode("\n", $content);
    foreach ($lines as $line) {
        // Process line
    }
}

// Good
function processLargeFile(string $filename): void {
    $handle = fopen($filename, 'r');
    while (($line = fgets($handle)) !== false) {
        // Process line
    }
    fclose($handle);
}

MISTAKE 19: Not using proper dependency injection

// Bad
class UserService {
    private $db;
    
    public function __construct() {
        $this->db = new Database(); // Hard coupling
    }
}

// Good
class UserService {
    public function __construct(
        private readonly DatabaseInterface $db
    ) {}
}

MISTAKE 20: Not using proper error codes

// Bad
class CustomException extends Exception {
    public function __construct($message) {
        parent::__construct($message);
    }
}

// Good
class CustomException extends Exception {
    public const INVALID_INPUT = 1001;
    public const DATABASE_ERROR = 1002;
    public const API_ERROR = 1003;
    
    public function __construct(
        string $message,
        int $code = self::INVALID_INPUT,
        ?Throwable $previous = null
    ) {
        parent::__construct($message, $code, $previous);
    }
}

MISTAKE 21: Not using early returns

// Bad
function processUser($user) {
    if ($user !== null) {
        if ($user->isActive()) {
            if ($user->hasPermission('admin')) {
                // Do something
                return true;
            }
        }
    }
    return false;
}

// Good
function processUser(?User $user): bool {
    if ($user === null) {
        return false;
    }
    
    if (!$user->isActive()) {
        return false;
    }
    
    if (!$user->hasPermission('admin')) {
        return false;
    }
    
    // Do something
    return true;
}

MISTAKE 22: Not using proper array initialization

// Bad
$items = null;
if (someCondition()) {
    $items = [];
}

// Good
$items = [];
if (someCondition()) {
    // Fill array
}

MISTAKE 23: Not using proper logging

// Bad
function processPayment($amount) {
    try {
        // Process payment
    } catch (Exception $e) {
        error_log('Payment failed');
    }
}

// Good
function processPayment(float $amount): void {
    try {
        // Process payment
    } catch (PaymentException $e) {
        $context = [
            'amount' => $amount,
            'error' => $e->getMessage(),
            'trace' => $e->getTraceAsString(),
            'timestamp' => date('Y-m-d H:i:s')
        ];
        $this->logger->error('Payment processing failed', $context);
        throw $e;
    }
}

MISTAKE 24: Not using proper service containers

// Bad
class UserController {
    private UserService $userService;
    private Logger $logger;
    
    public function __construct() {
        $this->userService = new UserService(new Database());
        $this->logger = new Logger();
    }
}

// Good
class Container {
    private array $services = [];
    private array $factories = [];
    
    public function register(string $id, callable $factory): void {
        $this->factories[$id] = $factory;
    }
    
    public function get(string $id): object {
        if (!isset($this->services[$id])) {
            if (!isset($this->factories[$id])) {
                throw new ServiceNotFoundException($id);
            }
            $this->services[$id] = $this->factories[$id]();
        }
        
        return $this->services[$id];
    }
}

class UserController {
    public function __construct(
        private readonly UserService $userService,
        private readonly LoggerInterface $logger
    ) {}
}

MISTAKE 25: Not using proper password hashing

// Bad
function setPassword($password) {
    $this->password = md5($password); // Never use MD5 for passwords
}

// Good
function setPassword(string $password): void {
    $this->password = password_hash(
        $password,
        PASSWORD_DEFAULT,
        ['cost' => 12]
    );
}

Conclusion

Writing high-quality PHP code requires attention to detail and awareness of modern best practices. By avoiding these common mistakes and following the recommended approaches, you can create more maintainable, secure, and efficient applications.

Remember to:

  1. Use strict types and proper type declarations
  2. Leverage modern PHP features
  3. Focus on security best practices
  4. Optimize performance where it matters
  5. Write clean, maintainable code
  6. Follow SOLID principles
  7. Use appropriate error handling
  8. Implement proper logging
  9. Write testable code
  10. Keep up with PHP’s evolution

Additional Resources

  • PHP Official Documentation
  • PHP Standards Recommendations (PSR)
  • PHP The Right Way
  • Modern PHP Books and Tutorials
  • PHP Security Best Practices Guide

Thank you for reading this article. Happy Coding!!!

Share on:
Share on:
LinkedIn
Email
Facebook
Reddit
Twitter
WhatsApp
Skype
Print

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment

Recent posts

LogicRays Blogs

Read other latest blogs on technology, trending, Web & Mobile App, E-Commerce related etc.
We recommend
Featured posts

Table of Contents