decmuc / pdodb
Modern, secure and fully compatible PDO-based replacement for ThingEngineerβs PHP-MySQLi-Database-Class
Requires
- php: >=8.1
README
PDOdb is a modern database wrapper built on top of PDO. It gives you a clean, expressive API for building queries without writing raw SQL by hand β while staying safe, strict and fast by default.
Inspired by ThingEngineer/MySQLiDb, but rewritten from scratch for PDO with full type-safe WHERE methods, strict injection protection and a fluent or step-by-step API β your choice.
π Documentation: https://DocsPDOdb.decmuc.dev
Why PDOdb?
Because writing $pdo->prepare("SELECT...") for the hundredth time is boring β and forgetting to bind a parameter is how things go wrong.
PDOdb handles the boring parts. You write what you mean:
$user = $db->whereInt('id', 42)->getOne('users'); // β SELECT * FROM users WHERE id = 42 LIMIT 1
No manual prepare, no manual bind, no white screen on error. Exceptions all the way.
Installation
composer require decmuc/pdodb
Or download manually β PDOdb is a single file.
Quick Start
require 'vendor/autoload.php'; use decMuc\PDOdb\PDOdb; $db = new PDOdb([ 'host' => 'localhost', 'username' => 'root', 'password' => 'secret', 'db' => 'my_database', 'charset' => 'utf8mb4', ]);
Both styles work β use whichever fits your code:
// Step by step β easy to read and extend $db->whereInt('active', 1); $db->whereString('role', 'admin'); $db->orderBy('created_at', 'DESC'); $users = $db->get('users'); // Fluent β compact for experienced devs $users = $db->whereInt('active', 1) ->whereString('role', 'admin') ->orderBy('created_at', 'DESC') ->get('users'); // β SELECT * FROM users WHERE active = 1 AND role = 'admin' ORDER BY created_at DESC
Features
- β
Type-safe WHERE methods β
whereInt(),whereFloat(),whereString(),whereBool(),whereDate(),whereLike(),whereSoundsLike()and more - β Prepared statements β all values are bound automatically, never interpolated
- β
Heuristic injection check β blocks obvious attack patterns like
1 OR 1=1before they even reach the DB - β Fluent or step-by-step API β both work, both produce the same SQL
- β
WHERE grouping β
whereGroup()for parenthesized conditions - β Joins & subqueries β with prefix support and aliasing
- β
Transactions β
startTransaction(),commit(),rollback() - β
Bulk insert & pagination β
insertBulk(),paginate() - β Table prefix β set once, applied everywhere automatically
- β Multiple instances β connect to several databases side by side
- β
Named placeholders in
rawQuery()β both:nameandnamestyle - β
Debug & trace β
setTrace(true),getLastDebugQuery(), debug levels 0β3
A Few More Examples
// Boolean flags β the clean way $db->whereBool('is_active', true)->get('users'); // β SELECT * FROM users WHERE is_active = 1 // Date range $db->whereDateBetween('created_at', '2025-01-01', '2025-12-31')->get('orders'); // β SELECT * FROM orders WHERE created_at BETWEEN '2025-01-01' AND '2025-12-31' // LIKE with wildcard modes $db->whereLike('name', 'john', 'both')->get('users'); // β SELECT * FROM users WHERE name LIKE '%john%' // WHERE groups with parentheses $db->whereInt('active', 1) ->whereGroup(function($q) { $q->whereString('role', 'admin') ->orWhereString('role', 'editor'); }) ->get('users'); // β SELECT * FROM users WHERE active = 1 AND (role = 'admin' OR role = 'editor') // Raw query with named placeholders $db->rawQuery("SELECT * FROM users WHERE id = :id AND role = :role", [ 'id' => 42, 'role' => 'admin', ]); // Insert & get ID $id = $db->insert('users', [ 'name' => 'Alice', 'email' => 'alice@example.com', 'active' => 1, ]); // Transactions $db->startTransaction(); try { $db->insert('orders', ['user_id' => 1, 'total' => 49.99]); $db->update('users', ['last_order' => date('Y-m-d')], $db->whereInt('id', 1)); $db->commit(); } catch (\Throwable $e) { $db->rollback(); }
Error Handling
PDOdb throws real exceptions β no more white screens, no more silent failures.
try { $db->whereInt('id', 'not-a-number'); $user = $db->getOne('users'); } catch (\InvalidArgumentException $e) { echo $e->getMessage(); // β Invalid integer value for column 'id'. }
Roadmap
v1.4.0 (current)
whereLike()/whereNotLike()with wildcard modes (both,left,right,none)whereSoundsLike()using MySQLSOUNDS LIKEwhereGroup()/openWhereGroup()/closeWhereGroup()for parenthesized conditions- Named placeholders in
rawQuery() - Several bug fixes (JOIN prefix, subquery bind params,
copy()with PDO)
v2.0.0 (planned)
- Multi-driver support: PostgreSQL, SQLite (and later MSSQL)
- Same API, different dialects internally β your code stays the same
- Compatibility table per method in the docs (β MySQL β PostgreSQL β οΈ SQLite)
Documentation
Full documentation with examples for every method: π https://DocsPDOdb.decmuc.dev
License
MIT β see LICENSE for details.
Built with β€οΈ by L. Fischer (decMuc)