|
2 | 2 | title: Inspect Variables |
3 | 3 | --- |
4 | 4 |
|
5 | | -Inspect variables, objects, arrays, and their properties at any point while execution is paused. |
| 5 | +Stopping is only half of it. The reason to stop somewhere is to look at what the |
| 6 | +code is actually holding at that moment — and the debugger gives your editor |
| 7 | +everything that is in scope, on demand, without you adding a single `var_dump()`. |
6 | 8 |
|
7 | | -:::note |
8 | | -This page is a work in progress — full documentation is coming soon. |
9 | | -::: |
| 9 | +## Stack levels |
| 10 | + |
| 11 | +When execution stops, you are not just at a line. You are at a line inside a |
| 12 | +function, called from another function, called from another, all the way back to |
| 13 | +the entry point. That chain is the call stack, and every frame in it has its own |
| 14 | +set of variables. |
| 15 | + |
| 16 | +Your editor shows it as a list — usually "Call Stack" or "Frames" — with the place |
| 17 | +you stopped at the top and the entry point at the bottom. Clicking any frame |
| 18 | +switches the variables panel to *that* frame's scope. |
| 19 | + |
| 20 | +This is the part people miss, and it is the most useful thing on the page. When a |
| 21 | +function blows up on a value it was handed, the interesting question is rarely what |
| 22 | +that function is holding — it is what the caller passed and where that came from. |
| 23 | +Click one frame up and you are looking at the caller's variables at the exact moment |
| 24 | +it made the call, with everything it had in hand. |
| 25 | + |
| 26 | +You are only reading. Selecting an outer frame changes what you are shown, not |
| 27 | +where execution will resume; the script still continues from where it stopped. |
| 28 | + |
| 29 | +## Reading the values |
| 30 | + |
| 31 | +The variables panel lists what is in scope as a tree. Simple values — strings, |
| 32 | +numbers, booleans, `null` — are shown inline, with their type. |
| 33 | + |
| 34 | +Anything with contents inside it — arrays, objects — arrives **collapsed**, showing |
| 35 | +a summary rather than the contents: the class name, or the number of elements. |
| 36 | +Expanding a node asks the debugger for that node's children, and it answers with |
| 37 | +just those. |
| 38 | + |
| 39 | +That is worth understanding, because it explains the behaviour you will see. The |
| 40 | +debugger does not send you the whole object graph when it stops; it sends the top |
| 41 | +layer and waits. Expanding is a fresh request each time. This is what makes it |
| 42 | +practical to stop inside a framework and open up a container holding half the |
| 43 | +application without the session grinding to a halt. |
| 44 | + |
| 45 | +There are limits on how much comes back in one go, so a very large array is |
| 46 | +returned a chunk at a time, a deeply nested structure is only walked so far down, |
| 47 | +and a very long string is truncated. Editors handle this for you, usually with a |
| 48 | +"show more" affordance at the point where the list was cut off. If you find |
| 49 | +yourself hitting those limits constantly, your editor's settings will have knobs |
| 50 | +for them — they are negotiated per session, so raising them there is enough and no |
| 51 | +`php.ini` change is needed. |
| 52 | + |
| 53 | +Objects show their private and protected properties as well as their public ones, |
| 54 | +which is the whole point of a debugger over a `print_r()`. |
| 55 | + |
| 56 | +## The three groups |
| 57 | + |
| 58 | +Variables arrive in three named groups. Your editor may show them as sections, as |
| 59 | +separate panels, or as a dropdown. |
| 60 | + |
| 61 | +| Group | What is in it | |
| 62 | +| --- | --- | |
| 63 | +| Locals | Everything in scope in the selected frame — parameters, local variables, and `$this` when there is one. | |
| 64 | +| Superglobals | `$_GET`, `$_POST`, `$_SERVER`, `$_SESSION` and friends, plus anything else living at global scope. | |
| 65 | +| User defined constants | Constants defined by your code with `define()`. | |
| 66 | + |
| 67 | +**Locals is the one you will use.** It follows the frame you have selected in the |
| 68 | +stack, so switching frames changes it. Almost everything you go looking for is |
| 69 | +here. |
| 70 | + |
| 71 | +The other two are worth knowing about, and worth not expecting much from. |
| 72 | + |
| 73 | +### Why the other two disappoint |
| 74 | + |
| 75 | +Both made much more sense in the PHP people wrote fifteen years ago. |
| 76 | + |
| 77 | +**Superglobals** mattered when request handling meant reading `$_GET` and `$_POST` |
| 78 | +directly. Any framework written this decade wraps them the moment the request |
| 79 | +arrives and hands you a request object instead, and from that point the framework's |
| 80 | +copy is the truth — it has been filtered, validated, cast, and possibly rewritten |
| 81 | +by middleware. The superglobal still holds the raw original, which is occasionally |
| 82 | +exactly what you want when you suspect the framework of mangling something, and |
| 83 | +irrelevant the rest of the time. Look at the request object in Locals instead. |
| 84 | + |
| 85 | +`$_SERVER` remains genuinely useful for checking what the web server actually |
| 86 | +passed — headers, the resolved path, the environment. |
| 87 | + |
| 88 | +**User defined constants** has the same story and a sharper edge. The list only |
| 89 | +ever contains constants your code defined with `define()` — PHP's own constants and |
| 90 | +those from extensions are deliberately left out, so the list is far shorter than |
| 91 | +you might expect. And `define()` itself has largely been replaced: values that were |
| 92 | +once constants now live as class constants, enum cases, container parameters or |
| 93 | +environment configuration, none of which show up here. |
| 94 | + |
| 95 | +The practical consequence is that on a modern codebase this group is often empty, |
| 96 | +or holds three entries from a bootstrap file. That is not a fault — there is simply |
| 97 | +not much left for it to report. |
0 commit comments