1 | <?php declare(strict_types = 1); |
||||
2 | |||||
3 | namespace Portiny\Doctrine\Adapter\Nette\Tracy; |
||||
4 | |||||
5 | use Doctrine\DBAL\Logging\SQLLogger; |
||||
6 | use Doctrine\ORM\Cache\Logging\CacheLoggerChain; |
||||
7 | use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger; |
||||
8 | use Doctrine\ORM\EntityManager; |
||||
9 | use Tracy\Debugger; |
||||
10 | use Tracy\Dumper; |
||||
11 | use Tracy\IBarPanel; |
||||
12 | |||||
13 | /** |
||||
14 | * Debug panel for Doctrine |
||||
15 | * |
||||
16 | * @author David Grudl |
||||
17 | * @author Patrik Votoček |
||||
18 | * @author Jan Mareš |
||||
19 | * @author Tomáš Pilař |
||||
20 | */ |
||||
21 | final class DoctrineSQLPanel implements IBarPanel, SQLLogger |
||||
0 ignored issues
–
show
|
|||||
22 | { |
||||
23 | public const DATA_INDEX_SQL = 0; |
||||
24 | |||||
25 | public const DATA_INDEX_PARAMS = 1; |
||||
26 | |||||
27 | public const DATA_INDEX_TYPES = 2; |
||||
28 | |||||
29 | public const DATA_INDEX_TIME = 3; |
||||
30 | |||||
31 | public const DATA_INDEX_TRACE = 4; |
||||
32 | |||||
33 | public const DATA_INDEX_COUNT = 5; |
||||
34 | |||||
35 | /** |
||||
36 | * @var int |
||||
37 | */ |
||||
38 | private $totalTime = 0; |
||||
39 | |||||
40 | /** |
||||
41 | * @var bool |
||||
42 | */ |
||||
43 | private $sortQueries = false; |
||||
44 | |||||
45 | /** |
||||
46 | * @var array |
||||
47 | */ |
||||
48 | private $queries = []; |
||||
49 | |||||
50 | /** |
||||
51 | * @var EntityManager |
||||
52 | */ |
||||
53 | private $entityManager; |
||||
54 | |||||
55 | |||||
56 | 4 | public function __construct(EntityManager $entityManager) |
|||
57 | { |
||||
58 | 4 | $this->entityManager = $entityManager; |
|||
59 | 4 | } |
|||
60 | |||||
61 | |||||
62 | /** |
||||
63 | * {@inheritdoc} |
||||
64 | */ |
||||
65 | 4 | public function startQuery($sql, ?array $params = null, ?array $types = null): void |
|||
66 | { |
||||
67 | 4 | Debugger::timer('doctrine'); |
|||
68 | |||||
69 | 4 | $this->queries[] = [ |
|||
70 | 4 | self::DATA_INDEX_SQL => $sql, |
|||
71 | 4 | self::DATA_INDEX_PARAMS => $params, |
|||
72 | 4 | self::DATA_INDEX_TYPES => $types, |
|||
73 | 4 | self::DATA_INDEX_TIME => 0, |
|||
74 | 4 | self::DATA_INDEX_TRACE => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), |
|||
75 | ]; |
||||
76 | 4 | } |
|||
77 | |||||
78 | |||||
79 | /** |
||||
80 | * {@inheritdoc} |
||||
81 | */ |
||||
82 | 4 | public function stopQuery(): void |
|||
83 | { |
||||
84 | 4 | $keys = array_keys($this->queries); |
|||
85 | 4 | $key = end($keys); |
|||
86 | 4 | $this->queries[$key][self::DATA_INDEX_TIME] = Debugger::timer('doctrine'); |
|||
87 | 4 | $this->totalTime += $this->queries[$key][self::DATA_INDEX_TIME]; |
|||
88 | 4 | } |
|||
89 | |||||
90 | |||||
91 | /** |
||||
92 | * {@inheritdoc} |
||||
93 | */ |
||||
94 | 1 | public function getTab(): string |
|||
95 | { |
||||
96 | return '<span title="Doctrine 2">' |
||||
97 | . '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAKT2lDQ1BQaG90b3Nob3A' |
||||
98 | . 'gSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIo' |
||||
99 | . 'K2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDw' |
||||
100 | . 'rIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl' |
||||
101 | . '7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABR' |
||||
102 | . 'G8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8' |
||||
103 | . 't6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcp' |
||||
104 | . 'Xff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcU' |
||||
105 | . 'l0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAA' |
||||
106 | . 'ARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLy' |
||||
107 | . 'BCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLV' |
||||
108 | . 'Duag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQ' |
||||
109 | . 'SgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkm' |
||||
110 | . 'xpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2' |
||||
111 | . 'ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl' |
||||
112 | . '3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61M' |
||||
113 | . 'bU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvO' |
||||
114 | . 'UZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9l' |
||||
115 | . 'T3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcN' |
||||
116 | . 'AQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2B' |
||||
117 | . 'aeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8W' |
||||
118 | . 'uw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc' |
||||
119 | . '+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrde' |
||||
120 | . 'wt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1' |
||||
121 | . 'BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU8' |
||||
122 | . '5ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJT' |
||||
123 | . 'wQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZB' |
||||
124 | . 'xQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsI' |
||||
125 | . 'S4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+' |
||||
126 | . '1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7Z' |
||||
127 | . 'DuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXH' |
||||
128 | . 'txwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRpt' |
||||
129 | . 'TmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK' |
||||
130 | . '4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu' |
||||
131 | . '72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6' |
||||
132 | . 'i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8' |
||||
133 | . 'EA5jz/GMzLdsAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQffCxUPDinoxmA5AAABO1BMVEUAAADjcTnqakDwgzrxgz7ziDv' |
||||
134 | . '1gz72iUD5hz35iD75iT7/gAD/gED/gEf/gID/iz25VS33hDv3iUjngzf/hT7xgTz3hj31gTz8iTv4hj7tfTr5hj77ij78iT73hj3' |
||||
135 | . '6iD37hkD8iT35hz77hz77iT73hj36hz76hz/6hz76iD79iD/2hTz7iD75hz37iD76iD77iT75hz77iT75iD78ij/6iT/6iT74hz7' |
||||
136 | . '3hj37hz33hj30hD31gDb1gjj1gjn1hDr1hDv1hTz1hT31iEP1iUP2hT32hT72hj32i0b2lVX3hTr3hj33hz73k1L3mFz3mV33ml7' |
||||
137 | . '3m1/3nGP4hjz4hz74n2X4oGf4qXf4sYL5hz76iD781bz83cr849H96dz969/+7uT+8+v+8+3+9O7+9/H++PT//Pv//v7///+xeeL' |
||||
138 | . 'XAAAAO3RSTlMAAAAAAAAAAAAAAAAAAAAAAgUGBw0QEBERFBUZHR4fKSotP0RKW15lc32GlaWsydvo6err6+z2+vv8/YuXaogAAAA' |
||||
139 | . 'BYktHRGjLbPQiAAAAuklEQVQYGQXBhyIVABQA0FNkr6zsGTKzZT83e5Vsks39/y/oHFD7ZbC+HADMLU82qgRQaSpivsUHAGVtCxE' |
||||
140 | . '37aoBRRrGI+K6B1BhZGntVyHisB8wtBOX+bq7EWfdxfjUfBPx8yHf9wrxHfTF6vHvk5fMP4UfdTAafzMzM3NzqwsG4ur56fEt837' |
||||
141 | . 'loAk6D6Kwfp75by1moMpExEXmXcTOMPB5No7yNmJ7TA3g2+Lp/vX0VyWAUjp6W/mI/zsxJP3EcQMdAAAAAElFTkSuQmCC" />' |
||||
142 | 1 | . count($this->queries) . ' queries' |
|||
143 | 1 | . ($this->totalTime ? ' / ' . sprintf('%0.1f', $this->totalTime * 1000) . 'ms' : '') |
|||
144 | 1 | . '</span>'; |
|||
145 | } |
||||
146 | |||||
147 | |||||
148 | /** |
||||
149 | * {@inheritdoc} |
||||
150 | */ |
||||
151 | 1 | public function getPanel(): string |
|||
152 | { |
||||
153 | 1 | $s = ''; |
|||
154 | |||||
155 | 1 | if ($this->sortQueries) { |
|||
156 | $this->queries = $this->sortQueries($this->queries, self::DATA_INDEX_TIME); |
||||
157 | } |
||||
158 | |||||
159 | 1 | foreach ($this->queries as $query) { |
|||
160 | 1 | $s .= $this->processQuery($query); |
|||
161 | } |
||||
162 | |||||
163 | 1 | return $this->renderStyles() . |
|||
164 | 1 | '<h1>Queries: ' . count($this->queries) . |
|||
165 | 1 | ($this->totalTime ? ', time: ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms' : '') . |
|||
166 | 1 | '</h1> |
|||
167 | <div class="tracy-inner nette-Doctrine2Panel"> |
||||
168 | 1 | ' . $this->renderPanelCacheStatistics() . ' |
|||
169 | <h2>Queries</h2> |
||||
170 | <table> |
||||
171 | 1 | <tr><th>Time ms</th><th>SQL</th><th>Params</th><th>Trace</th></tr>' . $s . |
|||
172 | 1 | '</table> |
|||
173 | </div>'; |
||||
174 | } |
||||
175 | |||||
176 | |||||
177 | /** |
||||
178 | * Binds panel to debug bar. |
||||
179 | */ |
||||
180 | public function bindToBar(): void |
||||
181 | { |
||||
182 | if (! $this->isTracyEnabled()) { |
||||
183 | return; |
||||
184 | } |
||||
185 | |||||
186 | $this->entityManager->getConfiguration()->setSQLLogger($this); |
||||
0 ignored issues
–
show
The function
Doctrine\DBAL\Configuration::setSQLLogger() has been deprecated: Use {@see setMiddlewares()} and {@see \Doctrine\DBAL\Logging\Middleware} instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||
187 | Debugger::getBar()->addPanel($this); |
||||
188 | } |
||||
189 | |||||
190 | |||||
191 | /** |
||||
192 | * @param bool $sortQueries |
||||
193 | */ |
||||
194 | public function setSortQueries($sortQueries): void |
||||
195 | { |
||||
196 | $this->sortQueries = $sortQueries; |
||||
197 | } |
||||
198 | |||||
199 | |||||
200 | 2 | public function getQueries(): array |
|||
201 | { |
||||
202 | 2 | return $this->queries; |
|||
203 | } |
||||
204 | |||||
205 | |||||
206 | private function sortQueries(array $queries, int $key): array |
||||
207 | { |
||||
208 | uasort( |
||||
209 | $queries, |
||||
210 | function ($a, $b) use ($key) { |
||||
211 | if ($a[$key] === $b[$key]) { |
||||
212 | return 0; |
||||
213 | } |
||||
214 | |||||
215 | return $a[$key] > $b[$key] ? -1 : 1; |
||||
216 | } |
||||
217 | ); |
||||
218 | |||||
219 | return $queries; |
||||
220 | } |
||||
221 | |||||
222 | |||||
223 | 1 | private function processQuery(array $query): string |
|||
224 | { |
||||
225 | 1 | $s = '<tr>'; |
|||
226 | 1 | $s .= '<td>' . sprintf('%0.3f', $query[self::DATA_INDEX_TIME] * 1000); |
|||
227 | |||||
228 | 1 | if (isset($query[self::DATA_INDEX_COUNT])) { |
|||
229 | $s .= '/' . sprintf('%d', $query[self::DATA_INDEX_COUNT]); |
||||
230 | } |
||||
231 | |||||
232 | 1 | $s .= '</td>'; |
|||
233 | |||||
234 | $s .= '<td class="nette-Doctrine2Panel-sql" style="min-width: 400px">' . |
||||
235 | 1 | Helper::dumpSql($query[self::DATA_INDEX_SQL]); |
|||
236 | |||||
237 | 1 | $s .= '</td>'; |
|||
238 | 1 | $s .= '<td>' . Dumper::toHtml($query[self::DATA_INDEX_PARAMS]) . '</td>'; |
|||
239 | 1 | $s .= '<td>' . Dumper::toHtml($query[self::DATA_INDEX_TRACE]) . '</td>'; |
|||
240 | 1 | $s .= '</tr>'; |
|||
241 | |||||
242 | 1 | return $s; |
|||
243 | } |
||||
244 | |||||
245 | |||||
246 | 1 | private function renderStyles(): string |
|||
247 | { |
||||
248 | 1 | return '<style> |
|||
249 | #tracy-debug td.nette-Doctrine2Panel-sql { background: white !important } |
||||
250 | #tracy-debug .nette-Doctrine2Panel-source { color: #BBB !important } |
||||
251 | #tracy-debug div.tracy-inner.nette-Doctrine2Panel { max-width: 1000px } |
||||
252 | #tracy-debug .nette-Doctrine2Panel tr table { margin: 8px 0; max-height: 150px; overflow:auto } |
||||
253 | #tracy-debug .nette-Doctrine2Panel-cache-green { color: green !important; font-weight: bold } |
||||
254 | #tracy-debug .nette-Doctrine2Panel-cache-red { color: red !important; font-weight: bold } |
||||
255 | #tracy-debug .nette-Doctrine2Panel h2 { font-size: 23px; } |
||||
256 | </style>'; |
||||
257 | } |
||||
258 | |||||
259 | |||||
260 | 1 | private function renderPanelCacheStatistics(): string |
|||
261 | { |
||||
262 | 1 | if (empty($this->entityManager)) { |
|||
263 | return ''; |
||||
264 | } |
||||
265 | |||||
266 | 1 | $config = $this->entityManager->getConfiguration(); |
|||
267 | 1 | if (! $config->isSecondLevelCacheEnabled()) { |
|||
268 | 1 | return ''; |
|||
269 | } |
||||
270 | |||||
271 | $cacheConfiguration = $config->getSecondLevelCacheConfiguration(); |
||||
272 | if (! $cacheConfiguration) { |
||||
273 | return ''; |
||||
274 | } |
||||
275 | |||||
276 | $cacheLogger = $cacheConfiguration->getCacheLogger(); |
||||
277 | if (! $cacheLogger instanceof CacheLoggerChain) { |
||||
278 | return ''; |
||||
279 | } |
||||
280 | |||||
281 | /** @var StatisticsCacheLogger|null $statistics */ |
||||
282 | $statistics = $cacheLogger->getLogger('statistics'); |
||||
283 | if (! $statistics) { |
||||
0 ignored issues
–
show
|
|||||
284 | return ''; |
||||
285 | } |
||||
286 | |||||
287 | $cacheDriver = $this->entityManager->getConfiguration()->getMetadataCacheImpl(); |
||||
0 ignored issues
–
show
The function
Doctrine\ORM\Configuration::getMetadataCacheImpl() has been deprecated: Deprecated in favor of getMetadataCache
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||
288 | $driverInformation = ''; |
||||
289 | if ($cacheDriver) { |
||||
290 | $driverInformation = get_class($cacheDriver); |
||||
291 | } |
||||
292 | |||||
293 | return '<h2>Second Level Cache</h2> |
||||
294 | <table> |
||||
295 | <tr> |
||||
296 | <td>Driver</td> |
||||
297 | <td><strong>' . $driverInformation . '</strong></td> |
||||
298 | </tr> |
||||
299 | <tr> |
||||
300 | <td>Cache hits</td> |
||||
301 | <td> |
||||
302 | <strong class="nette-Doctrine2Panel-cache-green">' . $statistics->getHitCount() . '</strong> |
||||
303 | </td> |
||||
304 | </tr> |
||||
305 | <tr> |
||||
306 | <td>Cache misses</td> |
||||
307 | <td> |
||||
308 | <strong class="nette-Doctrine2Panel-cache-red">' . $statistics->getMissCount() . '</strong> |
||||
309 | </td> |
||||
310 | </tr> |
||||
311 | <tr> |
||||
312 | <td>Cache puts</td> |
||||
313 | <td> |
||||
314 | <strong class="nette-Doctrine2Panel-cache-red">' . $statistics->getPutCount() . '</strong> |
||||
315 | </td> |
||||
316 | </tr> |
||||
317 | </table>'; |
||||
318 | } |
||||
319 | |||||
320 | |||||
321 | private function isTracyEnabled(): bool |
||||
322 | { |
||||
323 | return PHP_SAPI !== 'cli' && Debugger::isEnabled() && ! Debugger::$productionMode; |
||||
0 ignored issues
–
show
The expression
Tracy\Debugger::productionMode of type boolean|null is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
|
|||||
324 | } |
||||
325 | |||||
326 | } |
||||
327 |
This interface has been deprecated. The supplier of the interface has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.