1. php
  2. /database
  3. /pdo-mysql

PHP PDO and MySQL

Introduction to PDO and MySQL

PHP Data Objects (PDO) is a database abstraction layer providing a uniform interface for accessing databases in PHP. When combined with MySQL, one of the world's most popular relational database systems, PDO offers a powerful, secure, and flexible solution for database operations in web applications.

Understanding PDO with MySQL is essential for building secure, efficient database-driven applications that protect against SQL injection and provide reliable data management.

Why PDO and MySQL Matter

Security: PDO's prepared statements provide excellent protection against SQL injection attacks through proper parameter binding.

Database Abstraction: PDO allows switching between different database systems with minimal code changes.

Performance: Prepared statements can be reused, improving performance for repeated queries.

Error Handling: Comprehensive error reporting and exception handling for debugging and error management.

Advanced Features: Support for transactions, stored procedures, and complex data types.

MySQL Compatibility: Excellent integration with MySQL's features including stored procedures, views, and advanced data types.

Key PDO Features

Prepared Statements: Pre-compiled SQL statements that separate data from code for security and performance.

Parameter Binding: Safe way to include user data in SQL queries without concatenation.

Transaction Support: ACID-compliant transaction handling for data integrity.

Error Modes: Configurable error reporting including exceptions for robust error handling.

Fetch Modes: Multiple ways to retrieve data including arrays, objects, and custom classes.

PDO Connection and Configuration

Establishing MySQL Connections

