مشروع تدريبي — المصفوفات والدوال
لقد أمضيت 14 درسًا في استيعاب قواعد اللغة والوظائف. حان الوقت الآن لربط كل هذه العناصر معًا. ستتيح لك هذه المشاريع الثلاثة — التي تتراوح بين البسيطة والطموحة — إنشاء تطبيقات PHP حقيقية وقابلة للتشغيل.
1. الإعداد
أنشئ مجلدًا باسم practice/ داخل الدليل htdocs/myphp/ وضع جميع ملفات التمارين فيه. يمكنك الوصول إليها من خلال http://localhost/myphp/practice/.
2. المشروع الأول: عربة التسوق
صمم نموذجًا لعربة التسوق باستخدام مصفوفة — أضف العناصر، وقم بتحديث الكميات، وأزل العناصر، واحسب الإجماليات.
PHP
<?php
// cart.php — Shopping Cart System
/**
* Add an item to the cart
* @param array $cart Cart array (by reference)
* @param string $name Product name
* @param float $price Unit price
* @param int $qty Quantity (default: 1)
* @return void
*/
function addItem(array &$cart, string $name, float $price, int $qty = 1): void {
if (isset($cart[$name])) {
$cart[$name]['qty'] += $qty;
} else {
$cart[$name] = ['price' => $price, 'qty' => $qty];
}
}
/**
* Update a product's quantity
*/
function updateQty(array &$cart, string $name, int $qty): void {
if ($qty <= 0) {
unset($cart[$name]);
} elseif (isset($cart[$name])) {
$cart[$name]['qty'] = $qty;
}
}
/**
* Remove an item from the cart
*/
function removeItem(array &$cart, string $name): void {
unset($cart[$name]);
}
/**
* Calculate the total price
*/
function getTotal(array $cart): float {
return array_sum(array_map(
fn($item) => $item['price'] * $item['qty'],
$cart
));
}
// === Test the cart ===
$cart = [];
addItem($cart, "PHP Tutorial", 39.90, 2);
addItem($cart, "MySQL Basics", 29.90, 1);
addItem($cart, "PHP Tutorial", 39.90, 1); // Add one more copy
echo "<pre>";
echo "Cart contents:\n";
print_r($cart);
echo "\nTotal: $" . getTotal($cart) . "\n";
// Update quantity
updateQty($cart, "MySQL Basics", 3);
echo "\nAfter update — Total: $" . getTotal($cart) . "\n";
// Remove an item
removeItem($cart, "PHP Tutorial");
echo "\nAfter removal:\n";
print_r($cart);
echo "\nFinal total: $" . getTotal($cart) . "\n";
echo "</pre>";
?>
💡 نصيحة: تُخزّن سلة التسوق هذه جميع البيانات في الذاكرة — ويؤدي تحديث الصفحة إلى مسح كل شيء. في الدرس 21، بمجرد أن تتعرف على مفهوم «الجلسات»، ستحتفظ سلة التسوق الخاصة بك بالعناصر التي أضفتها حتى عند تحميل الصفحة من جديد.
3. المشروع الثاني: قائمة المهام
إدارة المهام باستخدام مصفوفة — الإضافة، والإنجاز، والحذف، والتصفية حسب الحالة، والفرز حسب الأولوية.
▶ مثال: تطبيق «Todo»
PHP
<?php
// todo.php — To-Do List
/**
* Add a new task
*/
function addTodo(array &$todos, string $title, string $priority = "medium"): void {
$todos[] = [
'id' => count($todos) + 1,
'title' => $title,
'done' => false,
'priority' => $priority,
'created' => date("Y-m-d H:i:s"),
];
}
/**
* Mark a task as complete
*/
function markDone(array &$todos, int $id): void {
foreach ($todos as &$todo) {
if ($todo['id'] === $id) {
$todo['done'] = true;
break;
}
}
}
/**
* Delete a task
*/
function deleteTodo(array &$todos, int $id): void {
$todos = array_filter($todos, fn($t) => $t['id'] !== $id);
}
/**
* Get all pending (incomplete) tasks
*/
function getPending(array $todos): array {
return array_filter($todos, fn($t) => !$t['done']);
}
/**
* Completion statistics
*/
function getStats(array $todos): array {
$total = count($todos);
$done = count(array_filter($todos, fn($t) => $t['done']));
return ['total' => $total, 'done' => $done, 'pending' => $total - $done];
}
// === Test the Todo app ===
$todos = [];
addTodo($todos, "Learn PHP arrays", "high");
addTodo($todos, "Practice foreach loops", "medium");
addTodo($todos, "Write the cart functions", "high");
addTodo($todos, "Review date functions", "low");
markDone($todos, 1);
markDone($todos, 3);
$stats = getStats($todos);
echo "Total: {$stats['total']} | Done: {$stats['done']} | Pending: {$stats['pending']}<br>";
echo "<h3>Pending Tasks</h3>";
foreach (getPending($todos) as $todo) {
$priorityEmoji = [
'high' => '🔴',
'medium' => '🟡',
'low' => '🟢',
];
echo $priorityEmoji[$todo['priority']] . " {$todo['title']}<br>";
}
?>
4. المشروع الثالث: استطلاع بسيط
استخدم مصفوفة ترابطية لتخزين الخيارات وعدد الأصوات، مع توفير إمكانية التصويت وعرض النتائج والفرز حسب عدد الأصوات.
▶ مثال: نظام التصويت
PHP
<?php
// vote.php — Simple Poll
function createPoll(array $options): array {
return array_fill_keys($options, 0);
}
function vote(array &$poll, string $option): bool {
if (!array_key_exists($option, $poll)) {
return false;
}
$poll[$option]++;
return true;
}
function getResults(array $poll): array {
arsort($poll); // Sort by vote count descending
return $poll;
}
function getTotalVotes(array $poll): int {
return array_sum($poll);
}
function getWinner(array $poll): ?string {
$results = getResults($poll);
$maxVotes = max($results);
if ($maxVotes === 0) return null;
return array_key_first($results);
}
// === Test the poll ===
$poll = createPoll(["PHP", "Python", "JavaScript", "Go", "Rust"]);
vote($poll, "PHP");
vote($poll, "PHP");
vote($poll, "JavaScript");
vote($poll, "Python");
vote($poll, "PHP");
vote($poll, "Rust");
vote($poll, "Python");
echo "<h3>Poll Results</h3>";
echo "Total votes: " . getTotalVotes($poll) . "<br>";
$results = getResults($poll);
foreach ($results as $lang => $votes) {
$percent = round($votes / getTotalVotes($poll) * 100, 1);
$bar = str_repeat("█", $votes);
echo "{$lang}: {$bar} {$votes} vote(s) ({$percent}%)<br>";
}
echo "<br>🏆 Leader: " . getWinner($poll) . "<br>";
?>
5. التأمل: من البرامج النصية إلى التطبيقات
تُبرز هذه المشاريع الثلاثة عدة أفكار رئيسية:
- المصفوفات لا تقتصر على تخزين البيانات فحسب — بل يمكنها أيضًا تمثيل منطق الأعمال الفعلي.
- الدوال تعمل على تغليف العمليات، مما يضمن بقاء الكود نظيفًا وقابلًا للتركيب.
- التمرير بالمرجع (
&$arr) يتيح للدوال تعديل هياكل البيانات مباشرةً. array_map+ الدوال السهمية تجعل معالجة البيانات موجزة وسهلة القراءة.
لكنك ربما لاحظت أيضًا أوجه القصور التالية:
- تُخزَّن جميع البيانات في الذاكرة — وتُحذف عند تحديث الصفحة. (تم حل هذه المشكلة لاحقًا باستخدام الجلسات / قواعد البيانات.)
- يختلط الكود مع العرض. (تم حل هذه المشكلة لاحقًا باستخدام بنية MVC.)
- لا يوجد تفاعل مع النماذج حتى الآن. (هذا موضوع الدرس التالي.)
❓ أسئلة شائعة
س لماذا نستخدم مصفوفة مرتبطة لعربة التسوق بدلاً من مصفوفة مفهرسة؟
ج تستخدم المصفوفات المرتبطة اسم المنتج كمفتاح، مما يتيح إجراء عمليات البحث والتحديث بسرعة O(1). أما المصفوفة المفهرسة فتتطلب مسحًا للبحث عن العناصر، وهو ما يصبح بطيئًا مع تزايد حجم عربة التسوق.
س ما وظيفة
array_fill_keys؟ج
array_fill_keys(['a', 'b'], 0) تُرجع ['a' => 0, 'b' => 0] — فهي تُعيّن نفس القيمة لعدة مفاتيح في استدعاء واحد. نستخدمها في نظام الاستطلاع لتهيئة كل خيار بحيث يكون عدد الأصوات عليه صفرًا.س هل ستبقى البيانات محفوظة بين عمليات تحميل الصفحات؟
ج لا — فالتحديث يؤدي إلى مسح كل شيء. وهذه هي طبيعة لغة PHP «الخالية من الحالة». في الدرس 21، ستتعرف على «الجلسات» (Sessions)، التي تتيح الاحتفاظ ببيانات سلة التسوق عبر الطلبات المختلفة ضمن نفس جلسة المستخدم.
📖 ملخص
- سلة التسوق: المصفوفات الترابطية + التمرير بالمرجع + تتبع الكمية
- قائمة المهام: المصفوفات متعددة الأبعاد +
array_filterللتصفية + الإحصاءات - استطلاع الرأي:
array_fill_keysللتعيين الأولي +arsortللترتيب +array_key_first - إن فهم القيد المتمثل في "عدم وجود حالة" يبرز الحاجة إلى الجلسات وقواعد البيانات
📝 تمارين
- قم بتوسيع سلة التسوق لتشمل 5 منتجات على الأقل، ثم أضف وظيفة
clearCart()التي تعمل على إزالة كل المحتويات. - إضافة خيار «الترتيب حسب الأولوية» (عالية → متوسطة → منخفضة) إلى نظام قائمة المهام.
- إضافة آلية لمنع التزوير في الاقتراع: التحقق من وجود الخيار قبل احتساب الصوت، ورفض الخيارات غير الصالحة.



