عمليات قاعدة البيانات 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() فتسترد كل البيانات إلى مصفوفة دفعة واحدة — وهي أبسط، لكنها قد تستهلك قدرًا كبيرًا من الذاكرة في حالة مجموعات البيانات الكبيرة.

📖 ملخص

📝 تمارين

  1. استخدم PDO للاتصال بقاعدة بيانات myblog، واسترجع جميع البيانات من جدول users، وعرضها في جدول.
  2. قم بإنشاء صفحة تسجيل تحتوي على نموذج لإدخال اسم المستخدم/البريد الإلكتروني/كلمة المرور. استخدم العبارات المعدة مسبقًا في PDO لإضافة المستخدم الجديد (لا تنسَ password_hash).
  3. أضف زر «حذف» إلى كل صف في الجدول الوارد في التمرين 1. ويجب أن يؤدي النقر عليه إلى حذف سجل المستخدم المقابل.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%