
הצהרת טיפוסים בפונקציות ב-PHP
הצהרת טיפוסים (Type Declaration) נקראת לעתים גם רמיזה על טיפוסים (Type Hinting). זהו כלי רב עוצמה ב-PHP המאפשר לציין את טיפוס הארגומנטים שפונקציה יכולה לקבל, ואת טיפוס ערך החזרה שפונקציה מחזירה. ללא הצהרת טיפוסים, כברירת מחדל, פונקציות ב-PHP מקבלות ארגומנטים מכל טיפוס ומחזירות כל טיפוס אפשרי של ערך חזרה, דבר שעלול להוביל להתנהגות לא מתוכננת של הפונקציה או שימוש לא נכון בה.
האפשרות להוסיף הצהרה על טיפוסי הארגומנטים ועל ערך החזרה של פונקציה, משפרת את קריאות הקוד, מהימנותו וחוסנו, על ידי איתור שגיאות הקשורות לטיפוסים במהלך הפיתוח.
הטיפוסים אותם ניתן לקבל ולהחזיר:
טיפוסים סקלריים - int, float, string, bool
טיפוסים מורכבים - array
טיפוסים מיוחדים - mixed, object, null, void
דוגמה:
<?php
function calculateArea(float $length, float $width): float {
return $length * $width;
}
function processArray(array $data): int {
return count($data);
}
function logMessage(string $message): void {
echo $message;
}
echo calculateArea(5.5, 3.2); // Output: 17.6
echo processArray([1, 2, 3, 4]); // Output: 4
logMessage('hello');
?>
בדוגמה זו, הפונקציה calculateArea מקבלת שני פרמטרים, שניהם מטיפוס float (נקודה צפה, שזה למעשה שבר) ומחזירה float. הפונקציה processArray מקבלת מערך (כל מערך אפשרי) ומחזירה int (מספר שלם). הפונקציה logMessage מקבלת string (מחרוזת) ומחזירה void, כלומר, לא מחזירה שום ערך, ולכן גם אין חובה לכלול בה הצהרת return.
הצהרת טיפוסים עם אופרטור 3 נקודות
נוכל לבצע הצהרת טיפוסים גם במקרה שאנו משתמשים באופרטור 3 נקודות. נזכיר, כי אופרטור 3 נקודות מאפשר קבלה של ארגומנטים ללא הגבלה, כאשר כל הארגומנטים נכנסים לתוך מערך משותף.
דוגמה:
<?php
function sumAll(int ...$numbers): int {
return array_sum($numbers);
}
echo sumAll(1, 2, 3, 4); // Output: 10
?>
בדוגמה זו, הפונקציה sumAll מקבלת ארגומנטים ללא הגבלה, מטיפוס int. ארגומנטים אלו יוצרים יחד את המערך בשם numbers. הפונקציה מחשבת את סכום הערכים במערך ומחזירה int.
טיפול בטיפוס null
הטיפוס null הוא טיפוס מיוחד שכולל ערך יחיד null (הטיפוס והערך שניהם null). ערך זה מייצג ערך "ריק". ניתן לקבוע כי ארגומנטים שמועברים לפונקציה יכולים לקבל ערך null בנוסף לטיפוס מוגדר אחר (כגון int, string או כל טיפוס אחר). הדבר נעשה באמצעות הוספת סימן שאלה (?) לפני הטיפוס.
דוגמה:
<?php
function getUser(?int $id): ?string {
$users = ['Alice', 'Bob'];
return $users[$id] ?? null;
// This expression equals to the following expression:
// return isset($users[$id]) ? $users[$id] : null;
}
echo getUser(0); // Output: Alice
echo getUser(1); // Output: Bob
echo getUser(2); // Output: (empty)
echo getUser('Something'); // Output: (empty)
echo getUser(null); // Output: (empty)
?>
בדוגמה זו, הפונקציה getUser מקבלת טיפוס int או את הערך null ומחזירה טיפוס string או את הערך null. בתוך הפונקציה אנו מגדירים מערך users שכולל 2 ערכים: Alice, Bob. הפונקציה מחזירה ביטוי שעושה שימוש באופרטור Null Coalescing (האופרטור כולל שני סימני שאלה "??") שיודע לבדוק קיום של ערכים. הוא פועל באופן הבא: בהנתן ערך id כלשהו, אם מוגדר users[id], אז הערך users[id] יוחזר. אחרת, מוחזר הערך שאחרי הסימן ??, כלומר במקרה שלנו null. למען הבנת הקוד, הוספנו בפונקציה הערה שמציגה ביטוי חלופי אפשרי עבור שורת ה-return אשר מתנהג בצורה זהה. למעשה, הפונקציה מקבלת מספר int ומחזירה את המשתמש שבאינדקס הזה, או null אם לא קיים משתמש שכזה.
הטיפוס mixed
הטיפוס mixed הוא טיפוס שמאפשר קבלת כל ערך. זהו למעשה איחוד של כלל הטיפוסים האפשריים, לרבות int, string, array, null וכן הלאה.
דוגמה:
<?php
function getValue(): mixed {
return rand(0, 1) ? "Hello" : 42;
}
?>
בדוגמה זו, הפונקציה getValue אינה מקבלת פרמטרים והיא מחזירה טיפוס mixed, כלומר, יכולה להחזיר כל טיפוס. הפונקציה מגרילה מספר שלם (integer) בין 0 ל-1 (כלומר, מגרילה או 0 או 1 בלבד). אם היא הגרילה 1, יוחזר הערך Hello מטיפוס string. אחרת (הוגרל 0), יוחזר הערך 42 מטיפוס int.
נשים לב שיכולנו שלא לציין שהפונקציה מחזירה mixed, שהרי ממילא אם לא נציין זאת הפונקציה תוכל להחזיר ערכים מכל טיפוס. הסיבה שבכל זאת ציינו את טיפוס החזרה mixed, היא כדי לשפר את קריאות הקוד, וכדי לסייע למי שיתחזק את הקוד בעתיד להבין שהחזרת כל ערך אפשרית מתוך כוונת המתכנת והדבר נעשה במכוון ולא בטעות.
הצהרת strict_types
כברירת מחדל, PHP היא שפה מסוג weak typing (או weakly typed language), כלומר, אינה אוכפת טיפול נוקשה בטיפוסים. לדוגמה, ניתן לבצע בה השמה של מחרוזת (string) למספר (int או float) ולהיפך, כאשר המרת הטיפוסים נעשית בצורה מרומזת (coercion). קיימות שפות תכנות מסוג strong typing (או strongly typed languages) שאוכפות בדיקה נוקשה יותר של טיפוסים כברירת מחדל, ואינן מאפשרות המרה של טיפוסים מסוגים בצורה מרומזת (coercion), אלא בצורה מפורשת (casting) בלבד.
דוגמה:
<?php
// Adding a string and an integer
$result1 = "10" + 5;
echo "Result of '10' + 5: " . $result1 . PHP_EOL; // Output: 15
// Comparing a string and an integer
$result2 = ("5" == 5);
echo "Result of '5' == 5: " . ($result2 ? "true" : "false") . PHP_EOL; // Output: true
// Using a string in a conditional
$value = "0";
if ($value) {
echo "'0' is considered true in a conditional." . PHP_EOL;
} else {
echo "'0' is considered false in a conditional." . PHP_EOL; // Output: '0' is considered false
}
// Concatenating a boolean with a string
$result3 = true . " apples";
echo "Result of true . ' apples': " . $result3 . PHP_EOL; // Output: 1 apples
// Multiplying a string with a number
$result4 = "3.5" * 2;
echo "Result of '3.5' * 2: " . $result4 . PHP_EOL; // Output: 7
// Comparing a string with non-numeric content and a number
$result5 = ("apple" == 0);
echo "Result of 'apple' == 0: " . ($result5 ? "true" : "false") . PHP_EOL; // Output: true
?>
בדוגמה זו, אנו רואים דוגמאות רבות בהן נעשית המרת טיפוסים בצורה מרומזת, כאשר ערכים מטיפוסים שונים מומרים אוטומטית לערכים מטיפוסים אחרים. הביטוי PHP_EOL מציין סימן סוף שורה (End Of Line) שמותאם לפלטפורמה בה הקוד רץ (חלונות, לינוקס, macOS של מקינטוש וכו').
כיוון ש-PHP מאפשרת המרת טיפוסים מרומזת כברירת מחדל, יתכנו מצבים שנעביר בטעות ארגומנטים מטיפוס מסויים לפונקציה שאמורה לקבל ארגומנטים מטיפוס אחר, או שנטפל בערך חזרה של פונקציה כאילו הוא מטיפוס מסויים למרות שהוא מטיפוס אחר. הצהרת הטיפוסים שראינו עד כה (עבור ארגומנטים וערך חזרה של פונקציה) אמנם מגדירה את הטיפוסים הנדרשים, אך PHP בהחלט מאפשרת המרה מרומזת של טיפוסים גם במקרה של הצהרת טיפוסים.
דוגמה:
<?php
// No strict_types declaration (default behavior)
function addNumbers(int $a, int $b): int {
return $a + $b;
}
echo addNumbers("5", 10); // Output: 15 (string "5" is coerced to integer 5)
?>
בדוגמה זו, הפונקציה addNumbers מקבלת שני פרמטרים מטיפוס int, סוכמת אותם ומחזירה int. קראנו לפונקציה עם המחרוזת "5" ועם המספר 10. PHP ביצעה המרה מרומזת (coercion) של המחרוזת "5" למספר 5 בטרם הרצת הפונקציה, והחזירה את הערך 15, שהוא הסכום של שני המספרים 5 ו-10.
כיוון שהמרת הטיפוסים המרומזת עלולה להכניס איתה בעיות (נניח אם נעביר בטעות מחרוזת במקום מספר ו-PHP תאפשר זאת למרות שאיננו מעוניינים בכך), נוכל לדרוש מ-PHP למנוע ביצוע של המרות מרומזות. לשם כך, נשתמש בהצהרת strict_types אשר הופכת את PHP לשפה נוקשה יותר בבדיקת טיפוסים. לאחר שימוש בהצהרת strict_types, לא יתבצעו עוד המרות מרומזות בצורה אוטומטית. אם נרצה שכן תתבצע המרה, נוכל לעשות זאת תמיד בצורה מפורשת (casting).
דוגמה:
<?php
declare(strict_types=1);
function addNumbers(int $a, int $b): int {
return $a + $b;
}
echo addNumbers(5, 10); // Output: 15
// echo addNumbers(5, "10"); // Throws TypeError in strict mode
?>
בדוגמה זו, תיקנו את הדוגמה הקודמת, והוספנו הצהרת strict_types. הצהרה זו תמנע מהקוד לבצע המרת טיפוסים מרומזת, ולכן, העברת מחרוזת במקום מספר לפונקציה addNumbers תחזיר שגיאה.