<?php /**  * PDO MySQL Connection and Configuration  *   * Demonstrates secure database connections, configuration options,  * and connection management best practices.  */  /**  * Database connection manager with connection pooling  */ class DatabaseManager {  private static ?PDO $connection = null;  private static array $config = [];  private static array $options = [  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,  PDO::ATTR_EMULATE_PREPARES => false,  PDO::ATTR_STRINGIFY_FETCHES => false,  PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"  ];    /**  * Initialize database configuration  */  public static function configure(array $config): void  {  self::$config = array_merge([  'host' => 'localhost',  'port' => 3306,  'database' => '',  'username' => '',  'password' => '',  'charset' => 'utf8mb4',  'collation' => 'utf8mb4_unicode_ci',  'timezone' => '+00:00',  'strict_mode' => true,  'engine' => 'InnoDB'  ], $config);  }    /**  * Get database connection  */  public static function getConnection(): PDO  {  if (self::$connection === null) {  self::connect();  }    return self::$connection;  }    /**  * Establish database connection  */  private static function connect(): void  {  if (empty(self::$config)) {  throw new RuntimeException('Database configuration not set');  }    $dsn = self::buildDSN();    try {  self::$connection = new PDO(  $dsn,  self::$config['username'],  self::$config['password'],  self::$options  );    // Set MySQL session variables  self::configureMySQLSession();    } catch (PDOException $e) {  throw new RuntimeException('Database connection failed: ' . $e->getMessage());  }  }    /**  * Build MySQL DSN string  */  private static function buildDSN(): string  {  $dsn = "mysql:host={self::$config['host']}";  $dsn .= ";port={self::$config['port']}";  $dsn .= ";dbname={self::$config['database']}";  $dsn .= ";charset={self::$config['charset']}";    return $dsn;  }    /**  * Configure MySQL session settings  */  private static function configureMySQLSession(): void  {  $statements = [  "SET time_zone = '{self::$config['timezone']}'",  "SET NAMES {self::$config['charset']} COLLATE {self::$config['collation']}"  ];    if (self::$config['strict_mode']) {  $statements[] = "SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'";  }    foreach ($statements as $sql) {  self::$connection->exec($sql);  }  }    /**  * Test database connection  */  public static function testConnection(): bool  {  try {  $pdo = self::getConnection();  $stmt = $pdo->query('SELECT 1');  return $stmt !== false;  } catch (Exception $e) {  return false;  }  }    /**  * Get connection information  */  public static function getConnectionInfo(): array  {  $pdo = self::getConnection();    return [  'server_version' => $pdo->getAttribute(PDO::ATTR_SERVER_VERSION),  'client_version' => $pdo->getAttribute(PDO::ATTR_CLIENT_VERSION),  'connection_status' => $pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS),  'server_info' => $pdo->getAttribute(PDO::ATTR_SERVER_INFO),  'autocommit' => $pdo->getAttribute(PDO::ATTR_AUTOCOMMIT)  ];  }    /**  * Close database connection  */  public static function disconnect(): void  {  self::$connection = null;  }    /**  * Reconnect to database  */  public static function reconnect(): void  {  self::disconnect();  self::connect();  } }  /**  * Connection factory for multiple databases  */ class ConnectionFactory {  private static array $connections = [];  private static array $configs = [];    /**  * Register database configuration  */  public static function register(string $name, array $config): void  {  self::$configs[$name] = $config;  }    /**  * Get database connection by name  */  public static function get(string $name = 'default'): PDO  {  if (!isset(self::$connections[$name])) {  if (!isset(self::$configs[$name])) {  throw new InvalidArgumentException("Database configuration '$name' not found");  }    self::$connections[$name] = self::createConnection(self::$configs[$name]);  }    return self::$connections[$name];  }    /**  * Create new database connection  */  private static function createConnection(array $config): PDO  {  $dsn = "mysql:host={$config['host']};dbname={$config['database']};charset=utf8mb4";    $options = [  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,  PDO::ATTR_EMULATE_PREPARES => false,  PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"  ];    return new PDO($dsn, $config['username'], $config['password'], $options);  } }  // Usage examples try {  // Configure primary database  DatabaseManager::configure([  'host' => 'localhost',  'database' => 'my_app',  'username' => 'app_user',  'password' => 'secure_password',  'timezone' => '+00:00'  ]);    // Test connection  if (DatabaseManager::testConnection()) {  echo "Database connection successful!\n";    // Get connection info  $info = DatabaseManager::getConnectionInfo();  echo "MySQL Version: " . $info['server_version'] . "\n";  echo "Client Version: " . $info['client_version'] . "\n";  }    // Multiple database connections  ConnectionFactory::register('main', [  'host' => 'localhost',  'database' => 'main_db',  'username' => 'main_user',  'password' => 'main_pass'  ]);    ConnectionFactory::register('analytics', [  'host' => 'analytics-server',  'database' => 'analytics_db',  'username' => 'analytics_user',  'password' => 'analytics_pass'  ]);    $mainDB = ConnectionFactory::get('main');  $analyticsDB = ConnectionFactory::get('analytics');   } catch (Exception $e) {  echo "Database error: " . $e->getMessage() . "\n"; } ?> 

Prepared Statements and Parameter Binding

Secure Query Execution

<?php /**  * PDO Prepared Statements and Parameter Binding  *   * Demonstrates secure query execution, parameter binding,  * and various query patterns with MySQL.  */  /**  * Database query builder with prepared statements  */ class QueryBuilder {  private PDO $pdo;  private string $table = '';  private array $conditions = [];  private array $bindings = [];  private string $orderBy = '';  private string $groupBy = '';  private ?int $limit = null;  private ?int $offset = null;    public function __construct(PDO $pdo)  {  $this->pdo = $pdo;  }    /**  * Set table name  */  public function table(string $table): self  {  $this->table = $table;  return $this;  }    /**  * Add WHERE condition  */  public function where(string $column, string $operator, $value): self  {  $placeholder = ':' . $column . '_' . count($this->bindings);  $this->conditions[] = "$column $operator $placeholder";  $this->bindings[$placeholder] = $value;    return $this;  }    /**  * Add WHERE IN condition  */  public function whereIn(string $column, array $values): self  {  $placeholders = [];  foreach ($values as $i => $value) {  $placeholder = ":{$column}_in_{$i}";  $placeholders[] = $placeholder;  $this->bindings[$placeholder] = $value;  }    $this->conditions[] = "$column IN (" . implode(',', $placeholders) . ")";  return $this;  }    /**  * Add WHERE BETWEEN condition  */  public function whereBetween(string $column, $start, $end): self  {  $startPlaceholder = ":{$column}_start";  $endPlaceholder = ":{$column}_end";    $this->conditions[] = "$column BETWEEN $startPlaceholder AND $endPlaceholder";  $this->bindings[$startPlaceholder] = $start;  $this->bindings[$endPlaceholder] = $end;    return $this;  }    /**  * Add WHERE LIKE condition  */  public function whereLike(string $column, string $pattern): self  {  $placeholder = ":{$column}_like";  $this->conditions[] = "$column LIKE $placeholder";  $this->bindings[$placeholder] = $pattern;    return $this;  }    /**  * Add ORDER BY clause  */  public function orderBy(string $column, string $direction = 'ASC'): self  {  $this->orderBy = "ORDER BY $column $direction";  return $this;  }    /**  * Add GROUP BY clause  */  public function groupBy(string $column): self  {  $this->groupBy = "GROUP BY $column";  return $this;  }    /**  * Add LIMIT clause  */  public function limit(int $limit, ?int $offset = null): self  {  $this->limit = $limit;  $this->offset = $offset;  return $this;  }    /**  * Execute SELECT query  */  public function get(array $columns = ['*']): array  {  $columnList = implode(', ', $columns);  $sql = "SELECT $columnList FROM {$this->table}";    if (!empty($this->conditions)) {  $sql .= ' WHERE ' . implode(' AND ', $this->conditions);  }    if ($this->groupBy) {  $sql .= ' ' . $this->groupBy;  }    if ($this->orderBy) {  $sql .= ' ' . $this->orderBy;  }    if ($this->limit) {  $sql .= " LIMIT {$this->limit}";  if ($this->offset) {  $sql .= " OFFSET {$this->offset}";  }  }    $stmt = $this->pdo->prepare($sql);  $stmt->execute($this->bindings);    return $stmt->fetchAll();  }    /**  * Execute SELECT query and return first result  */  public function first(array $columns = ['*']): ?array  {  $this->limit(1);  $results = $this->get($columns);  return $results[0] ?? null;  }    /**  * Get count of records  */  public function count(): int  {  $sql = "SELECT COUNT(*) FROM {$this->table}";    if (!empty($this->conditions)) {  $sql .= ' WHERE ' . implode(' AND ', $this->conditions);  }    $stmt = $this->pdo->prepare($sql);  $stmt->execute($this->bindings);    return (int) $stmt->fetchColumn();  }    /**  * Insert record  */  public function insert(array $data): int  {  $columns = array_keys($data);  $placeholders = array_map(fn($col) => ":$col", $columns);    $sql = "INSERT INTO {$this->table} (" . implode(', ', $columns) . ") VALUES (" . implode(', ', $placeholders) . ")";    $stmt = $this->pdo->prepare($sql);  $stmt->execute($data);    return (int) $this->pdo->lastInsertId();  }    /**  * Update records  */  public function update(array $data): int  {  $setParts = [];  foreach ($data as $column => $value) {  $setParts[] = "$column = :update_$column";  $this->bindings[":update_$column"] = $value;  }    $sql = "UPDATE {$this->table} SET " . implode(', ', $setParts);    if (!empty($this->conditions)) {  $sql .= ' WHERE ' . implode(' AND ', $this->conditions);  }    $stmt = $this->pdo->prepare($sql);  $stmt->execute($this->bindings);    return $stmt->rowCount();  }    /**  * Delete records  */  public function delete(): int  {  if (empty($this->conditions)) {  throw new RuntimeException('DELETE queries must have WHERE conditions');  }    $sql = "DELETE FROM {$this->table} WHERE " . implode(' AND ', $this->conditions);    $stmt = $this->pdo->prepare($sql);  $stmt->execute($this->bindings);    return $stmt->rowCount();  }    /**  * Reset query builder  */  public function reset(): self  {  $this->conditions = [];  $this->bindings = [];  $this->orderBy = '';  $this->groupBy = '';  $this->limit = null;  $this->offset = null;    return $this;  } }  /**  * User repository with prepared statements  */ class UserRepository {  private PDO $pdo;  private QueryBuilder $query;    public function __construct(PDO $pdo)  {  $this->pdo = $pdo;  $this->query = new QueryBuilder($pdo);  }    /**  * Find user by ID  */  public function findById(int $id): ?array  {  return $this->query->table('users')  ->where('id', '=', $id)  ->first();  }    /**  * Find user by email  */  public function findByEmail(string $email): ?array  {  return $this->query->reset()  ->table('users')  ->where('email', '=', $email)  ->first();  }    /**  * Find users by role  */  public function findByRole(string $role): array  {  return $this->query->reset()  ->table('users')  ->where('role', '=', $role)  ->where('active', '=', 1)  ->orderBy('name')  ->get();  }    /**  * Search users by name  */  public function searchByName(string $search): array  {  return $this->query->reset()  ->table('users')  ->whereLike('name', "%$search%")  ->orderBy('name')  ->get();  }    /**  * Get paginated users  */  public function getPaginated(int $page, int $perPage): array  {  $offset = ($page - 1) * $perPage;    $users = $this->query->reset()  ->table('users')  ->orderBy('created_at', 'DESC')  ->limit($perPage, $offset)  ->get();    $total = $this->query->reset()  ->table('users')  ->count();    return [  'data' => $users,  'total' => $total,  'page' => $page,  'per_page' => $perPage,  'pages' => ceil($total / $perPage)  ];  }    /**  * Create new user  */  public function create(array $userData): int  {  $userData['created_at'] = date('Y-m-d H:i:s');  $userData['updated_at'] = date('Y-m-d H:i:s');    return $this->query->reset()  ->table('users')  ->insert($userData);  }    /**  * Update user  */  public function update(int $id, array $userData): bool  {  $userData['updated_at'] = date('Y-m-d H:i:s');    $affected = $this->query->reset()  ->table('users')  ->where('id', '=', $id)  ->update($userData);    return $affected > 0;  }    /**  * Delete user  */  public function delete(int $id): bool  {  $affected = $this->query->reset()  ->table('users')  ->where('id', '=', $id)  ->delete();    return $affected > 0;  }    /**  * Soft delete user  */  public function softDelete(int $id): bool  {  return $this->update($id, [  'deleted_at' => date('Y-m-d H:i:s'),  'active' => 0  ]);  }    /**  * Batch insert users  */  public function batchInsert(array $users): bool  {  if (empty($users)) {  return false;  }    $columns = array_keys($users[0]);  $placeholders = '(' . implode(',', array_map(fn($col) => ":$col", $columns)) . ')';    $sql = "INSERT INTO users (" . implode(', ', $columns) . ") VALUES ";  $values = [];  $bindings = [];    foreach ($users as $index => $user) {  $rowPlaceholders = [];  foreach ($columns as $column) {  $placeholder = ":{$column}_{$index}";  $rowPlaceholders[] = $placeholder;  $bindings[$placeholder] = $user[$column];  }  $values[] = '(' . implode(',', $rowPlaceholders) . ')';  }    $sql .= implode(',', $values);    $stmt = $this->pdo->prepare($sql);  return $stmt->execute($bindings);  }    /**  * Get user statistics  */  public function getStatistics(): array  {  $sql = "  SELECT   COUNT(*) as total,  SUM(CASE WHEN active = 1 THEN 1 ELSE 0 END) as active,  SUM(CASE WHEN role = 'admin' THEN 1 ELSE 0 END) as admins,  AVG(TIMESTAMPDIFF(YEAR, created_at, NOW())) as avg_age_years  FROM users  ";    $stmt = $this->pdo->prepare($sql);  $stmt->execute();    return $stmt->fetch();  } }  // Usage examples try {  $pdo = DatabaseManager::getConnection();  $userRepo = new UserRepository($pdo);    // Find user by ID  $user = $userRepo->findById(1);  if ($user) {  echo "Found user: " . $user['name'] . "\n";  }    // Search users  $searchResults = $userRepo->searchByName('john');  echo "Found " . count($searchResults) . " users matching 'john'\n";    // Get paginated results  $page = $userRepo->getPaginated(1, 10);  echo "Page 1 of {$page['pages']} ({$page['total']} total users)\n";    // Create new user  $newUserId = $userRepo->create([  'name' => 'Jane Doe',  'email' => '[email protected]',  'role' => 'user',  'active' => 1  ]);  echo "Created user with ID: $newUserId\n";    // Update user  $updated = $userRepo->update($newUserId, [  'name' => 'Jane Smith',  'role' => 'admin'  ]);  echo "User updated: " . ($updated ? 'Yes' : 'No') . "\n";    // Get statistics  $stats = $userRepo->getStatistics();  echo "User Statistics:\n";  echo "- Total: {$stats['total']}\n";  echo "- Active: {$stats['active']}\n";  echo "- Admins: {$stats['admins']}\n";   } catch (Exception $e) {  echo "Error: " . $e->getMessage() . "\n"; } ?> 

Error Handling and Debugging

Comprehensive Error Management

<?php /**  * PDO Error Handling and Debugging  *   * Demonstrates error handling, debugging techniques,  * and logging for PDO MySQL operations.  */  /**  * Database error handler with logging  */ class DatabaseErrorHandler {  private string $logFile;  private bool $debugMode;    public function __construct(string $logFile = 'database.log', bool $debugMode = false)  {  $this->logFile = $logFile;  $this->debugMode = $debugMode;  }    /**  * Handle PDO exceptions  */  public function handlePDOException(PDOException $e, string $sql = '', array $bindings = []): void  {  $error = [  'timestamp' => date('Y-m-d H:i:s'),  'error_code' => $e->getCode(),  'error_message' => $e->getMessage(),  'sql_state' => $e->errorInfo[0] ?? 'Unknown',  'driver_code' => $e->errorInfo[1] ?? 'Unknown',  'driver_message' => $e->errorInfo[2] ?? 'Unknown',  'file' => $e->getFile(),  'line' => $e->getLine(),  'sql' => $sql,  'bindings' => $bindings  ];    $this->logError($error);    if ($this->debugMode) {  $this->displayError($error);  }  }    /**  * Log error to file  */  private function logError(array $error): void  {  $logEntry = sprintf(  "[%s] PDO Error %s: %s | SQL: %s | Bindings: %s | File: %s:%d\n",  $error['timestamp'],  $error['error_code'],  $error['error_message'],  $error['sql'],  json_encode($error['bindings']),  $error['file'],  $error['line']  );    file_put_contents($this->logFile, $logEntry, FILE_APPEND | LOCK_EX);  }    /**  * Display error in debug mode  */  private function displayError(array $error): void  {  echo "<div style='background: #ffebee; border: 1px solid #f44336; padding: 15px; margin: 10px; border-radius: 4px;'>";  echo "<h3 style='color: #d32f2f; margin: 0 0 10px 0;'>Database Error</h3>";  echo "<p><strong>Error:</strong> {$error['error_message']}</p>";  echo "<p><strong>Code:</strong> {$error['error_code']}</p>";  echo "<p><strong>SQL State:</strong> {$error['sql_state']}</p>";    if ($error['sql']) {  echo "<p><strong>SQL:</strong> <code>{$error['sql']}</code></p>";  }    if (!empty($error['bindings'])) {  echo "<p><strong>Bindings:</strong> <code>" . json_encode($error['bindings']) . "</code></p>";  }    echo "<p><strong>Location:</strong> {$error['file']}:{$error['line']}</p>";  echo "</div>";  }    /**  * Check MySQL connection health  */  public function checkConnectionHealth(PDO $pdo): array  {  $health = [  'connected' => false,  'server_version' => null,  'uptime' => null,  'threads_connected' => null,  'queries_per_second' => null,  'errors' => []  ];    try {  // Test basic connectivity  $stmt = $pdo->query('SELECT 1');  $health['connected'] = true;    // Get server version  $health['server_version'] = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);    // Get server status  $stmt = $pdo->query('SHOW STATUS WHERE Variable_name IN ("Uptime", "Threads_connected", "Queries")');  $status = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);    $health['uptime'] = $status['Uptime'] ?? null;  $health['threads_connected'] = $status['Threads_connected'] ?? null;    if (isset($status['Queries']) && $health['uptime']) {  $health['queries_per_second'] = round($status['Queries'] / $health['uptime'], 2);  }    } catch (PDOException $e) {  $health['errors'][] = $e->getMessage();  }    return $health;  } }  /**  * Query profiler for performance monitoring  */ class QueryProfiler {  private array $queries = [];  private bool $enabled = true;    /**  * Start query profiling  */  public function startQuery(string $sql, array $bindings = []): string  {  if (!$this->enabled) {  return '';  }    $queryId = uniqid();  $this->queries[$queryId] = [  'sql' => $sql,  'bindings' => $bindings,  'start_time' => microtime(true),  'start_memory' => memory_get_usage(true),  'end_time' => null,  'end_memory' => null,  'duration' => null,  'memory_delta' => null  ];    return $queryId;  }    /**  * End query profiling  */  public function endQuery(string $queryId): void  {  if (!$this->enabled || !isset($this->queries[$queryId])) {  return;  }    $endTime = microtime(true);  $endMemory = memory_get_usage(true);    $this->queries[$queryId]['end_time'] = $endTime;  $this->queries[$queryId]['end_memory'] = $endMemory;  $this->queries[$queryId]['duration'] = $endTime - $this->queries[$queryId]['start_time'];  $this->queries[$queryId]['memory_delta'] = $endMemory - $this->queries[$queryId]['start_memory'];  }    /**  * Get profiling results  */  public function getResults(): array  {  $totalQueries = count($this->queries);  $totalTime = array_sum(array_column($this->queries, 'duration'));  $avgTime = $totalQueries > 0 ? $totalTime / $totalQueries : 0;    $slowQueries = array_filter($this->queries, fn($q) => $q['duration'] > 0.1);    return [  'total_queries' => $totalQueries,  'total_time' => round($totalTime, 4),  'average_time' => round($avgTime, 4),  'slow_queries' => count($slowQueries),  'queries' => $this->queries  ];  }    /**  * Reset profiler  */  public function reset(): void  {  $this->queries = [];  }    /**  * Enable/disable profiling  */  public function setEnabled(bool $enabled): void  {  $this->enabled = $enabled;  } }  /**  * Enhanced PDO wrapper with error handling and profiling  */ class SafePDO {  private PDO $pdo;  private DatabaseErrorHandler $errorHandler;  private QueryProfiler $profiler;    public function __construct(PDO $pdo, bool $debugMode = false)  {  $this->pdo = $pdo;  $this->errorHandler = new DatabaseErrorHandler('database.log', $debugMode);  $this->profiler = new QueryProfiler();  }    /**  * Prepare and execute query safely  */  public function execute(string $sql, array $bindings = []): PDOStatement  {  $queryId = $this->profiler->startQuery($sql, $bindings);    try {  $stmt = $this->pdo->prepare($sql);  $stmt->execute($bindings);    $this->profiler->endQuery($queryId);  return $stmt;    } catch (PDOException $e) {  $this->profiler->endQuery($queryId);  $this->errorHandler->handlePDOException($e, $sql, $bindings);  throw $e;  }  }    /**  * Execute query and fetch all results  */  public function fetchAll(string $sql, array $bindings = []): array  {  $stmt = $this->execute($sql, $bindings);  return $stmt->fetchAll();  }    /**  * Execute query and fetch single row  */  public function fetchOne(string $sql, array $bindings = []): ?array  {  $stmt = $this->execute($sql, $bindings);  $result = $stmt->fetch();  return $result ?: null;  }    /**  * Execute query and fetch single column  */  public function fetchColumn(string $sql, array $bindings = []): mixed  {  $stmt = $this->execute($sql, $bindings);  return $stmt->fetchColumn();  }    /**  * Begin transaction  */  public function beginTransaction(): bool  {  try {  return $this->pdo->beginTransaction();  } catch (PDOException $e) {  $this->errorHandler->handlePDOException($e);  throw $e;  }  }    /**  * Commit transaction  */  public function commit(): bool  {  try {  return $this->pdo->commit();  } catch (PDOException $e) {  $this->errorHandler->handlePDOException($e);  throw $e;  }  }    /**  * Rollback transaction  */  public function rollback(): bool  {  try {  return $this->pdo->rollback();  } catch (PDOException $e) {  $this->errorHandler->handlePDOException($e);  throw $e;  }  }    /**  * Get profiling results  */  public function getProfilingResults(): array  {  return $this->profiler->getResults();  }    /**  * Check database health  */  public function getHealthStatus(): array  {  return $this->errorHandler->checkConnectionHealth($this->pdo);  }    /**  * Get underlying PDO instance  */  public function getPDO(): PDO  {  return $this->pdo;  } }  // Usage examples try {  $pdo = DatabaseManager::getConnection();  $safePDO = new SafePDO($pdo, true);    // Execute queries with profiling and error handling  $users = $safePDO->fetchAll('SELECT * FROM users WHERE active = :active', ['active' => 1]);  echo "Found " . count($users) . " active users\n";    // Test error handling  try {  $safePDO->fetchAll('SELECT * FROM non_existent_table');  } catch (PDOException $e) {  echo "Caught and handled database error\n";  }    // Check database health  $health = $safePDO->getHealthStatus();  echo "Database connected: " . ($health['connected'] ? 'Yes' : 'No') . "\n";  echo "MySQL version: " . ($health['server_version'] ?? 'Unknown') . "\n";    // Get profiling results  $profile = $safePDO->getProfilingResults();  echo "Executed {$profile['total_queries']} queries in {$profile['total_time']}s\n";  echo "Average query time: {$profile['average_time']}s\n";   } catch (Exception $e) {  echo "Application error: " . $e->getMessage() . "\n"; } ?> 

For more PHP database topics:

Summary

PDO with MySQL provides a robust foundation for PHP database operations:

Secure Connections: Proper configuration and connection management prevent security vulnerabilities and ensure reliable database access.

Prepared Statements: Parameter binding protects against SQL injection while improving performance through statement reuse.

Error Handling: Comprehensive error management with logging and debugging capabilities ensures robust application behavior.

Query Building: Structured query builders provide clean, maintainable database operations with proper parameter binding.

Performance Monitoring: Query profiling and health monitoring enable optimization and troubleshooting of database operations.

Transaction Support: ACID-compliant transaction handling ensures data integrity in complex operations.

Best Practices: Following established patterns for connection management, error handling, and query execution creates maintainable, secure applications.

Mastering PDO with MySQL enables you to build secure, efficient database-driven PHP applications with professional error handling and performance monitoring capabilities.