Lab 04: PDO & Repository Pattern

Objective

Build a full data access layer using PDO: prepared statements with named parameters, transactions with rollback, the Repository pattern for decoupled data access, query builder basics, and performance with fetchAll(PDO::FETCH_CLASS).

Background

PDO (PHP Data Objects) provides a database-agnostic API — the same code works with SQLite, MySQL, PostgreSQL, and others by changing only the DSN. The Repository pattern separates business logic from data access: OrderService calls $orderRepo->save($order) without knowing whether it's SQLite or PostgreSQL underneath. This makes testing easy (swap the real repo for an in-memory fake) and keeps domain logic clean.

Time

35 minutes

Prerequisites

  • PHP Foundations Lab 11 (Database with PDO)

Tools

  • Docker: zchencow/innozverse-php:latest (SQLite included)


Lab Instructions

Step 1: Schema, prepared statements & named parameters

💡 Always use prepared statements — never string-interpolate user input into SQL. "SELECT * FROM products WHERE id = {$_GET['id']}" is a SQL injection vulnerability. With PDO named parameters (:id) or positional (?), the value is always treated as data, never as SQL. The database driver handles escaping. This is not about performance (though prepared statements are faster for repeated queries) — it is about security.

📸 Verified Output:


Step 2: Transactions with rollback + Repository pattern

📸 Verified Output:


Summary

Feature
Code
Purpose

Named params

:name, :price

Readable, prevents injection

execute(array)

$stmt->execute($data)

Bind and run in one call

FETCH_CLASS

fetchAll(PDO::FETCH_CLASS, ClassName::class)

Direct object hydration

Transaction

beginTransaction(), commit(), rollBack()

Atomic multi-step writes

Repository

ProductRepository::find(int $id)

Decouple data access

Further Reading

Last updated