Menu
Coddy logo textTech

מילת המפתח final

חלק מהיחידה תכנות מונחה עצמים במסלול ה-PHP של Coddy. שיעור 24 מתוך 91.

בעוד שירושה ודריסת מתודות מספקות גמישות, לפעמים צריך למנוע שינויים במחלקות או במתודות מסוימות. מילת המפתח final נועלת את הקוד שלך, ומבטיחה שמחלקות יורשות לא יוכלו לשנות מימושים מסוימים.

כשמסמנים מתודה בתור final, אף מחלקת בת לא יכולה לדרוס אותה:

<?php
class BankAccount {
    protected $balance;
    
    public function __construct($balance) {
        $this->balance = $balance;
    }
    
    final public function getAccountId() {
        return "ACC-" . spl_object_id($this);
    }
}

class SavingsAccount extends BankAccount {
    public function addInterest() {
        return $this->balance * 0.05;
    }
}

$account = new SavingsAccount(1000);
echo $account->getAccountId();

פלט:

ACC-1

אי אפשר לדרוס את המתודה getAccountId() ב־SavingsAccount או בכל מחלקת צאצא אחרת. כך מוגנת פונקציונליות קריטית שחייבת להישאר אחידה בכל סוגי החשבונות.

אפשר גם לסמן מחלקה שלמה כ-final כדי למנוע כל ירושה:

<?php
final class SecurityManager {
    public function authenticate($user) {
        return "Authenticating $user";
    }
}

$security = new SecurityManager();
echo $security->authenticate("admin");

פלט:

Authenticating admin

אין מחלקה שיכולה לרשת את SecurityManager. הדבר שימושי למחלקות הרגישות מבחינת אבטחה או כאשר תכנון המחלקה הושלם ואין לשנותו.

נקודה חשובה: השתמשו ב־final על מתודות כדי למנוע דריסה תוך מתן אפשרות לירושה, או על מחלקות כדי למנוע ירושה לחלוטין. זהו כלי להגנה על קוד קריטי שחייב לפעול בדיוק כפי שתוכנן.

challenge icon

אתגר

קל

בואו נבנה מערכת לניהול מסמכים שמדגימה כיצד מילת המפתח final מגינה על פונקציונליות קריטית מפני שינוי על ידי מחלקות צאצא.

תיצרו שלושה קבצים שפועלים יחד כדי לנהל סוגים שונים של מסמכים, תוך הקפדה על כך שמאפייני אבטחה מסוימים יישארו נעולים:

  • Document.php: הגדירו מחלקה בשם Document שתשמש כמחלקת הבסיס לכל המסמכים. צריכים להיות לה מאפיין ציבורי $title ומאפיין מוגן $author. הבנאי מקבל גם את הכותרת וגם את שם המחבר. כללו מתודה מסוג final בשם getSignature() שמחזירה "Signed by: [author]". אסור למחלקות צאצא לשנות את מאפיין האבטחה הזה. הוסיפו גם מתודה רגילה בשם getContent() שמחזירה "Document: [title]".
  • Report.php: הגדירו מחלקה בשם Report שיורשת מ־Document. כללו את קובץ Document בראש הקובץ. המחלקה הזאת מוסיפה מאפיין $department. הבנאי צריך לקבל כותרת, שם מחבר ומחלקה: השתמשו ב־parent::__construct() עבור שני הערכים הראשונים, ואז הגדירו את המחלקה. שנו את המתודה getContent() כך שתחזיר "Report: [title] ([department])". המחלקה Report יורשת את המתודה הסופית getSignature() ואינה יכולה לשנות אותה.
  • main.php: כללו את קובץ Report. תקבלו שלושה קלטים: כותרת המסמך, שם המחבר והמחלקה. צרו אובייקט Report עם הערכים האלה. הדפיסו את התוצאה של getContent() בשורה הראשונה, ולאחר מכן הדפיסו את התוצאה של getSignature() בשורה השנייה.

האתגר הזה מדגים כיצד מתודות final מגינות על פונקציונליות קריטית: יצירת החתימה נשארת עקבית בכל סוגי המסמכים, בעוד שאפשר להתאים אישית מתודות אחרות, כמו getContent(), בכל מחלקת צאצא. המחלקה Report יכולה לשנות את אופן הצגת התוכן, אבל פורמט החתימה נעול במחלקת האב.

נסו בעצמכם

<?php
require_once 'Report.php';

// קרא את הקלט
$title = trim(fgets(STDIN));
$author = trim(fgets(STDIN));
$department = trim(fgets(STDIN));

// TODO: צור אובייקט Report עם ערכי הקלט

// TODO: הדפס את התוצאה של getContent()

// TODO: הדפס את התוצאה של getSignature()
?>
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר PHP אונליין