معالجة البيانات الضخمة باستخدام PHP: من الأسطورة إلى مشروع حقيقي

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

PHP وBig Data: ليس تناقضًا، بل واقع



عندما تسمع "معالجة البيانات الضخمة"، أول ما يتبادر إلى الذهن هو Spark أو Hadoop أو Python مع Pandas. PHP في هذه القائمة يُنظر إليه عادةً على أنه "لغة للمواقع البسيطة والمنتديات". لكن دعونا نواجه الحقيقة: إذا كان مشروعك يعمل بالفعل على PHP، فإن إعادة كتابته بالكامل بلغة Go من أجل مهمة واحدة لمعالجة ملف CSV بحجم جيجابايت هو بمثابة إطلاق مدفع على عصفور.



PHP يتعامل بشكل ممتاز مع Big Data إذا تم التعامل مع الأمر بذكاء. في هذه المقالة، سنستعرض التقنيات الحقيقية: كيف لا تقتل الخادم أثناء العمل مع ملفات بحجم 10+ جيجابايت، وكيفية معالجة ملايين الصفوف من قاعدة البيانات دون out of memory، وكيفية تحويل PHP إلى خط أنابيب بيانات حقيقي. بدون حشو، فقط كود وحلول معمارية.



لماذا PHP "لا يحب" البيانات الضخمة (وكيفية إصلاح ذلك)



المشكلة الرئيسية في PHP في سياق Big Data هي نموذج التنفيذ الخاص به. يتم تنفيذ السكريبت بشكل تسلسلي، محملاً كل شيء في الذاكرة. جرب استخدام file_get_contents() على ملف بحجم 5 جيجابايت - سينهار الخادم ببساطة.



لكن هناك خبر سار: PHP يحتوي على آليات مدمجة للمعالجة التدفقية. كل ما عليك فعله هو نسيان الطرق "البدائية" مثل file() أو file_get_contents() والانتقال إلى المولدات والتدفقات واستعلامات التجزئة.



المولدات: أداتك الرئيسية



المولدات (الكلمة المفتاحية yield) تسمح بإرجاع البيانات عنصرًا عنصرًا، دون تحميل المجموعة بأكملها في الذاكرة. هذا مثالي لقراءة الملفات الكبيرة أو الاستعلامات من قاعدة البيانات.



مثال: قراءة ملف CSV بحجم 5 جيجابايت سطرًا سطرًا دون استنزاف الذاكرة:



<?phpfunction readLargeCSV(string $filePath): Generator{    $handle = fopen($filePath, 'r');    if ($handle === false) {        throw new RuntimeException("فشل فتح الملف: $filePath");    }

// تخطي BOM إذا كان موجودًا $bom = fread($handle, 3); if ($bom !== "\\xEF\\xBB\\xBF") { rewind($handle); // إذا لم يكن BOM موجودًا، نعود إلى البداية }

while (($row = fgetcsv($handle, 0, ',')) !== false) { yield $row; }

fclose($handle);}

// الاستخدامforeach (readLargeCSV('/data/orders_2024.csv') as $index => $row) { // معالجة كل سطر على حدة if ($index === 0) { continue; // تخطي العنوان } processOrder($row);}?>


لماذا يعمل هذا؟ المولد لا يقوم بتحميل الملف بأكمله في مصفوفة. يقرأ سطرًا واحدًا - يعيده - يقرأ السطر التالي. يبقى استهلاك الذاكرة عند مستوى بضعة كيلوبايتات، بغض النظر عن حجم الملف.



العمل مع قواعد البيانات الكبيرة: استعلامات التجزئة



إذا كنت بحاجة لمعالجة 5 ملايين سجل من MySQL، لا تحاول استخدام SELECT * FROM table - فهذا سيقتل قاعدة البيانات وPHP معًا. بدلاً من ذلك، استخدم المؤشرات أو استعلامات التجزئة.



إليك النهج الصحيح باستخدام PDO وتكرار التجزئة:



<?phpfunction processLargeTable(PDO $pdo, int $chunkSize = 1000, callable $callback): void{    $offset = 0;    $lastId = 0;

// استخدام ORDER BY id للاستقرار $stmt = $pdo->prepare("SELECT * FROM orders WHERE id > :lastId ORDER BY id LIMIT :limit");

do { $stmt->execute(['lastId' => $lastId, 'limit' => $chunkSize]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

if (empty($rows)) { break; }

foreach ($rows as $row) { $callback($row); $lastId = $row['id']; // تذكر آخر ID تمت معالجته }

// تحرير الذاكرة unset($rows); $stmt->closeCursor();

} while (true);}

// الاستخدام$pdo = new PDO('mysql:host=localhost;dbname=big_data', 'user', 'pass');$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

p

المدونات

توصيات الكتب