عمليات قاعدة البيانات PDO
لقد تعلمت أوامر MySQL، لكن الهدف الحقيقي هو إدارة قاعدة البيانات من خلال PHP. PDO (PHP Data Objects) هي طبقة تجريد قواعد البيانات القياسية الموصى بها في PHP — حيث تعمل مجموعة واحدة من الأكواد مع 12 نوعًا من قواعد البيانات. تذكر: تعلم PDO، وتجاهل MySQLi.
1. لماذا PDO؟
| PDO | MySQLi | |
|---|---|---|
| قواعد البيانات المدعومة | 12 (MySQL/PostgreSQL/SQLite...) | MySQL فقط |
| المعلمات المسماة | ✅ :name |
❌ ? فقط |
| استرداد المصفوفات الترابطية | ✅ PDO::FETCH_ASSOC |
✅ |
| استرداد الكائنات | ✅ PDO::FETCH_OBJ |
❌ (يتطلب إعدادات إضافية) |
| وضع الاستثناء | ✅ قابل للتكوين | ✅ قابل للتكوين |
| الحداثة | 🏆 معيار المجتمع | التراث |
2. اتصال PDO
PHP
<?php
$host = 'localhost';
$dbname = 'myblog';
$username = 'root';
$password = '';
$charset = 'utf8mb4';
$dsn = "mysql:host={$host};dbname={$dbname};charset={$charset}";
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
echo "✅ Database connected successfully!<br>";
} catch (PDOException $e) {
die("❌ Connection failed: " . $e->getMessage());
}
?>
| خيار الاتصال | المعنى | السبب |
|---|---|---|
ERRMODE_EXCEPTION |
إثارة استثناءات عند حدوث أخطاء | لا للفشل الصامت |
FETCH_ASSOC |
التعيين الافتراضي للمصفوفات الترابطية | التنسيق الأكثر استخدامًا |
EMULATE_PREPARES => false |
استخدم العبارات المعدة مسبقًا | أمان حقيقي |
💡 نصيحة: هذه الخيارات الثلاثة الخاصة بـ PDO هي الإعدادات القياسية — احرص دائمًا على تضمينها عند إنشاء اتصال PDO. يضمن
EMULATE_PREPARES => false استخدام العبارات المُعدة مسبقًا الأصلية في MySQL بدلاً من تلك التي يحاكيها PDO.
3. query() — تنفيذ استعلامات SELECT
PHP
<?php
// Simple query
$stmt = $pdo->query("SELECT * FROM users");
$users = $stmt->fetchAll();
// Iterate results
foreach ($users as $user) {
echo "ID: {$user['id']}, Username: {$user['username']}<br>";
}
// Fetch a single row
$stmt = $pdo->query("SELECT * FROM users WHERE id = 1");
$user = $stmt->fetch();
echo $user['username']; // John
?>
(1) أوضاع الاسترجاع
PHP
<?php
$stmt = $pdo->query("SELECT id, username FROM users");
// Associative array (default)
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo $row['username'];
// Numeric index
$row = $stmt->fetch(PDO::FETCH_NUM);
echo $row[1];
// Object
$row = $stmt->fetch(PDO::FETCH_OBJ);
echo $row->username;
// Fetch a single column
$usernames = $stmt->fetchAll(PDO::FETCH_COLUMN, 1);
print_r($usernames); // ['John', 'Jane', ...]
?>
4. العبارات المعدة مسبقًا (أساسي!)
تعد العبارات المُعدة مسبقًا هي المفتاح لمنع هجمات حقن SQL:
▶ مثال: استعلام آمن للمستخدم
PHP
<?php
// ❌ Dangerous: direct SQL concatenation (SQL injection vulnerability)
// $stmt = $pdo->query("SELECT * FROM users WHERE username = '$input'");
// ✅ Safe: prepared statement
$username = $_GET['username'] ?? '';
$sql = "SELECT * FROM users WHERE username = :username";
$stmt = $pdo->prepare($sql);
$stmt->execute(['username' => $username]);
$user = $stmt->fetch();
if ($user) {
echo "Found user: {$user['username']}";
} else {
echo "User not found";
}
?>
(1) إدراج
PHP
<?php
$sql = "INSERT INTO users (username, email, password, age)
VALUES (:username, :email, :password, :age)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'username' => 'Alex',
'email' => 'alex@example.com',
'password' => password_hash('123456', PASSWORD_DEFAULT),
'age' => 24,
]);
$newId = $pdo->lastInsertId();
echo "New user ID: {$newId}";
?>
(2) تحديث
PHP
<?php
$sql = "UPDATE users SET age = :age WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['age' => 27, 'id' => 1]);
echo "Affected {$stmt->rowCount()} row(s)";
?>
(3) حذف
PHP
<?php
$sql = "DELETE FROM users WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => 5]);
echo "Deleted {$stmt->rowCount()} row(s)";
?>
5. تطبيق CRUD الكامل عمليًّا
▶ مثال: صفحة إدارة المستخدمين
PHP
<?php
// Database connection (same as above, omitted for brevity)
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'add') {
$stmt = $pdo->prepare(
"INSERT INTO users (username, email, password, age)
VALUES (:username, :email, :password, :age)"
);
$stmt->execute([
'username' => $_POST['username'],
'email' => $_POST['email'],
'password' => password_hash($_POST['password'], PASSWORD_DEFAULT),
'age' => (int)$_POST['age'],
]);
echo "<p style='color:green'>User added successfully!</p>";
} elseif ($action === 'delete') {
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
$stmt->execute(['id' => (int)$_POST['id']]);
echo "<p style='color:green'>User deleted!</p>";
}
}
// Query all users
$users = $pdo->query("SELECT * FROM users ORDER BY id DESC")->fetchAll();
?>
<h2>User Management</h2>
<table border="1" cellpadding="8">
<tr><th>ID</th><th>Username</th><th>Email</th><th>Age</th><th>Registered</th><th>Actions</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<td><?= $u['id'] ?></td>
<td><?= htmlspecialchars($u['username']) ?></td>
<td><?= htmlspecialchars($u['email']) ?></td>
<td><?= $u['age'] ?></td>
<td><?= $u['created_at'] ?></td>
<td>
<form method="POST" style="display:inline">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $u['id'] ?>">
<button type="submit" onclick="return confirm('Confirm deletion?')">Delete</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</table>
<h3>Add User</h3>
<form method="POST">
<input type="hidden" name="action" value="add">
<input type="text" name="username" placeholder="Username" required>
<input type="email" name="email" placeholder="Email" required>
<input type="password" name="password" placeholder="Password" required>
<input type="number" name="age" placeholder="Age">
<button type="submit">Add</button>
</form>
❓ أسئلة شائعة
س PDO أم MySQLi — أيهما يجب أن أختار؟
ج PDO. فهو يدعم 12 نوعًا من قواعد البيانات (يمكنك التبديل بين قواعد البيانات دون الحاجة إلى إعادة كتابة الكود)، ويتميز ببناء جمل أوامر مُعدة مسبقًا أكثر إيجازًا (
:name المعلمات المسماة)، كما أنه المعيار المقبول لدى مجتمع PHP. أما MySQLi فهو مناسب فقط لصيانة المشاريع القديمة.س ما الفرق بين
fetch() وfetchAll()؟ج تسترد
fetch() صفًا واحدًا في كل مرة (كل استدعاء يُرجع صفًا واحدًا) — وهي مناسبة لمجموعات النتائج الكبيرة. أما fetchAll() فتسترد كل البيانات إلى مصفوفة دفعة واحدة — وهي أبسط، لكنها قد تستهلك قدرًا كبيرًا من الذاكرة في حالة مجموعات البيانات الكبيرة.📖 ملخص
- PDO هي طبقة تجريد قواعد البيانات الموصى بها رسميًا في لغة PHP، وهي تدعم 12 نوعًا من قواعد البيانات
- خيارات الاتصال القياسية الثلاثة: ERRMODE_EXCEPTION / FETCH_ASSOC / EMULATE_PREPARES=false
query()يُنفِّذ أمر SELECT، وfetchAll()يسترد جميع النتائج، وfetch()يسترد نتيجة واحدة- تمنع العبارات المُعدة مسبقًا (الإعداد/التنفيذ) حدوث هجمات حقن SQL
- العناصر النائبة المسماة
:nameأكثر وضوحًا من? lastInsertId()تُرجع معرّف آخر صف تم إدراجه، وrowCount()تُرجع عدد الصفوف المتأثرة
📝 تمارين
- استخدم PDO للاتصال بقاعدة بيانات myblog، واسترجع جميع البيانات من جدول users، وعرضها في جدول.
- قم بإنشاء صفحة تسجيل تحتوي على نموذج لإدخال اسم المستخدم/البريد الإلكتروني/كلمة المرور. استخدم العبارات المعدة مسبقًا في PDO لإضافة المستخدم الجديد (لا تنسَ
password_hash). - أضف زر «حذف» إلى كل صف في الجدول الوارد في التمرين 1. ويجب أن يؤدي النقر عليه إلى حذف سجل المستخدم المقابل.



