בנית-אתרים.com – בלוג בנית אתרים
בקטגוריה: פרוייקטים|תכנות מונחה עצמים
17 מרץ 2010שים לב: הפוסט הזה מסתמך על ידע מפוסטים קודמים בסדרה, לאינדקס הפוסטים של תכנות מונחה עצמים.
בואו וניקח את הרעיונות והשמות שדיברנו עליהם ונהפוך אותם לקוד של ממש.
את הקוד אכתוב בPHP כיוון שזה בלוג בנושא בנית אתרים אולם קוד דומה ישמש לשפות רבות ומה שישתנה זה כמעט אך ורק התחביר.
נכתוב מחלקה שמייצגת כלב ולאחר מכן ניצור את לאסי האובייקט שהוא מופע של כלב.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // This is the class Dog class Dog { // This is the property speed which represents dogs speed var $speed; // This is the method talk function talk() { echo "woof woof"; } // This is the method walk, which receives 1 argument and probabbly uses the speed property function walk($to) { // This is just an example, implementation of walk method should be here } } // Lets create an object of Dog named Lassie $lassie = new Dog(); // Lets make Lassie talk $lassie->talk(); // Lets change the speed of Lassie $lassie->speed = 10; // Lets make Lassie walk some where $lassie->walk("some where"); |
אסביר את הקוד:
class Dog – המילה השמורה class מציינת פתיחת מחלקה.
var $speed – המילה var (בהמשך נלמד על public, protected וprivate) מגדירה מאפיין למחלקה.
הפונקצייה talk וwalk – פעולות של המחלקה, walk מקבל ארגומנט אחד.
$lassie = new Dog(); – המילה השמורה new יוצרת מופע של המחלקה שרשומה אחריה. בקרוב נבין מה משמעות הסוגריים.
$lassie->talk(); – הסימן "->" משמש לשם פנייה לאיברים (מאפיינים ופעולות) של המחלקה, קריאה לפעולה talk.
$lassie->speed = 10; – שינוי של המאפיין speed ל10.
$lassie->walk("some where"); – קריאה לפעולה walk עם ארגומנט 1.
הפלט של הקוד הזה יהיה כמובן "woof woof".
בואו ננסה להבין יחד למה זה טוב. נניח שאת המחלקה Dog כתב מתכנת א' והוא השתמש בה בכדי ליצור את לאסי, אבל חודשיים לאחר מכן מתכנת ב' רצה ליצור כלב חדש – פלאפי. ללא מחלקה הוא היה צריך לקחת את הקוד של לאסי ולשכפל אותו בכל נקודה ולהבין את הלוגיקה שמאחורי כל פקודה ופקודה (במקרים שכל פעולה מכילה עשרות, מאות ואלפי שורות זה יותר משמעותי).
עם מחלקות הוא יכול לכתוב קוד שכזה:
1 2 3 4 | $flaffi = new Dog(); $lassie->speed = 8; $flaffi->walk("here"); $flaffi->talk(); |
בכל מחלקה ניתן להשתמש במשתנה הפנימי $this. משתנה זה הוא למעשה מפנה למשתנה של האובייקט עצמו כך שאם אוסיף את הקוד $this->speed = 10; לפעולה talk, ברגע שהיא תורץ המאפיין speed של האובייקט עצמו (לדוגמה $lassie) ישתנה ל10.
לעתים נרצה להפעיל פעולות מסויימות, לקבל משתנים לתוך האובייקט וכדומה עוד בזמן יצירתו, לשם כך קיימת פעולת Constructor.
הפעולה היא פעולה רגילה לחלוטין אך היא נקראת באופן אוטומטי ברגע היצירה של האובייקט, כמובן שאין חובה ליצור אחת כזו. שם הפעולה צריך להיות זהה לשם המחלקה (במרבית שפות התכנות וגם בPHP), אך מPHP5 ומעלה מומלץ לקרוא לה __construct (כולל שני הקווים התחתונים).
נחזור לדוגמה הקודמת, נניח שאנו רוצים לקבוע את מהירות ההליכה של הכלב בזמן שאנו יוצרים אותו, נוסיף למחלקה את הקוד הבא:
1 2 3 | function Dog($speed) { $this->speed = $speed; } |
לאחר מכן, נצטרך לשנות את היצירה של לאסי ופלאפי לשורות הבאות (ונוכל למחוק את השורות שמשנות את המהירות באופן חיצוני):
1 2 | $lassie = new Dog(10); $flaffi = new Dog(8); |
אובייקטים נשמרים בתצורה הנקראת Reference Type בעוד משתנים "פרמיטיבים" כמו מספרים נשמרים בתצורה הנקראת Value Type.
ההבדל בין השתיים הוא שבמשתנים מסוג Value Type המשתנה מקבל את הערך עצמו, בעוד באובייקטים המשתנה מצביע למיקום שבו נמצא הערך!
קוד להמחשה:
1 2 3 4 5 6 7 8 9 | $a = 5; $b = $a; $b = 8; echo $a; // Will print out 5 $dog1 = new Dog(5); // Init the speed to 5 $dog2 = $dog1; $dog2->speed = 8; echo $dog1->speed; // Will print out 8 |
לקריאה נוספת בעברית – Value Type & Reference Type in PHP (נכתב על ידי איתי סלע).
שמי שי ואני בונה אתרים וכיום חותך (מקודד) ומתכנת.
אני עובד אל מול התקן העולמי של W3C, ומתכנת בשפת PHP תוך שימוש בטכנולוגיות עדכניות, תוך שמירה על קוד שניתן לתחזוקה.
בין כישורי נמנים: PHP, SQL, (X)HTML, CSS (2-3), XML, JavaScript ( + jQuery) ועוד.
10 תגובות ליישום של תכנות מונחה עצמים
איתי סלע
17 מרץ, 2010 בשעה 18:12
יפה מאוד. שם לב שבתור מדריך ראשוני זה טוב אך כשמדברים על תיכנות מונחה עצמים ברמה היותר מתקדמת ומציאותית שלו צריכה להיות הפרדה יותר חזקה בין החלקים שבתוך האובייקט ולא נגישים מבחוץ לבין כאלה שכן.
למשל ייתכן ותרצה שהמשתנה speed יוכל להיות מוגדר רק ע"י פונקציה שתאמת שהערך שאתה מנסה להכניס לו גדול מ-1 והוא מסוג מספר שלם. (הרעיון הוא שבקוד הנוכחי עלול להיווצר מצב שבו יוכנס לspeed ערך שגוי שיגרום לשגיאה)
כמו כן, הערה חשובה עוד יותר: הקוד שאתה מציג פה הוא מPHP 4. כיום אנחנו בPHP 5, אני ממליץ שאם אתה כבר כותב מדריך שמלמד אנשים – שילמד את השיטה החדשה והנכונה יותר(הכוונה שאין פה התייחסות להרשאות גישה כגון public private protected). כמובן שבמדריך בסיסי אתה לא צריך להסביר יותר מדי בנושא הזה אבל עדיין לשמור על קוד איכותי ושבהמשך תפרט את הסעיפים שיותר מסובכים בו.
תודה על הקישור למדריך
מחכה לעוד מדריכים !
Shay | Exalted Web
17 מרץ, 2010 בשעה 19:20
תודה על התגובה איתי
אני מסכים לגבי כל מה שציינת ולמעשה ציינתי את זה בעצמי.
ראשית אם תסתכל באינדקס של התכנים המאמר הבא הוא על כימוס – Encapsulation שזה בגדול העניין של public, protected וprivate, אפילו רשמתי את זה בפוסט הזה. אני הולך להדגים את כל הנושא הזה ולתת דוגמאות פרקטיות לזה.
שנית רשמתי על ההבדל בין PHP4 לPHP5 בנושא של Constructors.
אני תמיד שמח לשמוע ממך!
איתי סלע
17 מרץ, 2010 בשעה 19:31
מעולה. אני סומך עלייך. אני רק רוצה להדגיש שמבחינתי החלק שהכי חשוב(או לחילופין: שהייתי הכי שמח לראות יותר מדריכים שלו) זה לאו דווקא תיכנות מונחה עצמים ברמה של הסינטקס ו"איך משתמשים" (ברמה של יצירת מחלקה ודוגמאות כאלה למיניהן) אלה דברים יותר פרקטיים, קוד ללא תיכנות מונחה עצמים לעומת קוד עם תיכנות מונחה עצמים אשר ממחיש את היעילות וכן, התמקדות בחלק של תיכנון האפליקציה(ברמה הרעיונית, איך לקחת מערכת ולחלק אותה למודלים נכונים).
הנקודה היא שלטעמי החלק הכי קשה למתכנתים שמגיעים לכל הנושא של פיתוח מתקדם ותיכנות מונחה עצמים אינו חוסר ההבנה איך לעשות את הדברים אלה חוסר ההבנה איך לתכנן את הדברים ולמה בכלל צריך את זה(מעבר למשפט הבאנלי שתיכנות מונחה עצמים מספק גמישות לשינויים, קוד יעיל יותר, ברור יותר וקצר יותר) – בהרבה מקרים תיכנון לקוי מוביל לסיבוכיות באפליקציה והתוצאה הפוכה.
בטוח שתספק את הסחורה.
Shay | Exalted Web
17 מרץ, 2010 בשעה 19:41
הוצאת לי את המילים מהפה.
החלק המסובך הוא ללא ספק למה ואיך נכון ולא מה הסינטקס, בשביל זה פתחתי את הסדרה בהסבר על ההגיון שעומד מאחורי תכנות מונחה עצמים.
רומן
21 מרץ, 2010 בשעה 8:33
יש גם deconstructor, ובנוסף לpublic, private וכו, יש גם static, שגם יכול להועיל מידי פעם.
Shay | Exalted Web
26 מרץ, 2010 בשעה 22:54
תודה על התגובה.
ראשית השם הוא Destructor וכן בשלב מסויים אדון בו כנראה.
לגבי static, זה נושא אחר לגמרי ממה שדנו במאמר הזה, בשלב מסויים נדבר גם על כך אך זה פחות חשוב לי כעת. לדעתי שימוש בסטטיות זה לא הרבה יותר מאגירה של פונקציות תחת שם אחד, שזה נושא פחות חשוב לטעמי.
איתי סלע
28 מרץ, 2010 בשעה 10:18
שי,
לגביי הפילוסופיה שמאחורי static אני לא אכנס אלייך. דבר אחד כן אגיד: החוק עם static הוא – אם אתה לא צריך ליצור מספר מופעים שונים ממחלקה מסויימת, קרי – אין הבדל בין הנתונים הפנימים שלה במקומות שונים בקוד בהם אתה משתמש בה – היא צריכה להיות static. אתה תתפלא, אם תבחן את הקוד שלך, כמה מחלקות צריכות להיות static ואינן.
למשל, כמה פעמים השתמשת באיזה שהיא מחלקה בצורה הבאה:
$classX = new ClassX();
$classX->doSomething();
בלי שיש כל ייחודיות לאובייקט הספציפי שבו אתה משתמש.
static הוא נושא מאוד מאוד חשוב ובמיוחד שילוב של static ומחלקות "רגילות" – למשל – לא תמיד נרצה לכתוב מחלקה שהיא pure static – הבט נוסף של static הוא שהוא שומר מידע זהה בין כל האובייקטים של אותה מחלקה. כך למשל אתה יכול לעשות מחלקה "רגילה" אך שיהיה לה מאפיין מסויים שהוא static ולכן הוא יהיה זהה בכל המופעים של המחלקה(למשל לכל בני האדם בעולם יש מאפיין של מיקום השמש ביקום ולכן פונקצית החישוב של "האם כעת יום" תחשב את מיקום האדם הנוכחי ביחס למיקום השמש הקבוע(שמשתנה כל הזמן אך משותף לכל האובייקטים של האדם))
Shay | Exalted Web
28 מרץ, 2010 בשעה 15:46
הממ תראה, סטטיות זה כן נושא מועיל אבל דבר ראשון אני צריך לציין שלא יוצא להשתמש בזה הרבה וכתוצאה מכך אני לא מבין בזה יותר מדי.
דבר שני, בוודאי שסטטיות זה מועיל מאוד במידה ויש לך מחלקה שאתה "צריך מופע אחד" ולא יותר מזה, או שיש דברים שמשותפים לכל המופעים, אבל כרגע זה פחות חשוב לטעמי מאבסטרקציה ופולימרפיזם.
איתי סלע
28 מרץ, 2010 בשעה 22:34
אם יש לך שאלות אתה מוזמן. אני מניח שאתה יודע שחשוב בתור מדריך שמתיימר להסביר על OOP לדון גם בstatic גם אם זה נושא פחות בר-שימוש, מה שדרך אגב, לדעתי כלל לא נכון. תסתכל קצת בZEND ותיראה כמה מחלקות סטטיות יש שם(כדי שתקבל קצת תחושה איפה כדאי להשתמש בזה).
אני ארחיב ואגיד(ולדעתי אתה יכול להכניס את זה גם לאחד המאמרים) שבPHP כל נושא הOOP הוא פחות מורגש(בניגוד לC# למשל או לכל שפה שפחות מבוססת על דינמיות) גם מבחינת העבודה שמדובר באפליקציה וואבית וגם מבחינת הגמישות שPHP מספקת שדיי מתנגשת עם חלק מהרעיון של OOP (בין היתר להגביל את המשתמש במחלקה בכדי למנוע טעויות). כך למשל אפשר לממש דברים ללא static והכל יהיה בסדר. אך גם הרבה דברים אחרים בOOP אפשר לממש בלי OOP ולהגיד לתוצאות זהות (ולעיתים יותר מובנות\נוחות לשינוי\מהירות). עדיין צריך להכיר את המושגים ולהשתמש בהם במקומות המתאימים.
Shay | Exalted Web
29 מרץ, 2010 בשעה 10:34
תודה על ההסבר. אני מסכים איתך ולומד מכל תגובה שלך
אני מניח שאני גם אכתוב מאמר על סטטיות, ומאמר שכבר תכננתי זה מאמר שיסביר שבPHP אין OOP מועיל כמו בשפות עיליות מסוימות (לפחות בינתיים).