מדריך PHP: תכנות מונחה עצמים – פולימורפיזם, overloading ומתודות קסם
פולימורפיזם הוא בעצם שימוש באותה מתודה לביצוע דברים כאשר מה שאנו עושים באמצעות המתודה משתנה בהתאם למשתנים שלנו (בהתאם לסוג שלהם או למספר שלהם). למשל בשפת C הפונקציה הפולימורפית (sum(int, int היא פונקציה שעובדת באופן שונה מ: (sum(float, float – מה שהפונקציה עושה נקבע לפי הפרמטרים.
ב-PHP למרבה הצער אין לנו יכולת לעשות את זה, וגם (למי שמכיר) אין לנו כרגע יכולת לבצע late binding, כך שהיכולות שלנו בנושא פולימורפיזם הן כרגע (לפחות בגרסת PHP5.3 ) יותר מוגבלות משפות אחרות. למרות זאת, פולימורפיזם הוא חשוב ואני כן אתייחס אליו.
פולימורפיזם הוא לאו דווקא איזו פקודה אלא יותר טכניקה המורכבת מכל הפקודות שלמדנו עד עכשיו. פולימורפיזם הוא שם מסובך למשהו שהוא יחסית פשוט – אכיפה של interface אחד על מספר class על מנת להמנע מ-class אחד שעושה הכל עם משפטי תנאי משונים.
אנחנו יכולים להשתמש ב-abstract class או ב-interface על מנת לקחת class אחד וליצור לו פונקציונליות שונה בהתאם ל-class שהוא יורש ממנו תוך כדי שאנו אוכפים אותו מבנה ואותו שם:
<?php interface my_interface { public function hello($arg1, $arg2, $date); } class a { public function hello($arg1, $arg2, $date) { return "$arg1 $arg2 in $date"; } } class b extends a implements my_interface{ public function hello($arg1, $arg2, $date) { a::hello($arg1, $arg2, date('Y-M-j')); } } class c extends a implements my_interface{ public function hello($arg1, $arg2, $date) { return 'I am C and I don't care about stupid arg'; } } $a = new a(); print $a->hello('hello','world', date('Y-M-j')); $c = new c(); print $c->hello('hello','world', date('Y-M-j'));
כאן למשל אנו משתמשים במתודת hello אך היא משתנה בהתאם להקשר, הייתי יכול במקום זה לכתוב קוד גרוע ב-class a שבו אני מבצע תנאי ומחזיר פלט בהתאם למשתנה נוסף שהייתי דוחף שם, אבל זה יותר אלגנטי.
למרבה הצער, פולימורפיזם אמיתי כרגע אין ב-PHP, אני מקווה שבגרסאות הבאות יהיה.
Overloading
Overloading ב-PHP מאפשר לנו ליצור מתודות ותכונות באובייקט מסוים, on the fly לפי הצורך. אנו עושים זאת באמצעות שימוש במתודות מיוחדות שנקראות 'מתודות קסם' (Magic methods).
בואו ונניח שיש לי class בשם class a חביב. יכול להיות שיש בו מתודות ותכונות ואין שום בעיה עם זה. נניח ואני רוצה להוסיף לו, בזמן הריצה, איזו תכונה חביבה וחדשה. הכיצד?
את זה אפשר לעשות באמצעות מתודת הקסם המופלאה __set (כל מתודות הקסם מתחילות ב__). המתודה הזו מופעלת בכל פעם שאני מוסיף תכונה כלשהי. אני יכול לעשות עם set כל מה שבא לי, אבל שימו לב בבקשה למה ש-__set עושה במקרה הזה:
<?php class a { private $data = array(); public function __set($name, $value) { print "Setting '$name' to '$value'"; $this->data[$name] = $value; } }
קודם כל יש לי תכונת private שמכילה מערך חביב שבו אשתמש ב-set.
במתודת set מה שאני עושה מלבד הדפסת אישור, הוא להכניס את מה שאני מקבל לתוך המערך.
עכשיו אני יכול להכניס משהו לתוך ה-class! שימו לב לזה:
<?php class a { private $data = array(); public function __set($name, $value) { print "Setting '$name' to '$value'"; $this->data[$name] = $value; } } $a = new a(); $a->new_property = 'foobar';
וכך הכנסתי תכונה חדשה בשם new_propery שלה יש את הערך foobar! הוריי! אם אני רוצה לקרוא לה, אני צריך להגדיר מתודת קסם נוספת בשם __get, היא זהה בעקרון שלה ל__set:
class a { private $data = array(); public function __set($name, $value) { print "Setting '$name' to '$value'"; $this->data[$name] = $value; } public function __get($name) { if (array_key_exists($name, $this->data)) { return $this->data[$name]; } else { return null; } } } $a = new a(); $a->new_property = 'foobar'; print $a->new_property;
מה שהמתודה הזו עושה הוא פשוט ביצוע של קריאה למשתנה שכבר יצרנו – פשוט תנסו!
כמובן שאפשר לעשות עוד לא מעט פעולות עם set ועם get, אבל זו הפעולה הבסיסית – להכניס תכונות לתוך class בזמן ריצה מתי שרוצים.
ניתן גם ליצור מתודות on the fly באמצעות מתודת הקסם __call
כך עושים את זה:
<?php
class a { public function __call($name, $arguments) { // Note: value of $name is case sensitive. print "Calling object method '$name' " . implode(', ', $arguments). "n"; } } $a = new a(); $a->new_function('arg1','arg2');
באמצעות מתודת __call אני יכול להגדיר מה פונקציה שנוצרת on the fly אמורה לעשות. נכון שבמקרה הזה השימושיות שלה מוגבלת ואני לא יכול ממש ליצור מתודה חדשה, אבל אני כן יכול להשתמש בזה לעשות דברים גנריים כאשר אני לא יודע כמה משתנים אני הולך לקבל.
החל מגרסת PHP 5.3 אני יכול גם ליצור מתודה סטטית on the fly וזה כבר די שימושי. מתודת הקסם ליצירת מתודה סטטית היא __callStatic ומשתמשים בה באופן הבא:
<?php class a { public static function __callStatic($name, $arguments) { print "Calling static method '$name' " . implode(', ', $arguments). "n"; } } $a = new a(); $a::new_static_function('arg1','arg2');
נסו ותהנו! ישנן עוד כמה מתודות קסם ספורות שלא דנו בהם פה והן נמצאות בדוקומנטציה.
תגובות בפייסבוק