← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

ORM — Object-Relational Mapper

database PHP 7.0+ Beginner

Also Known As

ORM Eloquent Doctrine Active Record Data Mapper object-relational mapping

TL;DR

A library that maps database rows to PHP objects and vice versa — handling SQL generation, relationships, and lazy loading, at the cost of hiding query behaviour that can cause N+1 problems if used carelessly.

Explanation

An ORM bridges the object-oriented PHP world and the relational database world. Instead of writing SQL, you work with PHP objects (Eloquent models, Doctrine entities) and the ORM generates appropriate SQL. Two main patterns: Active Record (Eloquent in Laravel) — the model is both the domain object and the database gateway; User::find(1) issues SELECT and returns a User object; Doctrine in Data Mapper mode — entities are plain PHP objects, a separate Repository class handles persistence. ORM advantages: no raw SQL boilerplate; database-agnostic code (switch MySQL to PostgreSQL by changing config); built-in relationships (hasMany, belongsTo) with lazy loading; migrations. ORM pitfalls: lazy loading causes N+1 queries (loading 100 posts then accessing post->author triggers 100 individual author queries); ORM-generated SQL is not always optimal; complex reporting queries are easier in raw SQL.

Common Misconception

ORMs are slower than raw SQL and should be avoided in performance-sensitive code. ORMs generate correct SQL, and properly used with eager loading and indexes, perform identically to hand-written SQL. The performance issue is not the ORM itself but lazy loading causing N+1 queries — fixable with with() in Eloquent or JOIN FETCH in Doctrine. Use raw SQL only for complex reporting queries the ORM cannot express cleanly.

Why It Matters

ORMs are the default data access layer in Laravel and Symfony — understanding how they work prevents the most common performance antipattern in PHP applications. An Eloquent query like $posts = Post::all(); foreach ($posts as $post) { echo $post->author->name; } issues 1 + N database queries (one for posts, one per author). With $posts = Post::with('author')->get() it issues 2 queries total. Understanding the difference between lazy and eager loading is the single most impactful ORM knowledge for PHP developers.

Common Mistakes

  • Using lazy loading in loops — always eager-load relationships with with() when you know you will access them.
  • Calling ->get() and then ->count() separately — use ->count() alone which generates SELECT COUNT(*), not SELECT * then PHP count().
  • Using Model::all() on large tables — always add ->limit() or pagination to prevent loading entire tables into memory.
  • Over-using ORMs for reporting queries with multiple JOINs and aggregations — raw SQL with DB::select() is often cleaner and more readable for complex analytics.

Code Examples

✗ Vulnerable
// N+1 — 1 query for posts + 1 per post for author
$posts = Post::all(); // SELECT * FROM posts
foreach ($posts as $post) {
    echo $post->author->name; // SELECT * FROM users WHERE id = ? (×N)
    echo $post->comments->count(); // SELECT * FROM comments WHERE... (×N)
}
✓ Fixed
// Eager loading — 3 queries total regardless of post count
$posts = Post::with(['author', 'comments'])->paginate(20);
// SELECT * FROM posts LIMIT 20
// SELECT * FROM users WHERE id IN (1,2,3...)
// SELECT * FROM comments WHERE post_id IN (1,2,3...)
foreach ($posts as $post) {
    echo $post->author->name;     // no query — already loaded
    echo $post->comments->count(); // no query — already loaded
}

Added 23 Mar 2026
Edited 5 Apr 2026
Views 132
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 3 pings S 2 pings M 5 pings T 2 pings W 0 pings T 2 pings F 4 pings S 3 pings S 1 ping M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Google 92 Perplexity 15 Amazonbot 13 SEMrush 2 Ahrefs 2 Meta AI 1 ChatGPT 1
crawler 125 crawler_json 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Replace lazy loading with eager loading: Post::with(['author', 'comments'])->get() instead of Post::all() — eliminates N+1 queries for those relationships
📦 Applies To
PHP 7.0+ web cli

✓ schema.org compliant