lowyiyiu / ppmw
A modern, single-file, heavily typed PHP 8 PDO MySQL wrapper.
Requires
- php: >=8.1
- psr/log: ^2.0 || ^3.0
README
A modern, single-file, heavily typed PHP 8.1+ PDO MySQL wrapper. Designed for simplicity, performance, and ease of use, with built-in PSR-3 logging support and a fluid query builder.
Features
- Zero Configuration Boilerplate: Easy to set up and get running.
- Fluent Query Builder: Chainable methods for building complex SQL queries securely.
- Prepared Statements Default: 100% immune to SQL injection when using the query builder.
- Memory Efficient: Support for PHP Generators (
yield) to process massive datasets. - PSR-3 Logging: Automatically logs slow queries and database errors (bring your own logger).
- Single File Drop-In: Install via Composer or download as a standalone, dependency-free file.
Installation
Option 1: Via Composer (Recommended)
composer require lowyiyiu/ppmw
Option 2: Manual Include
Download src/Database.php and include it directly in your script. It includes a built-in PSR-3 interface fallback, meaning it requires zero external dependencies.
require_once 'path/to/src/Database.php';
Initialization & Configuration
To start, instantiate the Database class with your connection array.
use LOWYIYIU\PPMW\Database; $config = [ 'host' => '127.0.0.1', // Default: 127.0.0.1 'port' => 3306, // Default: 3306 'database' => 'my_app', 'username' => 'root', 'password' => 'secret', 'charset' => 'utf8mb4', // Default: utf8mb4 'prefix' => 'app_' // Optional: Auto-prepended to table names ]; // Basic instantiation $db = new Database($config); // Advanced instantiation with PSR-3 Logger and custom Slow Query Threshold (in seconds) // $db = new Database($config, $myPsr3Logger, 1.5);
Retrieving Data
PPMW offers a fluent query builder to fetch data easily.
Fetching Multiple Rows (get)
Returns an array of associative arrays.
$users = $db->from('users')->get();
Fetching a Single Row (getOne)
Applies a LIMIT 1 and returns a single associative array, or null if no record is found.
$user = $db->from('users')->where('id', 1)->getOne();
Fetching a Single Column Value (getValue)
Fetches exactly one specific column from one row. Useful for counts or specific lookups.
// Returns the integer count $total = $db->getValue('COUNT(*)', 'users'); // Returns the email string $email = $db->from('users')->where('id', 1)->getValue('email');
Fetching Large Datasets with Cursors (getCursor)
If you need to process thousands of rows, use getCursor(). It uses PHP Generators to fetch one row into memory at a time, preventing memory exhaustion.
$users = $db->from('users')->where('status', 'active')->getCursor(); foreach ($users as $user) { // Process $user row by row }
Query Builder Methods
You can chain these methods together to build complex SQL statements before calling an execution method (get, update, delete, etc.).
Select & From
By default, PPMW selects *. You can specify columns using select().
$db->select('id', 'name', 'email') ->from('users') ->get(); // You can also use an alias $db->from('users', 'u')->get();
Where Clauses
The where method is dynamic and handles operators and arrays automatically.
// Basic equality: WHERE status = 'active' $db->from('users')->where('status', 'active'); // Custom operator: WHERE age > 18 $db->from('users')->where('age', '>', 18); // IN clause: WHERE role IN ('admin', 'editor') // PPMW automatically detects arrays and uses IN $db->from('users')->where('role', ['admin', 'editor']); // OR clauses $db->from('users') ->where('status', 'active') ->orWhere('role', 'admin');
Sorting & Grouping
// ORDER BY created_at DESC $db->from('users')->orderBy('created_at', 'DESC'); // GROUP BY role, status $db->from('users')->groupBy('role', 'status');
Limit & Offset
// LIMIT 10 OFFSET 20 $db->from('users')->limit(10)->offset(20)->get();
Joins
PPMW automatically applies your table prefix to joined tables.
// INNER JOIN $db->from('users') ->join('posts', 'users.id', '=', 'posts.user_id') ->get(); // LEFT JOIN $db->from('users') ->leftJoin('profiles', 'users.id', '=', 'profiles.user_id') ->get();
Writing Data
Inserting
Pass an associative array of column-value pairs.
// Returns boolean true/false $success = $db->insert('users', [ 'name' => 'John Doe', 'email' => 'john@example.com' ]); // Returns the newly created auto-incrementing ID $newId = $db->insertGetId('users', [ 'name' => 'Jane Doe', 'email' => 'jane@example.com' ]);
Updating
Always chain a where() clause before calling update(), otherwise you will update every row in the table.
// Returns the number of affected rows $affected = $db->where('id', 1)->update('users', [ 'status' => 'inactive' ]);
Deleting
Like updating, ensure you chain a where() clause first.
// Returns the number of affected rows $deleted = $db->where('status', 'banned')->delete('users');
Advanced Usage
Transactions
Safely execute multiple queries. If one fails, you can roll everything back.
try { $db->beginTransaction(); $db->insert('users', ['name' => 'Alice']); $db->insert('profiles', ['user_id' => 1, 'bio' => 'Hello']); $db->commit(); } catch (\Exception $e) { $db->rollBack(); // Handle error }
Raw Queries
If the query builder isn't enough, you can execute raw SQL with prepared bindings.
// For SELECT queries returning data $results = $db->rawQuery( "SELECT * FROM app_users WHERE age > ? AND status = ?", [18, 'active'] ); // For execution queries (INSERT, UPDATE, DELETE, ALTER) $success = $db->raw( "UPDATE app_users SET logins = logins + 1 WHERE id = ?", [1] );
Connection Management
// Disconnect (closes PDO connection) $db->disconnect(); // Ping the server (returns true if alive, automatically reconnects if "MySQL gone away") $isAlive = $db->ping(); // Get the raw PDO instance for native PDO methods $pdo = $db->getPdo();
Debugging Utilities
// Get the last executed query string (with bindings populated for debugging) $sql = $db->getLastQuery(); // Get the row count of the last executed statement $count = $db->getRowCount();
Error Handling & Exceptions
PPMW throws specific exceptions that you can catch to handle errors gracefully:
LOWYIYIU\PPMW\DatabaseException: The base exception for the library.LOWYIYIU\PPMW\DatabaseConnectionException: Thrown if the initial connection fails (e.g., bad credentials).LOWYIYIU\PPMW\DatabaseQueryException: Thrown if a query has a syntax error or fails to execute.
use LOWYIYIU\PPMW\DatabaseConnectionException; try { $db = new Database($config); } catch (DatabaseConnectionException $e) { echo "Could not connect to database: " . $e->getMessage(); }
License
This project is licensed under the MIT License. See the LICENSE file for details.