בחינת מצב#

פרק זה מכסה את אוצר המילים של מנפה השגיאות לבחינת נתונים: x, V, X, y, m, M, i, והאפשרויות השולטות בעומק שבו מבוצע dump לערכים מצרפיים. לאחר פרק זה תוכלו לשאול כל תוכנית רצה ״איך המשתנה הזה, החבילה הזו, העצם הזה באמת נראים כרגע?״

קוראים מגיעים לכאן בידיעה ש־p EXPR מדפיס סקלר. שאר פקודות הבחינה מצדיקות את עצמן ברגע שהתשובה ל־״מה זה?״ דורשת יותר מערך יחיד.

x: dump של מבנים#

x EXPR מבצע הדפסה מסודרת בהקשר רשימה, ויורד רקורסיבית להפניות:

  DB<1> x \%config
0  HASH(0x5651f9a82358)
   'debug' => 1
   'dsn' => 'dbi:SQLite::memory:'
   'timeout' => 30
   'users' => ARRAY(0x5651f9b28a10)
      0  'alice'
      1  'bob'
      2  'carol'

תמיד העבירו הפניה עבור ערכים מצרפיים. x %h מבצע dump לרשימת מפתח/ערך שטוחה, אשר מסתירה את המבנה. x \%h עושה את מה שאתם רוצים.

  DB<2> x \@list
0  ARRAY(0x5651f9b28a10)
   0  'alice'
   1  'bob'
   2  'carol'

  DB<3> x $obj
0  MY::Class=HASH(0x5651fa01c2b0)
   'id' => 42
   'prefs' => HASH(0x5651fa01c330)
      'theme' => 'dark'

עבור מבנים עמוקים או מחזוריים, הגבילו את הרקורסיה:

  DB<4> x 2 \%tree      # recurse 2 levels deep
  DB<5> x 1 $obj        # one level

אם הטוקן הראשון של הביטוי הוא מספרי, השתמשו בסוגריים:

  DB<6> x (3 + $offset)     # without parens, 3 is mis-parsed as depth

V ו־X: משתני חבילה#

V [PKG [VARS]] מבצע dump לגלובלים של חבילה:

  DB<1> V main
$counter = 42
@ARGV = (
    0  '--verbose'
    1  'input.txt'
)
%ENV = (
    'PATH' => '/usr/bin:/bin'
    ...
)

עם ארגומנט שני, סננו משתנים:

  DB<2> V MyApp $config $last_user       # only these
  DB<3> V MyApp ~^config                 # regex: names matching /^config/
  DB<4> V MyApp !^_                      # regex: names NOT matching /^_/

X הוא V עבור החבילה הנוכחית:

  DB<5> X                 # dump current package's globals
  DB<6> X $foo @bar       # filtered

V / X לא רואים לקסיקלים (משתני my). עבור אלה, השתמשו ב־y.

y: לקסיקלים בתחום העוטף#

y LEVEL [VARS] קורא משתני my לקסיקליים דרך PadWalker:

  DB<1> y 0                # lexicals of the current sub
my $req = HTTP::Request=HASH(0x...)
my $user_id = 42
my @errors = ()

  DB<2> y 1                # one frame up (the caller's lexicals)
my $request_count = 118
my $dispatcher = MyApp::Dispatcher=HASH(0x...)

  DB<3> y 0 $req $user_id  # only those

y דורש את PadWalker בגרסה 0.08 או חדשה יותר. הוא עובד רק בתוך sub (לגוף הסקריפט החיצוני אין pad לעבור עליו).

m: מתודות של עצם או מחלקה#

m EXPR מפרט מתודות שניתן לקרוא להן על עצם או מחלקה:

  DB<1> m $user
via UNIVERSAL: isa can DOES VERSION DESTROY
via MyApp::Model: save load delete update
via MyApp::Role::Auditable: audit_log record_event

  DB<2> m 'MyApp::Worker'
via UNIVERSAL: ...
via MyApp::Worker: dispatch retry cancel

מקבץ מתודות לפי החבילה שמספקת אותן - שימושי לאיתור איזה תפקיד או על־מחלקה מספקים מתודה.

M ו־i: מודולים וירושה#

M מפרט מודולים טעונים עם גרסאות:

  DB<1> M
  'DBI' (version 1.643)
  'JSON::PP' (version 4.16)
  'MyApp::Model' (version undef)
  ...

i CLASS או i $obj מדפיס את עץ הירושה:

  DB<2> i $user
MyApp::User 0.12
   MyApp::Model 0.42
      Moo::Object ?

