php
43 lines · 7 steps
A safe PDO user repository in PHP
A repository class wraps PDO with prepared statements to fetch users without exposing SQL injection risks.
Explained by
highlit
1<?php
2
3final class UserRepository
4{
5 public function __construct(private PDO $pdo)
6 {
7 }
8
9 public function findByEmail(string $email): ?array
10 {
11 $stmt = $this->pdo->prepare(
12 'SELECT id, email, display_name, created_at
13 FROM users
14 WHERE email = :email
15 LIMIT 1'
16 );
17
18 $stmt->bindValue(':email', $email, PDO::PARAM_STR);
19 $stmt->execute();
20
21 $user = $stmt->fetch(PDO::FETCH_ASSOC);
22
23 return $user === false ? null : $user;
24 }
25
26 public function searchActive(string $term, int $limit): array
27 {
28 $stmt = $this->pdo->prepare(
29 'SELECT id, email, display_name
30 FROM users
31 WHERE is_active = 1
32 AND display_name LIKE :term
33 ORDER BY display_name ASC
34 LIMIT :limit'
35 );
36
37 $stmt->bindValue(':term', '%' . $term . '%', PDO::PARAM_STR);
38 $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
39 $stmt->execute();
40
41 return $stmt->fetchAll(PDO::FETCH_ASSOC);
42 }
43}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Prepared statements with bound parameters keep user input out of the SQL text, closing off injection.
- 2Injecting the PDO connection lets the repository stay testable and agnostic about connection setup.
- 3Binding with the right PDO type — PARAM_INT for LIMIT, PARAM_STR for text — avoids subtle query bugs.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-safe-pdo-user-repository-in-php-explained-php-920f/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.