PHP

Lesson 04

PDO prepared statements

Use prepared statements with bound values instead of interpolating request data into SQL strings.

Good Code

src/UserRepository.php
<?php declare(strict_types=1);

final class UserRepository
{
    public function __construct(private PDO $pdo) {}

    public function findActiveByEmail(string $email): ?array
    {
        // Placeholders keep SQL structure separate from user data.
        $stmt = $this->pdo->prepare(
            'SELECT id, email, name FROM users WHERE email = :email AND active = 1'
        );
        $stmt->execute(['email' => $email]);

        $user = $stmt->fetch(PDO::FETCH_ASSOC);
        return $user === false ? null : $user;
    }
}

Bad Code

users.php
<?php

$email = $_GET['email'];
// Interpolating request data makes the query boundary unsafe.
$sql = "SELECT * FROM users WHERE email = '$email' AND active = 1";
$user = $pdo->query($sql)->fetch();

Review Notes

What to review

Good Code

The good version prepares SQL once, binds the email as data, selects explicit columns, and returns null when no row matches.

Bad Code

The bad version interpolates a request value into SQL and selects every column. A reviewer cannot trust the query boundary or the response shape.

Takeaways

  • SQL structure and SQL values should stay separate; PDO placeholders make that boundary reviewable.