הדרך הפשוטה ביותר לשימוש חוזר בקוד היא יצירת סאב-רוטינות (שיגרה - subroutine).

סאב-רוטינות מאפשרות להריץ את אותו קוד במספר מקומות ביישום שלכם, והן מאפשרות להריץ אותו עם פרמטרים שונים.

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

פונקציה פשוטה

למשל נניח שאתם רוצים לפנות אל המשתמש ולשאול שאלה:

ask_question();
my $answer = get_answer();
# some code
ask_question();
my $second_answer = get_answer();

########## sub declarations come here

sub ask_question {
  print "Have we arrived already?";
  return;
}

sub get_answer {
  my $answer = <STDIN>;
  chomp $answer;
  return $answer;
}

sub terminate {
   die "Hasta La Vista";
}

בחלק הראשון של הקוד קראנו פעמיים לפונקציה ask_question , וכמו כן קראנו לפונקציה get_answer פעמיים. בחלק השני של הקוד, אחרי ה- #####, יש לנו את את ההגדרות של שלוש הפונקציות.

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

השנייה משלבת את אופרטור קריאת השורה ואת chomp לקריאה אחת לפונקציה. היא ממתינה לקלט, וכשנלחץ ENTER היא מחזירה את המחרוזת שהקלדתם ללא סימן סוף השורה (newline) בסופה.

הפונקציה השלישית גם היא מאוד פשוטה, אך אף פעם לא קוראים לה ולכן היא אינה מבוצעת. זוהי נקודה מאוד חשובה למי שאינו מכיר פונקציות וסאב-רוטינות. הקוד שלכם, לא משנה איפה הוא נמצא בקובץ - מבוצע רק כשהוא "נקרא" על ידי שימוש בשם הפונקציה. בדיוק כפי שקראנו לשתי הפונקציות האחרות.

בכל המקרים, פרט למקרה האחרון, קראנו לפונקציה return של פרל כדי להחזיר ערך. למעשה הפונקציה תחזיר ערך כלשהו אפילו אם לא קראנו במפורש ל- return, אך מאוד מומלץ תמיד לקרוא ל- return. אפילו אם אין לנו משהו מיוחד להחזיר כמו בפונקציה ask_question() .

- בקשה לקלט prompt

נראה שיהיה יותר מעניין לשלב את שתי הפונקציות. כך תוכלו לכתוב:

my $answer = prompt();
# some code
my $second_answer = prompt();

sub prompt {
   print "Have we arrived already?";

   my $answer = <STDIN>;
   chomp $answer;
   return $answer;
}

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

my $first_name = prompt("First name: ");
my $last_name = prompt("Last name: ");

sub prompt {
   my ($text) = @_;
   print $text;

   my $answer = <STDIN>;
   chomp $answer;
   return $answer;
}

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

החידוש בדוגמה זו הייתה הצורה שבה העברנו את הפרמטר. אפילו יותר מעניין לראות איך הפונקציה קיבלה אותו.

כשקרואים לפונקציה אפשר להעביר לה מספר שרירותי של ארגומנטים, והערכים יוכנסו למשתנה הפנימי @_ . המשתנה שייך לפוקנציה שבה הוא נמצא. לכל פונקציה יש משתנה @_ משלה. ניתן לגשת לאלמנטים שלו כמו שעושים עם כל מערך אחר, כאשר $_[0] הוא האלמנט הראשון, אבל זה לא נראה יפה.

לרוב עדיף להעתיק את הערכים של @_ על ידי הצבתם ברשימה של ערכים מקומיים לפונקציה. זה מה שעשינו בדוגמה לעיל האחרונה עם my ($text) = @_;.

אחת השגיאות הנפוצות היא לשכוח את הסוגריים בהצבה.

sub prompt {
   my $text = @_;    # BAD! זה לא מה שאתם רוצים!!!
   ...
}

מה שיקרה זה שהמערך ייקרא בהקשר סקלרי ויחזיר את מספר האלמנטים. כך תקבלו מספר במשתנה $text . אם לא ברור לכם הנושא של הקשר, אפשר לקרוא על זה עוד הקשר סקלרי(Scalar) והקשר רשימתי (List) בפרל ואחר כך לחזור לכאן.

Prototypes אב-טיפוס

חלק משפות התיכנות מאפשרות, ואפילו מחייבות ליצור "prototypes (אב-טיפוס)" לפני שיוצרים את הפונקציה עצמה.

בפרל אין בכך צורך.

למעשה יש משהו בפרל שנקראה פרוטוטיפ, אבל זה לא עובד כמו שהייתם מצפים שזה יעבוד, ואני לא ממליץ עליהם. ודאי לא למתחילים. פרוטוטייפים בפרל הם שימושיים רק במקרים מעטים

פרמטרים או חתימה

בפרל 5 אין צורך או אפשרות להצהיר על החתימה של פונקציה.

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

sub do_something() {    # BAD !
}

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

סוגריים

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

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

ערכים מוחזרים

פונקציות בפרל תמיד מחזירות ערך.

או במפורש על ידי קריאה ל- return, או את התוצאה של השורה האחרונה בפונקציה. מומלץ תמיד לקרוא במפורש ל-return.

יש אפילו מדיניות של Perl::Critic שבודקת את הקוד שלכם ומציינת כל פונקציה שאין לה קריאה מפורשת ל-return בסוף הגדרת הפונקציה.

אם אין מה להחזיר אז פשוט קוראים ל- return; בלי ארגומנטים. כך אתם מוודאים שאתם באמת לא מחזירים כלום, במקום להחזיר בטעות את התוצאה של השורה האחרונה. זו דרך טובה להמנע מהפתעות למי שמשתמש בפונקציה.