|
2 | 2 | title: Breakpoints |
3 | 3 | --- |
4 | 4 |
|
5 | | -Set line, conditional, and exception breakpoints anywhere in your code, and manage them from your IDE or the CLI. |
| 5 | +A breakpoint tells the debugger when to stop and hand the session to you. You set |
| 6 | +them in your editor; your editor sends them over the connection, and the debugger |
| 7 | +holds them for as long as the session lasts. |
| 8 | + |
| 9 | +Nothing is written to your code and nothing is stored on disk. Every kind described |
| 10 | +below is set the same way — through your editor's own interface — so what follows |
| 11 | +covers what the debugger can do rather than which menu your editor puts it under. |
| 12 | + |
| 13 | +## Line breakpoints |
| 14 | + |
| 15 | +The common case: a file and a line number. Execution stops just before that line |
| 16 | +runs, with the scope at that point available to inspect. |
| 17 | + |
| 18 | +The line has to be one that actually executes. Blank lines, comments, a closing |
| 19 | +brace, a `use` statement at the top of a file — none of these are ever reached, so |
| 20 | +a breakpoint on them never fires. Editors usually move the marker to the next |
| 21 | +executable line; if yours does not, the breakpoint sits there and does nothing. |
| 22 | + |
| 23 | +## Function breakpoints |
| 24 | + |
| 25 | +Instead of a place, name a function and the debugger stops whenever it runs. Useful |
| 26 | +when you know *what* is being called but not *where* from, and it survives moving |
| 27 | +the code around. |
| 28 | + |
| 29 | +Two flavours: |
| 30 | + |
| 31 | +| Kind | Stops | |
| 32 | +| --- | --- | |
| 33 | +| Call | On entry, before the first statement of the body. | |
| 34 | +| Return | On the way out, with the return value available. | |
| 35 | + |
| 36 | +Name a plain function as `myFunction`, and a method as `MyClass::myMethod` for both |
| 37 | +static and instance methods. The name is matched exactly — the debugger is not |
| 38 | +matching a pattern, so a typo simply never fires. |
| 39 | + |
| 40 | +Return breakpoints are the quicker way to answer "what did this actually give |
| 41 | +back?" — you see the value without stepping to the call site to catch it. |
| 42 | + |
| 43 | +## Exception breakpoints |
| 44 | + |
| 45 | +Name an exception class and the debugger stops at the point it is thrown, before |
| 46 | +any `catch` block runs. This is the one that pays for itself: you get the stack as |
| 47 | +it was at the throw, rather than wherever the exception was eventually handled. |
| 48 | + |
| 49 | +Matching follows the class hierarchy — a breakpoint on a parent class catches |
| 50 | +everything below it, so `Throwable` catches every exception and error PHP has. A |
| 51 | +breakpoint on `*` catches all of them without naming anything. |
| 52 | + |
| 53 | +PHP's own error levels can be named the same way, as though they were exception |
| 54 | +classes: |
| 55 | + |
| 56 | +``` |
| 57 | +Warning |
| 58 | +Notice |
| 59 | +Deprecated |
| 60 | +Fatal error |
| 61 | +``` |
| 62 | + |
| 63 | +So a breakpoint on `Warning` stops at the line that raised it, which beats reading |
| 64 | +a log entry after the fact. |
| 65 | + |
| 66 | +## Breaking from your code |
| 67 | + |
| 68 | +When there is no useful line to click on — generated code, a template compiled at |
| 69 | +runtime, a file your editor cannot map to what is really executing — call the |
| 70 | +function instead: |
| 71 | + |
| 72 | +```php |
| 73 | +php_debugger_break(); |
| 74 | +``` |
| 75 | + |
| 76 | +Execution stops there as though you had set a line breakpoint on it. The call |
| 77 | +returns `true` if the debugger stopped and `false` if it could not. |
| 78 | + |
| 79 | +It needs somewhere to stop *to*. With your editor connected it just works. With |
| 80 | +nothing connected it is ignored, and raises a notice, unless |
| 81 | +`php_debugger.on_demand_debugging_enabled=1` lets the debugger attach mid-request — |
| 82 | +see [starting the debugger](./starting-the-debugger.md). |
| 83 | + |
| 84 | +Being real code, it goes in a commit if you are not careful. Prefer a breakpoint set |
| 85 | +from your editor whenever one will do. |
| 86 | + |
| 87 | +## Making a breakpoint fire less often |
| 88 | + |
| 89 | +A breakpoint in a loop, or in a function called from everywhere, stops far more |
| 90 | +often than you want. Two settings narrow it, and they can be combined. |
| 91 | + |
| 92 | +### Conditions |
| 93 | + |
| 94 | +Attach a PHP expression and the debugger only stops when it evaluates to true. The |
| 95 | +expression runs in the scope of the breakpoint, so it can see the local variables |
| 96 | +there: |
| 97 | + |
| 98 | +```php |
| 99 | +$order->getId() === 42 |
| 100 | +$i > 1000 && $found === null |
| 101 | +``` |
| 102 | + |
| 103 | +This is what your editor means by a *conditional breakpoint* — it is an ordinary |
| 104 | +breakpoint with an expression attached, not a separate thing. |
| 105 | + |
| 106 | +The expression is evaluated every time the line is reached, so keep it cheap and |
| 107 | +keep it free of side effects. An expression that fails to evaluate — a typo, a |
| 108 | +variable not in scope — counts as false, and the breakpoint silently never fires. |
| 109 | + |
| 110 | +### Hit counts |
| 111 | + |
| 112 | +A breakpoint counts how many times it has been hit, and can optionally use that |
| 113 | +count to decide whether to stop: |
| 114 | + |
| 115 | +| Condition | Stops | |
| 116 | +| --- | --- | |
| 117 | +| `>= n` | From the nth hit onwards. | |
| 118 | +| `== n` | On the nth hit only. | |
| 119 | +| `% n` | Every nth hit. | |
| 120 | + |
| 121 | +`>= 1` is the same as no hit condition at all, which is the default. |
| 122 | + |
| 123 | +One thing worth knowing when you use both together: **the counter only advances on |
| 124 | +hits where the condition was true.** The condition is evaluated first, and a hit |
| 125 | +that fails it does not count. So a condition of `$i > 100` with a hit count of |
| 126 | +`== 3` stops on the third time the condition held — not on the third time the line |
| 127 | +ran. |
| 128 | + |
| 129 | +## Temporary breakpoints |
| 130 | + |
| 131 | +A temporary breakpoint fires once and then switches itself off. It is the natural |
| 132 | +fit for "get me into this function once so I can look around", and it saves you |
| 133 | +deleting the breakpoint immediately afterwards. |
| 134 | + |
| 135 | +It disables itself rather than deleting itself, so it stays in your editor's list |
| 136 | +and you can switch it back on for another single hit. |
| 137 | + |
| 138 | +## Enabling and disabling |
| 139 | + |
| 140 | +Any breakpoint can be turned off without being removed. A disabled breakpoint keeps |
| 141 | +its line, its condition and its hit count, and stops firing until you turn it back |
| 142 | +on — useful when you are narrowing a problem and want to silence one without losing |
| 143 | +how it was set up. |
| 144 | + |
| 145 | +Disabling is not free, though. The breakpoint is still in the list the debugger |
| 146 | +carries, and still costs something to skip over. |
| 147 | + |
| 148 | +:::tip[Remove breakpoints once you are done with them] |
| 149 | + |
| 150 | +Every breakpoint left behind is checked on every request for the rest of the |
| 151 | +session, and a disabled one is only cheaper, not free. A list that has grown over |
| 152 | +an afternoon of debugging is a slow session that gets blamed on the debugger. |
| 153 | + |
| 154 | +When you have finished with a breakpoint, delete it rather than disabling it. |
6 | 155 |
|
7 | | -:::note |
8 | | -This page is a work in progress — full documentation is coming soon. |
9 | 156 | ::: |
0 commit comments