שימושי עבור ״מאיפה המתודה הזו באמת מגיעה?״ כאשר רזולוציית המתודה חוצה מספר תפקידים.

S: שמות תתי־שגרות#

S [[!]PAT] מפרט שמות sub התואמים (או שאינם תואמים) לתבנית:

  DB<1> S ^MyApp::Worker::
MyApp::Worker::cancel
MyApp::Worker::dispatch
MyApp::Worker::retry

  DB<2> S !^(main|DB|UNIVERSAL)::      # everything except these

S לבדו מפרט הכל - ארוך.

p מול x: במה להשתמש מתי#

רוצים

השתמשו

ערך של סקלר יחיד, פשוט

p $x

ביטוי מצורף / מפורמט

p join ',', sort keys %h

hash או מערך

x \%h, x \@a

שדות של עצם

x $obj

רק הרמה העליונה

x 1 $deep_tree

משתני חבילה של Pkg

V Pkg

לקסיקלים של ה־sub הנוכחי

y 0

רשימת המתודות של $obj

m $obj

שרשרת ה־@ISA של $obj

i $obj

מקרה מיוחד: p הוא הדפסה שטוחה. עבור הפניה, p $ref מדפיס HASH(0x…). השתמשו ב־x $ref עבור התוכן.

אפשרויות עומק וקומפקטיות#

פלט ה־dump מעוצב על־ידי אפשרויות הנקבעות באמצעות הפקודה o. ההגדרות הרלוונטיות לבחינה:

אפשרות

השפעה

dumpDepth

עומק רקורסיה (שלילי = ללא הגבלה). ברירת מחדל 4.

arrayDepth

N האלמנטים הראשונים של המערך בלבד; ריק = הכל.

hashDepth

אותו דבר, עבור hashes.

compactDump

מערכים קצרים בשורה אחת.

veryCompact

הדוק עוד יותר.

globPrint

dump של תוכן glob.

DumpReused

הרחבה מלאה של הפניות חוזרות (היזהרו ממחזורים).

quote

" או ' או auto (ברירת מחדל).

undefPrint

כיצד undef מוצג.

bareStringify

הדפסה של הצורה הממורצת על־ידי overload.

קביעת אפשרות בסשן:

  DB<1> o dumpDepth=6
  DB<2> o compactDump=1
  DB<3> o arrayDepth=20
  DB<4> o compactDump?            # query current value

קביעת אפשרויות באתחול באמצעות PERLDB_OPTS או ב־.perldb:

PERLDB_OPTS="dumpDepth=6 compactDump=1" perl -d script.pl

בחינת ה־internals של SV#

Devel::Peek חושף את האחסון הפנימי של הסקלר - type flags, refcount, פריסת PV/NV/IV, שרשרת magic - כאשר השאלה היא ״איזה סוג סקלר זה באמת?״:

  DB<1> use Devel::Peek; Dump($sv)

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

שימו לב: Devel::Peek ב־pperl הוא שכבת תאימות - הוא מדווח על פריסת Sv ספציפית ל־pperl במקום פריסת SV של perl5. לשדות כמו REFCNT, FLAGS, PV, IV, NV יש מקבילים; הפלט המדויק שונה. ראו את מדריך הארכיטקטורה של pperl לפרטי הפריסה.

הערכה ב־prompt#

כל דבר שאינו מזוהה כפקודה מוערך כ־Perl. השתמשו בכך כדי לחקור עמוק יותר מאשר פקודה יחידה:

  DB<1> p keys %{ $obj->{prefs} }
theme,locale,tz

  DB<2> x [ grep { !defined $_->{parent} } @nodes ]
  DB<3> x { map { $_->id => $_->name } @users }

עבור assertions חד־פעמיים ללא עצירה:

  DB<1> die "unexpected" if ref $obj ne 'MyApp::User'

I/O של תוכנית מול I/O של מנפה השגיאות#

הקלט והפלט של מנפה השגיאות עוברים דרך $DB::IN ו־$DB::OUT, אשר פתוחים אל /dev/tty ישירות. התוכנית יכולה להפנות מחדש STDIN / STDOUT / STDERR בחופשיות; ה־prompt של מנפה השגיאות עדיין מופיע. בכיוון ההפוך, פלט p EXPR אינו מזהם את ה־stdout הנלכד של התוכנית.

למידע נוסף#

  • breakpoints - לעצור היכן שניתן לבחון; פרק זה הוא על מה לבחון לאחר שעוצרים.

  • tracing - לצפות בערכים משתנים לאורך זמן מבלי לעצור בכל צעד.