PDO (PHP Data Objects) – ZALECANE dla większości projektów
PDO to obecnie najlepszy wybór dla nowoczesnych aplikacji PHP ze względu na:
- Uniwersalność (możliwość zmiany bazy danych)
- Czytelność kodu (named parameters)
- Bezpieczeństwo (domyślne prepared statements)
- Zgodność ze standardami branżowymi
- Wsparcie dla frameworków (Laravel, Symfony używają PDO)
Szczegółowe porównanie tabelaryczne
| Kryterium | PDO | MySQLi (obiektowo) | MySQLi (proceduralnie) |
|---|---|---|---|
| Obsługiwane bazy danych | MySQL, PostgreSQL, SQLite, Oracle, MS SQL Server | Tylko MySQL/MariaDB | Tylko MySQL/MariaDB |
| Styl programowania | Tylko obiektowy (nowoczesny) | Obiektowy | Proceduralny (przestarzały) |
| Prepared statements | Named + positional | Tylko positional | Tylko positional |
| Named parameters | :email, :id (czytelne) | Tylko ? | Tylko ? |
| Obsługa błędów | Exceptions (nowoczesne) | Exceptions + kody | Głównie kody błędów |
| Transakcje | beginTransaction(), commit(), rollback() | begin_transaction(), commit(), rollback() | mysqli_begin_transaction() |
| Wydajność | Bardzo dobra | Nieznacznie szybsza (1-2%) | Nieznacznie szybsza |
| Czytelność kodu | Bardzo wysoka | Wysoka | Niska |
| Popularność w 2024 | 60% projektów | 35% projektów | 5% projektów (legacy) |
| Frameworki | Laravel, Symfony, Slim, Yii | Rzadko używane | Nie używane |
| Wsparcie społeczności | Bardzo duże | Duże | Małe |
| Łatwość nauki | Bardzo łatwe | Łatwe | Łatwe ale przestarzałe |
| Przenośność kodu | Wysoka (zmiana bazy bez przepisywania) | Niska (tylko MySQL) | Niska |
| Zgodność z OOP | W pełni obiektowe | Obiektowe | Nie obiektowe |
| Multiple queries | Nie wspiera (bezpieczniejsze) | Wspiera | Wspiera |
| Asynchroniczne zapytania | Nie wspiera | Wspiera | Wspiera |
| Polecane dla | Nowe projekty, aplikacje komercyjne | Projekty tylko MySQL | Stare projekty (nie polecane) |
Porównanie kodu – Przykłady praktyczne
Przykład 1: Połączenie z bazą
PDO (zalecane):
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=app_db;charset=utf8mb4',
'username',
'password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);
echo "Połączono z bazą!";
} catch (PDOException $e) {
die("Błąd: " . $e->getMessage());
}
MySQLi (obiektowo):
$mysqli = new mysqli('localhost', 'username', 'password', 'app_db');
if ($mysqli->connect_error) {
die("Błąd: " . $mysqli->connect_error);
}
$mysqli->set_charset('utf8mb4');
echo "Połączono z bazą!";
MySQLi (proceduralnie) – NIE POLECANE:
$conn = mysqli_connect('localhost', 'username', 'password', 'app_db');
if (!$conn) {
die("Błąd: " . mysqli_connect_error());
}
mysqli_set_charset($conn, 'utf8mb4');
echo "Połączono z bazą!";
Werdykt: PDO wygrywa – zwięzłe, z automatyczną obsługą wyjątków.
Przykład 2: Prepared Statements (bezpieczeństwo)
PDO (zalecane) – Named Parameters:
// Bardzo czytelne - wiadomo co jest czym
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email AND active = :active");
$stmt->execute([
'email' => $email,
'active' => 1
]);
$user = $stmt->fetch();
MySQLi (obiektowo):
// Mniej czytelne - trzeba pamiętać kolejność
$stmt = $mysqli->prepare("SELECT * FROM users WHERE email = ? AND active = ?");
$stmt->bind_param("si", $email, 1); // s=string, i=integer
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
MySQLi (proceduralnie) – NIE POLECANE:
// Najbardziej rozwlekłe
$stmt = mysqli_prepare($conn, "SELECT * FROM users WHERE email = ? AND active = ?");
mysqli_stmt_bind_param($stmt, "si", $email, 1);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$user = mysqli_fetch_assoc($result);
Przykład 3: INSERT z pobieraniem ID
PDO (zalecane):
$stmt = $pdo->prepare("INSERT INTO users (username, email) VALUES (:username, :email)");
$stmt->execute([
'username' => $username,
'email' => $email
]);
$userId = $pdo->lastInsertId();
echo "Dodano użytkownika ID: $userId";
MySQLi (obiektowo):
$stmt = $mysqli->prepare("INSERT INTO users (username, email) VALUES (?, ?)");
$stmt->bind_param("ss", $username, $email);
$stmt->execute();
$userId = $mysqli->insert_id;
echo "Dodano użytkownika ID: $userId";
MySQLi (proceduralnie) – NIE POLECANE:
$stmt = mysqli_prepare($conn, "INSERT INTO users (username, email) VALUES (?, ?)");
mysqli_stmt_bind_param($stmt, "ss", $username, $email);
mysqli_stmt_execute($stmt);
$userId = mysqli_insert_id($conn);
echo "Dodano użytkownika ID: $userId";
Przykład 4: Transakcje
PDO (zalecane):
try {
$pdo->beginTransaction();
$pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$pdo->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$pdo->commit();
echo "Przelew wykonany!";
} catch (Exception $e) {
$pdo->rollBack();
echo "Błąd: " . $e->getMessage();
}
MySQLi (obiektowo):
$mysqli->begin_transaction();
try {
$mysqli->query("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$mysqli->query("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$mysqli->commit();
echo "Przelew wykonany!";
} catch (Exception $e) {
$mysqli->rollback();
echo "Błąd: " . $e->getMessage();
}
MySQLi (proceduralnie) – NIE POLECANE:
mysqli_begin_transaction($conn);
$success = mysqli_query($conn, "UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$success = $success && mysqli_query($conn, "UPDATE accounts SET balance = balance + 100 WHERE id = 2");
if ($success) {
mysqli_commit($conn);
echo "Przelew wykonany!";
} else {
mysqli_rollback($conn);
echo "Błąd: " . mysqli_error($conn);
}
Kiedy używać którego rozwiązania?
- Budujesz nowy projekt (zawsze!)
- Chcesz mieć możliwość zmiany bazy danych w przyszłości
- Pracujesz nad aplikacją komercyjną
- Uczysz się nowoczesnego PHP
- Chcesz kodu zgodnego z branżowymi standardami
- Planujesz używać frameworków (Laravel, Symfony)
- Cenisz czytelność kodu (named parameters)
Przykłady projektów:
- System CRM
- E-commerce
- Blog/CMS
- API REST
- Aplikacja webowa SaaS
- Panel Discord bota
- System zarządzania treningami
Używaj MySQLi (obiektowo) gdy:
- Na 100% będziesz używać tylko MySQL/MariaDB
- Potrzebujesz asynchronicznych zapytań
- Potrzebujesz multiple statements
- Pracujesz z istniejącym projektem używającym MySQLi
- Wydajność jest KRYTYCZNA (różnica ~1-2%)
Przykłady projektów:
- Wysoko obciążony system (miliony zapytań/dzień)
- Integracje wymagające multiple queries
- Migracja starego projektu z mysql do mysqli
Używaj MySQLi (proceduralnie) TYLKO gdy:
- Pracujesz z bardzo starym kodem legacy
- Musisz utrzymywać stary projekt
NIE UŻYWAJ w nowych projektach! To przestarzałe podejście.