הבדיקה שתמיד נכונה
במאמר הזה
בשירות הזה יש 23 פקודות UPDATE בסך הכול. בדיוק אחת מהן בודקת אם שינתה משהו. הבדיקה הזאת היא:
'success' => $n->rowCount() >= 0
rowCount() מחזירה 0 כששום שורה לא התאימה. אפס גדול מאפס או שווה לו. הבדיקה עוברת בכל מקרה.
למה נועדה הפקודה
היא שומרת תיבת סימון: האם בעל המונה רוצה דוח שבועי בדוא״ל. הכתובת נמצאת בטבלה נפרדת, ושורה מופיעה בה רק אחרי שמישהו לחץ על קישור האישור בהודעה שביקש. לארבעה מונים יש שורה כזאת. יש 2,218 מונים פעילים.
לכן ב־99.8% מהמונים, הפקודה UPDATE אינה מתאימה לדבר. נקודת הקצה עונה success: true וההגדרה אינה נשמרת, כי אין היכן לשמור אותה.
ההערה שמעליה נכונה
שלוש שורות למעלה, באותה פונקציה:
“רק במקום שבו יש דרך חזרה מאושרת. בלעדיה אין כתובת שאליה המכתב יכול להישלח — ותיבת הסימון הייתה מבטיחה משהו שאינו קורה.”
זה נכון בדיוק. מישהו חשב על המקרה הזה, הבין אותו ותיעד את הנימוק. ואז השורה שמתחת השתמשה בערך >= במקום שבו הנימוק דרש >.
כדאי להסתכל על כך ישירות, כי ההסבר הרגיל — איש לא חשב על זה — זמין ושגוי. המחשבה נמצאת בקובץ. מה שנכשל הוא תו אחד, במקום שבו הגרסה השגויה והנכונה נראות זהות במבט חטוף ומתנהגות באופן זהה בכל בדיקה שיש בה שורה לעדכון.
איש אינו מקבל הבטחה כוזבת
הנה החלק שקל להשמיט, והשמטתו תהפוך את הרשומה לדרמטית יותר ואמיתית פחות.
הדף אינו מצייר את תיבת הסימון הזאת אלא אם השורה קיימת. במרחק מסך אחד, בקוד שמצייר את תיבת הגדרות הבעלים, אותה טבלה נשאלת תחילה והבלוק כולו אינו מוצג כשהשאילתה חוזרת ריקה. לכן בעל מונה ללא כתובת מאושרת לעולם אינו רואה את הפקד, לעולם אינו לוחץ עליו ולעולם אינו מקבל את האישור הכוזב.
אפשר להגיע לבדיקה המקולקלת רק בפנייה ישירה לנקודת הקצה עם אסימון תקף. מי שעושה זאת מקבל success: true וללא הגדרה שמורה. זה ליקוי אמיתי וצר.
למה עדיין כדאי לתעד זאת
התכונה בטוחה בזכות מנגנון הגנה שאיש לא תיעד כמנגנון ההגנה. השורה שקיימת כדי להפוך אותה לבטוחה אינה עושה זאת. מה שכן עושה זאת הוא תנאי ציור בפונקציה אחרת, שההערה שלה מסבירה למה תיבת הסימון מוסתרת — ולא שמשהו תלוי בכך שתישאר מוסתרת.
אם מסירים או משנים את מבנה תנאי הציור הזה — דבר סביר בעיצוב מחדש של לוח הגדרות — הליקוי נעשה גלוי מיד, בלי ששום דבר בשום מקום מקשר בין שני השינויים. הבטיחות אמיתית, והיא מקרית, ובטיחות מקרית היא הסוג שנעלם במהלך עבודה לא קשורה.
אותו קוד עושה זאת נכון בקובץ סמוך. הפונקציה המקבילה של טבעת האתרים שואלת אם השורה קיימת, מחזירה false כשאינה קיימת, ולעולם אינה שולחת את העדכון כלל. בטבלה הזאת יש כעת אפס שורות, ולכן הפונקציה הזאת מחזירה false בכל פעם שקוראים לה, וזאת התשובה הנכונה.
הדפוס הכללי
פקודת UPDATE שאינה מתאימה לשום שורה אינה שגיאה בשום מסד נתונים. זאת פקודה מוצלחת שלא עשתה דבר, וכל שכבה מעליה תדווח על הצלחה אלא אם משהו ישאל. עשרים ושתיים מהפקודות כאן אינן שואלות, ולרובן זה בסדר: הן מעדכנות שורה שהבקשה כבר הוכיחה שקיימת.
האחת שהייתה צריכה לשאול, שאלה בדרך שאינה יכולה להיכשל. rowCount() >= 0 אינה בדיקה חלשה, אלא היעדר בדיקה בתחפושת של בדיקה — וזה גרוע מהיעדר בדיקה, כי האדם הבא שיקרא את הפונקציה יראה שבודקים תוצאה ויפסיק לחפש.
הביטוי rowCount() > 0 מופיע אפס פעמים בקוד הזה. זה המספר שהפך טעות של תו אחד למשהו שכדאי לכתוב עליו רשומה: לא שהוא נכתב לא נכון פעם אחת, אלא שלא הייתה דוגמה נכונה בשום מקום להשוות אליה.
תוקן ב־28 באוגוסט 2026. נקודת הקצה שואלת כעת אם השורה קיימת לפני העדכון, כפי שפונקציית טבעת האתרים בקובץ הסמוך כבר עשתה, ועונה false כשאינה קיימת. התיקון המובן מאליו של תו אחד — בדיקה אם מספר השורות גדול מאפס במקום זאת — נמדד תחילה ונדחה: מנהל ההתקן מדווח על שורות שהשתנו ולא על שורות שהתאימו, ולכן הגדרת תיבת הסימון לערך שהיא כבר מחזיקה אינה משנה דבר, והגרסה הזאת הייתה מדווחת על כישלון של פעולה תקינה. שתי הגרסאות שגויות, בכיוונים מנוגדים.