في هذا الدرس 6تصفّح المواضيع
أدرج دائماً البيانات القادمة من المستخدم عبر استعلام محضر بالمعاملات المسماة (:name و:email) وتمرير مصفوفة القيم إلى $stmt->execute([...]).
- اذكر أسماء الأعمدة صراحةً في
INSERT INTO table (col1, col2) VALUES (:col1, :col2)حتى لا تتأثر عملية الإدراج عند إضافة أعمدة جديدة للجدول. - في PHP 8، لا يشترط كتابة النقطتين في مفاتيح مصفوفة
$stmt->execute()؛ فالمفتاح["name" => "Ali"]يرتبط تلقائياً بالمعامل:name. - استدعِ
$stmt->rowCount()بعد التنفيذ للتحقق من إدراج سجل واحد بنجاح.
يُحضَّر هيكل جملة SQL مرة واحدة عبر prepare()، وتُربط قيم المصفوفة الترابطية بأمان تام عبر execute().
<?php
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)');
$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute([
'name' => 'Maha Al-Harbi',
'email' => '[email protected]',
]);
echo "Inserted rows: " . $stmt->rowCount() . "\n";
فور إدراج سجل جديد في جدول يمتلك مفتاحاً أساسياً متزايداً تلقائياً، استدعِ الدالة $pdo->lastInsertId() على كائن الاتصال.
- انتبه إلى أن
lastInsertId()تُستدعى على كائن الاتصال$pdoوليس على كائن الاستعلام المحضر$stmt. - تُرجع الدالة المعرف الجديد كنص
string(مثل"1")، ويمكنك تحويله لعدد صحيح عبر(int) $pdo->lastInsertId(). - بما أن المعرف مرتبط بجلسة الاتصال الحالية فقط، فلن تتداخل أرقام
lastInsertId()أبداً بين الزوار المتزامنين.
تحويل النتيجة عبر (int) $pdo->lastInsertId() يمنحك المعرف كعدد صحيح جاهز للربط مع السجلات الفرعية مثل تفاصيل الطلب.
<?php
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY AUTOINCREMENT, total REAL)');
$stmt = $pdo->prepare('INSERT INTO orders (total) VALUES (:total)');
$stmt->execute(['total' => 380.00]);
$newOrderId = (int) $pdo->lastInsertId();
echo "New Order ID: $newOrderId (" . gettype($newOrderId) . ")\n";
عند إدراج عدة سجلات داخل حلقة تكرار، استدعِ $pdo->prepare() مرة واحدة فقط خارج الحلقة، ونفذ $stmt->execute($row) داخل الحلقة.
- تحضير جملة SQL مرة واحدة يتيح لمحرك قاعدة البيانات تحليل الاستعلام وبناء خطة التنفيذ مرة واحدة فقط.
- في كل دورة داخل حلقة
foreachيتم إرسال القيم الجديدة فقط دون إعادة تحليل نص الاستعلام. - تجنب استدعاء
$pdo->prepare()داخل الحلقة لأن ذلك يكرر عبء التحليل مع كل سجل.
استدعاء prepare() مرة واحدة قبل حلقة foreach يدرج الوسوم الثلاثة بكفاءة عالية.
<?php
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE tags (id INTEGER PRIMARY KEY, slug TEXT)');
$stmt = $pdo->prepare('INSERT INTO tags (slug) VALUES (:slug)');
foreach (['php-84', 'pdo-sql', 'security'] as $slug) {
$stmt->execute(['slug' => $slug]);
}
$total = $pdo->query('SELECT COUNT(*) FROM tags')->fetchColumn();
echo "Total inserted tags: $total\n";
افتراضياً، تعمل قواعد البيانات بوضع الاعتماد التلقائي وتكتب للقرص بعد كل عملية INSERT؛ لذا فإن إحاطة الإدراج الجماعي بمعاملة (Transaction) يضمن الذرية ويسرّع الأداء عشرات المرات.
- ابدأ المعاملة قبل الحلقة عبر
$pdo->beginTransaction()، واعتمد التغييرات دفعة واحدة بعد انتهاء الحلقة عبر$pdo->commit(). - أحِط الحلقة بكتلة
try / catch (Throwable $e)واستدعِif ($pdo->inTransaction()) { $pdo->rollBack(); }للتراجع الكامل إذا فشل أي صف. - تنبيه مهم: استدعِ
$pdo->lastInsertId()قبل استدعاء$pdo->commit()، لأن بعض المحركات تصفر المعرف بعد الاعتماد.
تُنفذ عمليات الإدراج الثلاث داخل معاملة واحدة، ويُلتقط $lastId قبل commit()، ثم تُحفظ السجلات ذرياً دفعة واحدة.
<?php
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE items (id INTEGER PRIMARY KEY, code TEXT NOT NULL)');
$pdo->beginTransaction();
$stmt = $pdo->prepare('INSERT INTO items (code) VALUES (:code)');
foreach (['A-10', 'B-20', 'C-30'] as $c) {
$stmt->execute(['code' => $c]);
}
$lastId = (int) $pdo->lastInsertId();
$pdo->commit();
echo "Batch committed! Last ID: $lastId\n";
عندما يخالف أمر INSERT قيد عدم التكرار UNIQUE (مثل بريد إلكتروني مسجل مسبقاً)، يطلق PDO استثناء PDOException برمز الحالة القياسي "23000".
- على عكس معظم الاستثناءات في PHP، تُرجع
PDOException::getCode()نصاً مكوناً من 5 محارف يمثل رمز SQLSTATE مثل"23000". - افحص الشرط
$e->getCode() === "23000"لعرض رسالة تنبيه واضحة للمستخدم ("هذا البريد مسجل بالفعل"). - إذا كان رمز الخطأ مختلفاً عن
"23000"، أعد إطلاق الاستثناء (throw $e;) ليتم تسجيل أخطاء النظام غير المتوقعة.
محاولة إدراج البريد [email protected] للمرة الثانية تطلق PDOException بالرمز "23000"، فيتم التقاطه ومعالجته بأمان.
<?php
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT UNIQUE)');
$stmt = $pdo->prepare('INSERT INTO users (email) VALUES (:email)');
$stmt->execute(['email' => '[email protected]']);
try {
$stmt->execute(['email' => '[email protected]']);
} catch (PDOException $e) {
$msg = ($e->getCode() === '23000') ? 'Duplicate email blocked' : 'Other error';
echo "$msg (SQLSTATE " . $e->getCode() . ")\n";
}
اختر نمط الإدراج في PDO بناءً على عدد السجلات ومستوى الذرية المطلوب في ميزة تطبيقك.
- استخدم استعلاماً محضراً مفرداً مع
lastInsertId()لإرسال النماذج المعتادة مثل إنشاء حساب أو إضافة تعليق. - استخدم الاستعلام المحضر داخل معاملة
beginTransaction() / commit()عند إدراج فاتورة رئيسية مع عدة بنود تابعة لها. - التقط دائماً الرمز
"23000"في الجداول التي تحتوي على أعمدةUNIQUEبدلاً من الاعتماد فقط على استعلامSELECTمسبق.
تعمل المعاملات الموضعية (?) أيضاً بسلاسة عند تمرير مصفوفة مفهرسة إلى $stmt->execute([...]).
| النمط / الدالة | أفضل حالة استخدام | قيمة الإرجاع / السلوك | القاعدة الحرجة |
|---|---|---|---|
$stmt->execute($data) | Single safe row insert | bool (check rowCount()) | Prepare SQL with :named or ? |
$pdo->lastInsertId() | Get new AUTO_INCREMENT ID | string ID (cast to int) | Call on $pdo BEFORE commit() |
prepare() + Tx Loop | Batch insert (10–10,000 rows) | Single disk commit | prepare() outside loop; rollBack() on error |
$e->getCode() === "23000" | Duplicate UNIQUE key trap | 5-char SQLSTATE string | Enforce UNIQUE index in DB schema |
<?php
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE logs (id INTEGER PRIMARY KEY, msg TEXT)');
$stmt = $pdo->prepare('INSERT INTO logs (msg) VALUES (?)');
$stmt->execute(['User logged in']);
echo "ID: " . $pdo->lastInsertId() . " | Rows: " . $stmt->rowCount() . "\n";
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
اختر نمط الإدراج في PDO بناءً على عدد السجلات ومستوى الذرية المطلوب في ميزة تطبيقك. استخدم استعلاماً محضراً مفرداً مع lastInsertId() لإرسال النماذج المعتادة مثل إنشاء حساب أو إضافة تعليق. استخدم الاستعلام المحضر داخل معاملة beginTransaction() / commit() عند إدراج فاتورة رئيسية مع عدة بنود تابعة لها. التقط دائماً الرمز "23000" في الجداول التي تحتوي على أعمدة UNIQUE بدلاً من الاعتماد فقط على استعلام SELECT مسبق.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 PDO Insert & Last ID الإدراج و lastInsertId
- أدرج السجلات المفردة والمتعددة في MySQL عبر الاستعلامات المحضرة، واسترجع المعرف التلقائي بـ lastInsertId وعالج القيم المكررة.
- للمراجعة
- 02 Inserting a Row with Named Placeholders إدراج سجل بمعاملات مسماة في PDO
- المفهوم الأساسي لقسم إدراج سجل بمعاملات مسماة في PDO في لغة PHP الحديثة.
- للمراجعة
- 03 Retrieving New ID with lastInsertId جلب المعرف الجديد عبر lastInsertId
- الصياغة البرمجية والتطبيق العملي المباشر لقسم جلب المعرف الجديد عبر lastInsertId.
- للمراجعة
- 04 Reusing Statements for Batch Inserts إدراج سجلات متعددة بإعادة تنفيذ الاستعلام
- قواعد التحقق وأفضل الممارسات القياسية الخاصة بقسم إدراج سجلات متعددة بإعادة تنفيذ الاستعلام.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 PHP PHP
- PHP: Hypertext Preprocessor
- لغة البرمجة النصية على جانب الخادم لبناء تطبيقات الويب الديناميكية وواجهات البرمجة.
- للمراجعة
- 02 CLI CLI
- Command-Line Interface
- واجهة سطر الأوامر التي تتيح تشغيل ملفات PHP مباشرة عبر الطرفية.
- للمراجعة
- 03 FPM FPM
- FastCGI Process Manager
- مدير عمليات FastCGI عالي الأداء لمعالجة طلبات خادم الويب في PHP.
- للمراجعة
- 04 HTML HTML
- HyperText Markup Language
- لغة الترميز القياسية التي يولدها محرك PHP ويرسلها إلى متصفح العميل بعد التنفيذ.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم إدراج سجل بمعاملات مسماة في PDO للتحقق من المخرجات.
-
بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم جلب المعرف الجديد عبر lastInsertId وقارن مخرجات التنفيذ.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي8 أسئلة تنتظرك +
على أي كائن يجب استدعاء الدالة lastInsertId() بعد تنفيذ استعلام INSERT المحضر؟
تتبع دالة lastInsertId() الصنف PDO وليس الصنف PDOStatement.
ما نوع البيانات الذي تُرجعه الدالة $pdo->lastInsertId() افتراضياً؟
تُرجع PDO المعرف كنص ويمكن تحويله بسهولة إلى عدد صحيح عبر (int).
عند إدراج 500 سجل داخل حلقة foreach، ما هو النمط الأسرع والأكثر أماناً في PDO؟
تحضير الاستعلام مرة واحدة مع المعاملة الموحدة يقلل الكتابة للقرص من 500 مرة إلى مرة واحدة.
ما رمز SQLSTATE الذي تُرجعه $e->getCode() عند إطلاق PDOException بسبب تكرار قيمة في عمود UNIQUE؟
الرمز "23000" هو الرمز القياسي لمخالفة قيود عدم التكرار والتكامل.
عند استخدام معاملة ($pdo->beginTransaction())، متى يجب استدعاء $pdo->lastInsertId()؟
استدعاؤها بعد commit() قد يُرجع "0" في بعض محركات قواعد البيانات.
في PHP 8، أي صيغة لمفاتيح المصفوفة مقبولة عند تمريرها إلى $stmt->execute() للاستعلام VALUES (:name, :email)؟
يقبل PDO مفاتيح المعاملات المسماة سواء كُتبت بنقطتين أو بدونهما.
ما الدالة في كائن الاستعلام $stmt التي تُرجع عدد الصفوف التي تم إدراجها أو تعديلها أو حذفها؟
تُرجع $stmt->rowCount() عدد الصفوف المتأثرة بعمليات الإدراج أو التحديث أو الحذف.
لماذا يجب دائماً كتابة أسماء الأعمدة صراحةً في جملة INSERT INTO users (name, email) بدلاً من تركها ضمنية؟
تحديد الأعمدة صراحةً يحمي الكود عند تطور قاعدة البيانات ويسمح بتعبئة الأعمدة الافتراضية تلقائياً.