PHP backend development tips and tricks: Frameworks and databases

PHP Backend Development Tips and Tricks: Frameworks and Databases

PHP remains one of the most widely used technologies in backend development, and for good reason. Its mature ecosystem, vast community, and continuous evolution make it a solid choice for projects of any scale. In this post, I’ll share practical tips for working with PHP in different frameworks and databases.

:rocket: General PHP Best Practices

1. Use Strict Typing

Since PHP 7.0, strict typing improves code quality and reduces errors:

declare(strict_types=1);

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

2. Leverage Modern Features

PHP 8.x introduced powerful features:

  • Named arguments: Improve readability
  • Match expressions: Cleaner alternative to switch
  • Nullsafe operator: Reduces null checks
  • Enums: Safe types for constant values
// Named arguments
$result = searchUser(
    name: 'Juan',
    active: true,
    limit: 10
);

// Match expression
$message = match($code) {
    200 => 'Success',
    404 => 'Not found',
    500 => 'Server error',
    default => 'Unknown code'
};

3. Composer is Your Ally

Manage dependencies professionally and leverage PSR-4 autoloading:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

:bullseye: Working with Frameworks

Laravel

Key Tips:

  1. Use Eloquent with Criterion: Models are powerful, but avoid N+1 queries. Use with() for eager loading:
// ❌ Bad: N+1 queries
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name;
}

// âś… Good: One query with join
$posts = Post::with('author')->get();
  1. Jobs and Queues: Decouple heavy tasks from the main request:
ProcessOrder::dispatch($order)->onQueue('payments');
  1. Service Container: Leverage dependency injection:
public function __construct(
    private readonly UserRepository $users,
    private readonly EmailService $mailer
) {}

Symfony

Key Tips:

  1. Modular Bundles: Organize your code into reusable bundles
  2. Doctrine Query Builder: More flexible than pure DQL:
$query = $em->createQueryBuilder()
    ->select('u')
    ->from('App\Entity\User', 'u')
    ->where('u.active = :active')
    ->setParameter('active', true)
    ->orderBy('u.name', 'ASC')
    ->getQuery();
  1. Event Dispatcher: Decouple logic with events:
$dispatcher->dispatch(new UserRegisteredEvent($user));

Slim/Lumen (Micro-frameworks)

Key Tips:

  1. Middleware: Organize cross-cutting logic (auth, logging, CORS)
  2. Keep Routes Clean: Use separate controllers
  3. PSR-7/PSR-15: Adhere to standards for better interoperability

:floppy_disk: Database Optimization

MySQL/MariaDB

1. Strategic Indexes:

-- For frequent searches
CREATE INDEX idx_user_email ON users(email);

-- Composite indexes for complex queries
CREATE INDEX idx_order_date_status ON orders(creation_date, status);

2. Always Use Prepared Statements:

$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);

3. EXPLAIN is Your Friend:
Analyze slow queries before optimizing.

PostgreSQL

1. JSONB for Semi-Structured Data:

// In Laravel/Eloquent
$users = User::where('metadata->level', '>', 5)->get();

2. Native Full-Text Search:

CREATE INDEX idx_product_search ON products
USING gin(to_tsvector('spanish', name || ' ' || description));

3. Partitioning Large Tables:
Useful for logs and historical data.

MongoDB (with official extension)

1. Projections to Reduce Transferred Data:

$users = $collection->find(
    ['active' => true],
    ['projection' => ['name' => 1, 'email' => 1]]
);

2. Aggregations for Complex Analysis:

$result = $collection->aggregate([
    ['$match' => ['status' => 'completed']],
    ['$group' => [
        '_id' => '$category',
        'total' => ['$sum' => '$amount']
    ]]
]);

Redis (cache and sessions)

1. Cache Expensive Queries:

$users = Cache::remember('active_users', 3600, function() {
    return User::where('active', true)->get();
});

2. Rate Limiting:

$key = "rate_limit:api:{$userId}";
$attempts = Redis::incr($key);
if ($attempts === 1) {
    Redis::expire($key, 60); // 60 seconds
}

:high_voltage: Performance Tips

  1. Always enable OPcache in production
  2. Use APCu or Redis for application cache
  3. Lazy load heavy resources
  4. Database connection pooling when possible
  5. Monitor with tools like New Relic or Blackfire

:locked: Basic Security

  • Never trust user input
  • Use password_hash() and password_verify()
  • Configure security headers correctly
  • Keep PHP and dependencies updated
  • Use environment variables for credentials (.env)

:graduation_cap: Recommended Resources

  • PHP.net documentation (always up-to-date)
  • PHP: The Right Way (phptherightway.com)
  • Laracasts (for Laravel)
  • SymfonyCasts (for Symfony)

:thought_balloon: Conclusion

Modern PHP is a robust and efficient language when used correctly. The key is to know your chosen framework well, optimize database interactions, and follow good development practices.

What other tips would you add? Is there any specific framework or database you want to dive deeper into? I read the comments!