بسم الله الرحمن الرحيم
سوف نناقش هذه السلسلة ان شاء الله علي عدة حلقات لأنه موضوع يطول شرحه , وهو موضوع لا يختص بشرح أساسيات ال php
وأرجو التأكيد علي أهمية هذا الموضوع لمبرمجي الويب عامة (php أو asp أو jsp أو perl إلخ ) , إلا أني سوف أقتصر الشرح بالأمثلة علي لغة البي أتش بي php
ملاحظة :
من لديه الرغبة أن يضيف اي معلومة في هذا الموضوع لم أقم بشرحها أو اي شئ من هذا القبيل , فالباب مفتوح للجميع حتي تعم الفائدة .
المتطلبات التي يجب توافرها في من سوف يتابع هذه السلسلة :
- أن يملك فكر برمجي بشكل عام ويفضل (ولا يلزم ) مبرمجي الويب
- يعرف أساسيات البرمجة بال php
- يملك أساسيات البرمجة الكائنية object oriented
لكن ما هي Design Patterns أو أنماط التصاميم البرمجية وما أهمية هذا الموضوع
تعريف أنماط التصاميم البرمجية Desgin Patterns :
ممكن أن نعرفها بشكل مبسط أنها أساليب وأفكار برمجية تم التعارف عليها بين المبرمجين
وهي تختص بعرض حلول بشكل جيد للمشاكل البرمجية , كما سوف نري فيما بعد
وهي لا تختص لمبرمجي الويب فقط بل للمبرمجين بشكل عام , لذلك أرجو لمن سوف يتابع هذه السلسلة من المبرمجين غير مبرمجي الويب
أن يحاول أن يستخلص إسلوب هذا الفكر ولا يهمل الموضوع , ولولا ضيق الوقت لأفردت دروس خاصة لمبرمجي ال DotNet والجافا .
أهمية هذه السلسلة :
سوف تعطي مطوري الويب الإسلوب الصحيح لتطوير مشاريعهم وطرق إتخاذهم للقرار في اي الطرق أفضل لإتمام مهمة ما .
سوف نبدء بإذن الله تعالي بشرح النمط الأول , توكلت علي الله
الحلقة الأولي : Singleton Pattern
يتم تطبيق هذا النمط عندما نريد عمل كائن واحد single instance ويكون علي هيئة متغير عام مشترك shared global variable
لكن ما هي الحاجة لعمل ذلك ؟
ربما تواجه حالات تحتاج فيها للتوفير في إستهلاك موارد الجهاز resources ( مثلا مثل الذاكرة memory )
لذلك تلجأ إلي عمل متغير ما يكون مشترك shared بين عمليات أخري , ومن أهم هذه الحالات (وبالطبع يوجد حالات أخري)
عندما نريد التعامل مع الحالات التالية
- ربما عندما نريد أن نفتح ملف ما للقراءة أو الكتابة ويكون هذا الملف دائم الإستخدام , كما هو الحال مع ملفات المتابعة log files.
- عند إجراء إتصال بقاعدة بيانات ما , فلتجنب إجهاد محرك قاعدة البيانات database engine وأيضا لتجنب إستهلاك الذاكرة
يفضل عمل إتصال واحد يكون عام ومشترك للإستخدام لجميع العمليات التي تتم علي قاعدة البيانات , دون اللجوء إلي فتح إتصال جديد بقاعدة البيانات كلما نريد تنفيذ أمرا ما علي قاعدة البيانات
ملاحظة : قد تم الإلتفات إلي هذه الحالة في ال php وهي الأن لا تسبب مشكلة ولا داعي لإستخدام نمط singleton
لأن دوال التعامل مع قواعد البيانات معظمها الأن يوفر الإتصال المستمر persistent connection , كما هو الحال مثلا عند إستخدام الدالة mysql_pconnect
وكما نعلم أن وظيفة الدالة mysql_pconnect يكافئ الدالة mysql_connect ولكن تختلف في التالي :
+ أنه عند طلب إجراء فتح إتصال جديد بقاعدة البيانات يتم البحث أولا علي إتصال موجود بالفعل يحمل نفس خصائص الإتصال المراد فتحه ( اسم السيرفر المضيف host واسم مستخدم قاعدة البيانات وكلمة المرور الخاصة به)
فإذا وجد إتصال مماثل يتم إستخدامه دون اللجوء إلي عمل إتصال جديد .
+ لذلك لن يتم إغلاق هذا الإتصال بعد تنفيذ اي أمر علي قاعدة البيانات
بالإضافة إلي أنه أيضا لن يتم إغلاق الإتصال (الذي تم فتحه من خلال mysql_pconnect ) حتي عند إستدعاء الدالة mysql_close .
لاحظ أن التعامل مع السيشن session هو مثال حي لتطبيق مفهوم singleton pattern
مثال تطبيقي لتوضيح هذا النمط
نريد تصميم صفحة تقوم بجلب وعرض بيانات المنتجات products من جدول المنتجات التالي
# # Table structure for table `products` # CREATE TABLE products ( PRODUCTID int(11) NOT NULL auto_increment, PRODUCTNAME varchar(255) NOT NULL default '', UNITPRICE varchar(255) NOT NULL default '', UNITSINSTOCK varchar(255) NOT NULL default '', DISCONTINUED varchar(255) NOT NULL default '', PRIMARY KEY (PRODUCTID) ) TYPE=MyISAM; # # Dumping data for table `products` # INSERT INTO products VALUES (1, 'Chai', '18', '39', '0'); INSERT INTO products VALUES (2, 'Chang', '19', '17', '0'); INSERT INTO products VALUES (3, 'Aniseed Syrup', '10', '13', '0'); INSERT INTO products VALUES (4, 'Chef Antons Cajun Seasoning', '22', '53', '0'); INSERT INTO products VALUES (5, 'Chef Anton Gumbo Mix', '21.35', '0', '1'); INSERT INTO products VALUES (6, 'Grandma Boysenberry Spread', '25', '120', '0'); INSERT INTO products VALUES (7, 'Uncle Bob Organic Dried Pears', '30', '15', '0'); INSERT INTO products VALUES (8, 'Northwoods Cranberry Sauce', '40', '6', '0'); INSERT INTO products VALUES (9, 'Mishi Kobe Niku', '97', '29', '1'); INSERT INTO products VALUES (10, 'Ikura', '31', '31', '0');
بافتراض أننا لا نملك أوامر الإتصال المستمر بقاعدة البيانات
الحل:
- كما أشرنا من قبل أن إجراء عملية فتح إتصال جديد بقاعدة البيانات , هو أمر مكلف في وقت التنفيذ وإستهلاك في الذاكرة
- لذلك نحتاج لعمل إتصال واحد فقط بحيث يمكننا إستخدامه كلما إستدعت الحاجة لذلك
سنقوم بعمل صفحة باسم Connection.php تحتوي علي الفئة Connection
التي تحتوي الدالة getConnection الخاصة لإرجاع معرف الإتصال بقاعدة البيانات
كما يلي
<?
class Connection {
/**
* getConnection
*
* get only one object refere to link identifier resource
* to avoid multi-connection open
*
* @return link identifier
*/
function getConnection() {
static $conn;
if( !isset($conn) ) {
echo "<h1>Singleton Object Created</h1>";
$conn = mysql_connect("localhost","root","");
mysql_select_db("test", $conn);
}
return $conn;
}
}
?>تكمن الفكرة كما نلاحظ بالكود السابق في تعريف متغير ساكن static variable بداخل الدالة getConnection باسم conn كما يلي
function getConnection() {
static $conn;وهذا المتغير يتم الإحتفاظ بقيمة حتي بعد إنتهاء تنفيذ الدالة ولا يتم تدميره لأنه لا يعتبر متغير محلي local variable
ثم نقوم بعمل صفحة باسم Products.php الخاصة بعرض بيانات المنتجات
كما يلي
<?
include_once "Connection.php";
?>
<h1>product List</h1>
<?
$sql = "select * from products limit 10";
$rs = mysql_query($sql, Connection::getConnection() );
while( $row = mysql_fetch_array($rs) ) {
echo $row["PRODUCTID"] . " : " . $row["PRODUCTNAME"] . "<br>";
}
?>
<?
$sql = "select * from products limit 10,5";
$rs = mysql_query($sql, Connection::getConnection() );
while( $row = mysql_fetch_array($rs) ) {
echo $row["PRODUCTID"] . " : " . $row["PRODUCTNAME"] . "<br>";
}
?>كما هو ملاحظ بالمثال فقد قمنا بتنفيذ جملتين إستعلام علي نفس قاعدة البيانات دون اللجوء إلي فتح أكثر من إتصال
إستنادا علي الدالة getConnection الموجودة بالفئة Connection الموجودة بالملف Connection.php
وهو مثال بسيط لتوضيح الفكرة فقط , أرجو أن يكون هذا المثال واضح
_______________________________________________________________________
كيف يمكننا تطبيق نمط Singleton في الإصدار الخامس php5:
تم تحسين هذه النسخة بوضع إمكانية عمل أعضاء ساكنة static members بفئة ما
وبذلك يمكننا تطبيق نمط ال Singleton بشكل أفضل كما يلي
سوف نعيد المثال السابق ولكن علي الإصدار الجديد php5
وسوف نعدل فقط الملف Connection.php
<?
class Connection {
private static $conn = null;
/**
* getConnection
*
* get only one object refere to link identifier resource
* to avoid multi-connection open
*
* @return link identifier
*/
public static function getConnection() {
if( self::$conn == null ) {
echo "<h1>Singleton Object Created</h1>";
self::$conn = mysql_connect("localhost","root","");
mysql_select_db("test", self::$conn);
}
return self::$conn;
}
}
?>كما نلاحظ فقد قمنا بتعريف عضو ساكن بالفئة Connection باسم conn كما يلي
<?
class Connection {
private static $conn = null;وهذا المتغير يحتفظ بقيمة دائما أثناء تنفيذ البرنامج (ولا يرتبط بالكائنات التي يتم إنشائها من هذه الفئة , لذلك يطلق علي الأعضاء الساكنه باسم Class Members اي أعضاء الفئة)
إلي اللقاء بإذن الله مع نمط جديد
وبالله التوفيق
والسلام عليكم ورحمة الله وبركاته
