انتقل إلى محتوى الدرس
الدرس 81
دورة PHP

إدراج السجلات المفردة والمتعددة وجلب آخر معرف lastInsertId في PDOPDO Inserting Data Batch Inserts and Last Insert ID

أدرج السجلات المفردة والمتعددة في MySQL عبر الاستعلامات المحضرة، واسترجع المعرف التلقائي بـ lastInsertId وعالج القيم المكررة.
أقسام الدرس
6
الأمثلة
6
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
0
محتوى الدرس
في هذا الدرس 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().

مخطط توضيحي: محاكي إدراج السجلات وجلب lastInsertId والمعاملات في PDO
PHP
<?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
<?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
<?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()، ثم تُحفظ السجلات ذرياً دفعة واحدة.

مخطط تدفق التنفيذ العملي لقسم تسريع الإدراج المتعدد داخل معاملة Transaction في لغة PHP
PHP
<?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
<?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 insertbool (check rowCount())Prepare SQL with :named or ?
$pdo->lastInsertId()Get new AUTO_INCREMENT IDstring ID (cast to int)Call on $pdo BEFORE commit()
prepare() + Tx LoopBatch insert (10–10,000 rows)Single disk commitprepare() outside loop; rollBack() on error
$e->getCode() === "23000"Duplicate UNIQUE key trap5-char SQLSTATE stringEnforce UNIQUE index in DB schema

PHP
<?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

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 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

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 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 ويرسلها إلى متصفح العميل بعد التنفيذ.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم إدراج سجل بمعاملات مسماة في PDO للتحقق من المخرجات.

  2. بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم جلب المعرف الجديد عبر lastInsertId وقارن مخرجات التنفيذ.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

8أسئلة 1أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي8 أسئلة تنتظرك
01

على أي كائن يجب استدعاء الدالة lastInsertId() بعد تنفيذ استعلام INSERT المحضر؟

تتبع دالة lastInsertId() الصنف PDO وليس الصنف PDOStatement.

02

ما نوع البيانات الذي تُرجعه الدالة $pdo->lastInsertId() افتراضياً؟

تُرجع PDO المعرف كنص ويمكن تحويله بسهولة إلى عدد صحيح عبر (int).

03

عند إدراج 500 سجل داخل حلقة foreach، ما هو النمط الأسرع والأكثر أماناً في PDO؟

تحضير الاستعلام مرة واحدة مع المعاملة الموحدة يقلل الكتابة للقرص من 500 مرة إلى مرة واحدة.

04

ما رمز SQLSTATE الذي تُرجعه $e->getCode() عند إطلاق PDOException بسبب تكرار قيمة في عمود UNIQUE؟

الرمز "23000" هو الرمز القياسي لمخالفة قيود عدم التكرار والتكامل.

05

عند استخدام معاملة ($pdo->beginTransaction())، متى يجب استدعاء $pdo->lastInsertId()؟

استدعاؤها بعد commit() قد يُرجع "0" في بعض محركات قواعد البيانات.

06

في PHP 8، أي صيغة لمفاتيح المصفوفة مقبولة عند تمريرها إلى $stmt->execute() للاستعلام VALUES (:name, :email)؟

يقبل PDO مفاتيح المعاملات المسماة سواء كُتبت بنقطتين أو بدونهما.

07

ما الدالة في كائن الاستعلام $stmt التي تُرجع عدد الصفوف التي تم إدراجها أو تعديلها أو حذفها؟

تُرجع $stmt->rowCount() عدد الصفوف المتأثرة بعمليات الإدراج أو التحديث أو الحذف.

08

لماذا يجب دائماً كتابة أسماء الأعمدة صراحةً في جملة INSERT INTO users (name, email) بدلاً من تركها ضمنية؟

تحديد الأعمدة صراحةً يحمي الكود عند تطور قاعدة البيانات ويسمح بتعبئة الأعمدة الافتراضية تلقائياً.