XdebugHandler::check()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 40
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 20
c 1
b 0
f 0
dl 0
loc 40
rs 8.4444
cc 8
nc 6
nop 0
1
<?php
2
3
/*
4
 * This file is part of composer/xdebug-handler.
5
 *
6
 * (c) Composer <https://github.com/composer>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace Composer\XdebugHandler;
13
14
use Psr\Log\LoggerInterface;
15
16
/**
17
 * @author John Stevenson <[email protected]>
18
 */
19
class XdebugHandler
20
{
21
    const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
22
    const SUFFIX_INIS = '_ORIGINAL_INIS';
23
    const RESTART_ID = 'internal';
24
    const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
25
    const DEBUG = 'XDEBUG_HANDLER_DEBUG';
26
27
    /** @var string|null */
28
    protected $tmpIni;
29
30
    private static $inRestart;
31
    private static $name;
32
    private static $skipped;
33
    private static $xdebugActive;
34
35
    private $cli;
36
    private $debug;
37
    private $envAllowXdebug;
38
    private $envOriginalInis;
39
    private $loaded;
40
    private $mode;
41
    private $persistent;
42
    private $script;
43
    /** @var Status|null */
44
    private $statusWriter;
45
46
    /**
47
     * Constructor
48
     *
49
     * The $envPrefix is used to create distinct environment variables. It is
50
     * uppercased and prepended to the default base values. For example 'myapp'
51
     * would result in MYAPP_ALLOW_XDEBUG and MYAPP_ORIGINAL_INIS.
52
     *
53
     * @param string $envPrefix Value used in environment variables
54
     * @throws \RuntimeException If the parameter is invalid
55
     */
56
    public function __construct($envPrefix)
57
    {
58
        if (!is_string($envPrefix) || empty($envPrefix)) {
0 ignored issues
show
introduced by
The condition is_string($envPrefix) is always true.
Loading history...
59
            throw new \RuntimeException('Invalid constructor parameter');
60
        }
61
62
        self::$name = strtoupper($envPrefix);
63
        $this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
64
        $this->envOriginalInis = self::$name.self::SUFFIX_INIS;
65
66
        if (extension_loaded('xdebug')) {
67
            $this->loaded = phpversion('xdebug') ?: 'unknown';
68
69
            if (false !== ($mode = ini_get('xdebug.mode'))) {
70
                $this->mode = getenv('XDEBUG_MODE') ?: ($mode  ?: 'off');
71
                if (preg_match('/^,+$/', str_replace(' ', '', $this->mode))) {
72
                    $this->mode = 'off';
73
                }
74
            }
75
        }
76
77
        self::$xdebugActive = $this->loaded && $this->mode !== 'off';
78
79
        if ($this->cli = PHP_SAPI === 'cli') {
80
            $this->debug = getenv(self::DEBUG);
81
        }
82
83
        $this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
84
    }
85
86
    /**
87
     * Activates status message output to a PSR3 logger
88
     *
89
     * @param LoggerInterface $logger
90
     *
91
     * @return $this
92
     */
93
    public function setLogger(LoggerInterface $logger)
94
    {
95
        $this->statusWriter->setLogger($logger);
0 ignored issues
show
Bug introduced by
The method setLogger() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

95
        $this->statusWriter->/** @scrutinizer ignore-call */ 
96
                             setLogger($logger);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
96
        return $this;
97
    }
98
99
    /**
100
     * Sets the main script location if it cannot be called from argv
101
     *
102
     * @param string $script
103
     *
104
     * @return $this
105
     */
106
    public function setMainScript($script)
107
    {
108
        $this->script = $script;
109
        return $this;
110
    }
111
112
    /**
113
     * Persist the settings to keep Xdebug out of sub-processes
114
     *
115
     * @return $this
116
     */
117
    public function setPersistent()
118
    {
119
        $this->persistent = true;
120
        return $this;
121
    }
122
123
    /**
124
     * Checks if Xdebug is loaded and the process needs to be restarted
125
     *
126
     * This behaviour can be disabled by setting the MYAPP_ALLOW_XDEBUG
127
     * environment variable to 1. This variable is used internally so that
128
     * the restarted process is created only once.
129
     */
130
    public function check()
131
    {
132
        $this->notify(Status::CHECK, $this->loaded.'|'.$this->mode);
133
        $envArgs = explode('|', (string) getenv($this->envAllowXdebug));
134
135
        if (empty($envArgs[0]) && $this->requiresRestart(self::$xdebugActive)) {
136
            // Restart required
137
            $this->notify(Status::RESTART);
138
139
            if ($this->prepareRestart()) {
140
                $command = $this->getCommand();
141
                $this->restart($command);
142
            }
143
            return;
144
        }
145
146
        if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
147
            // Restarted, so unset environment variable and use saved values
148
            $this->notify(Status::RESTARTED);
149
150
            Process::setEnv($this->envAllowXdebug);
151
            self::$inRestart = true;
152
153
            if (!$this->loaded) {
154
                // Skipped version is only set if Xdebug is not loaded
155
                self::$skipped = $envArgs[1];
156
            }
157
158
            $this->tryEnableSignals();
159
160
            // Put restart settings in the environment
161
            $this->setEnvRestartSettings($envArgs);
162
            return;
163
        }
164
165
        $this->notify(Status::NORESTART);
166
167
        if ($settings = self::getRestartSettings()) {
168
            // Called with existing settings, so sync our settings
169
            $this->syncSettings($settings);
170
        }
171
    }
172
173
    /**
174
     * Returns an array of php.ini locations with at least one entry
175
     *
176
     * The equivalent of calling php_ini_loaded_file then php_ini_scanned_files.
177
     * The loaded ini location is the first entry and may be empty.
178
     *
179
     * @return array
180
     */
181
    public static function getAllIniFiles()
182
    {
183
        if (!empty(self::$name)) {
184
            $env = getenv(self::$name.self::SUFFIX_INIS);
185
186
            if (false !== $env) {
187
                return explode(PATH_SEPARATOR, $env);
188
            }
189
        }
190
191
        $paths = array((string) php_ini_loaded_file());
192
193
        if ($scanned = php_ini_scanned_files()) {
194
            $paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
195
        }
196
197
        return $paths;
198
    }
199
200
    /**
201
     * Returns an array of restart settings or null
202
     *
203
     * Settings will be available if the current process was restarted, or
204
     * called with the settings from an existing restart.
205
     *
206
     * @return array|null
207
     */
208
    public static function getRestartSettings()
209
    {
210
        $envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
211
212
        if (count($envArgs) !== 6
213
            || (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
214
            return null;
215
        }
216
217
        return array(
218
            'tmpIni' => $envArgs[0],
219
            'scannedInis' => (bool) $envArgs[1],
220
            'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
221
            'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
222
            'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
223
            'skipped' => $envArgs[5],
224
        );
225
    }
226
227
    /**
228
     * Returns the Xdebug version that triggered a successful restart
229
     *
230
     * @return string
231
     */
232
    public static function getSkippedVersion()
233
    {
234
        return (string) self::$skipped;
235
    }
236
237
    /**
238
     * Returns whether Xdebug is loaded and active
239
     *
240
     * true: if Xdebug is loaded and is running in an active mode.
241
     * false: if Xdebug is not loaded, or it is running with xdebug.mode=off.
242
     *
243
     * @return bool
244
     */
245
    public static function isXdebugActive()
246
    {
247
        return self::$xdebugActive;
248
    }
249
250
    /**
251
     * Allows an extending class to decide if there should be a restart
252
     *
253
     * The default is to restart if Xdebug is loaded and its mode is not "off".
254
     * Do not typehint for 1.x compatibility.
255
     *
256
     * @param bool $default The default behaviour
257
     *
258
     * @return bool Whether the process should restart
259
     */
260
    protected function requiresRestart($default)
261
    {
262
        return $default;
263
    }
264
265
    /**
266
     * Allows an extending class to access the tmpIni
267
     *
268
     * Do not typehint for 1.x compatibility
269
     *
270
     * @param array $command
271
     */
272
    protected function restart($command)
273
    {
274
        $this->doRestart($command);
275
    }
276
277
    /**
278
     * Executes the restarted command then deletes the tmp ini
279
     *
280
     * @param array $command
281
     */
282
    private function doRestart(array $command)
283
    {
284
        $this->tryEnableSignals();
285
        $this->notify(Status::RESTARTING, implode(' ', $command));
286
287
        if (PHP_VERSION_ID >= 70400) {
288
            $cmd = $command;
289
        } else {
290
            $cmd = Process::escapeShellCommand($command);
291
            if (defined('PHP_WINDOWS_VERSION_BUILD')) {
292
                // Outer quotes required on cmd string below PHP 8
293
                $cmd = '"'.$cmd.'"';
294
            }
295
        }
296
297
        $process = proc_open($cmd, array(), $pipes);
298
        if (is_resource($process)) {
299
            $exitCode = proc_close($process);
300
        }
301
302
        if (!isset($exitCode)) {
303
            // Unlikely that php or the default shell cannot be invoked
304
            $this->notify(Status::ERROR, 'Unable to restart process');
305
            $exitCode = -1;
306
        } else {
307
            $this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
308
        }
309
310
        if ($this->debug === '2') {
311
            $this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
312
        } else {
313
            @unlink($this->tmpIni);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

313
            /** @scrutinizer ignore-unhandled */ @unlink($this->tmpIni);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Bug introduced by
It seems like $this->tmpIni can also be of type null; however, parameter $filename of unlink() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

313
            @unlink(/** @scrutinizer ignore-type */ $this->tmpIni);
Loading history...
314
        }
315
316
        exit($exitCode);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
Comprehensibility Best Practice introduced by
The variable $exitCode does not seem to be defined for all execution paths leading up to this point.
Loading history...
317
    }
318
319
    /**
320
     * Returns true if everything was written for the restart
321
     *
322
     * If any of the following fails (however unlikely) we must return false to
323
     * stop potential recursion:
324
     *   - tmp ini file creation
325
     *   - environment variable creation
326
     *
327
     * @return bool
328
     */
329
    private function prepareRestart()
330
    {
331
        $error = '';
332
        $iniFiles = self::getAllIniFiles();
333
        $scannedInis = count($iniFiles) > 1;
334
        $tmpDir = sys_get_temp_dir();
335
336
        if (!$this->cli) {
337
            $error = 'Unsupported SAPI: '.PHP_SAPI;
338
        } elseif (!defined('PHP_BINARY')) {
339
            $error = 'PHP version is too old: '.PHP_VERSION;
340
        } elseif (!$this->checkConfiguration($info)) {
341
            $error = $info;
342
        } elseif (!$this->checkScanDirConfig()) {
343
            $error = 'PHP version does not report scanned inis: '.PHP_VERSION;
344
        } elseif (!$this->checkMainScript()) {
345
            $error = 'Unable to access main script: '.$this->script;
346
        } elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
347
            $error = $error ?: 'Unable to create temp ini file at: '.$tmpDir;
348
        } elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
349
            $error = 'Unable to set environment variables';
350
        }
351
352
        if ($error) {
353
            $this->notify(Status::ERROR, $error);
354
        }
355
356
        return empty($error);
357
    }
358
359
    /**
360
     * Returns true if the tmp ini file was written
361
     *
362
     * @param array $iniFiles All ini files used in the current process
363
     * @param string $tmpDir The system temporary directory
364
     * @param string $error Set by method if ini file cannot be read
365
     *
366
     * @return bool
367
     */
368
    private function writeTmpIni(array $iniFiles, $tmpDir, &$error)
369
    {
370
        if (!$this->tmpIni = @tempnam($tmpDir, '')) {
0 ignored issues
show
Documentation Bug introduced by
It seems like @tempnam($tmpDir, '') can also be of type false. However, the property $tmpIni is declared as type null|string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
371
            return false;
372
        }
373
374
        // $iniFiles has at least one item and it may be empty
375
        if (empty($iniFiles[0])) {
376
            array_shift($iniFiles);
377
        }
378
379
        $content = '';
380
        $regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
381
382
        foreach ($iniFiles as $file) {
383
            // Check for inaccessible ini files
384
            if (($data = @file_get_contents($file)) === false) {
385
                $error = 'Unable to read ini: '.$file;
386
                return false;
387
            }
388
            $content .= preg_replace($regex, ';$1', $data).PHP_EOL;
389
        }
390
391
        // Merge loaded settings into our ini content, if it is valid
392
        if ($config = parse_ini_string($content)) {
393
            $loaded = ini_get_all(null, false);
394
            $content .= $this->mergeLoadedConfig($loaded, $config);
395
        }
396
397
        // Work-around for https://bugs.php.net/bug.php?id=75932
398
        $content .= 'opcache.enable_cli=0'.PHP_EOL;
399
400
        return @file_put_contents($this->tmpIni, $content);
0 ignored issues
show
Bug Best Practice introduced by
The expression return @file_put_content...this->tmpIni, $content) also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
401
    }
402
403
    /**
404
     * Returns the command line arguments for the restart
405
     *
406
     * @return array
407
     */
408
    private function getCommand()
409
    {
410
        $php = array(PHP_BINARY);
411
        $args = array_slice($_SERVER['argv'], 1);
412
413
        if (!$this->persistent) {
414
            // Use command-line options
415
            array_push($php, '-n', '-c', $this->tmpIni);
416
        }
417
418
        return array_merge($php, array($this->script), $args);
419
    }
420
421
    /**
422
     * Returns true if the restart environment variables were set
423
     *
424
     * No need to update $_SERVER since this is set in the restarted process.
425
     *
426
     * @param bool $scannedInis Whether there were scanned ini files
427
     * @param array $iniFiles All ini files used in the current process
428
     *
429
     * @return bool
430
     */
431
    private function setEnvironment($scannedInis, array $iniFiles)
432
    {
433
        $scanDir = getenv('PHP_INI_SCAN_DIR');
434
        $phprc = getenv('PHPRC');
435
436
        // Make original inis available to restarted process
437
        if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
438
            return false;
439
        }
440
441
        if ($this->persistent) {
442
            // Use the environment to persist the settings
443
            if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) {
444
                return false;
445
            }
446
        }
447
448
        // Flag restarted process and save values for it to use
449
        $envArgs = array(
450
            self::RESTART_ID,
451
            $this->loaded,
452
            (int) $scannedInis,
453
            false === $scanDir ? '*' : $scanDir,
454
            false === $phprc ? '*' : $phprc,
455
        );
456
457
        return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
458
    }
459
460
    /**
461
     * Logs status messages
462
     *
463
     * @param string $op Status handler constant
464
     * @param null|string $data Optional data
465
     */
466
    private function notify($op, $data = null)
467
    {
468
        $this->statusWriter->report($op, $data);
469
    }
470
471
    /**
472
     * Returns default, changed and command-line ini settings
473
     *
474
     * @param array $loadedConfig All current ini settings
475
     * @param array $iniConfig Settings from user ini files
476
     *
477
     * @return string
478
     */
479
    private function mergeLoadedConfig(array $loadedConfig, array $iniConfig)
480
    {
481
        $content = '';
482
483
        foreach ($loadedConfig as $name => $value) {
484
            // Value will either be null, string or array (HHVM only)
485
            if (!is_string($value)
486
                || strpos($name, 'xdebug') === 0
487
                || $name === 'apc.mmap_file_mask') {
488
                continue;
489
            }
490
491
            if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
492
                // Double-quote escape each value
493
                $content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
494
            }
495
        }
496
497
        return $content;
498
    }
499
500
    /**
501
     * Returns true if the script name can be used
502
     *
503
     * @return bool
504
     */
505
    private function checkMainScript()
506
    {
507
        if (null !== $this->script) {
508
            // Allow an application to set -- for standard input
509
            return file_exists($this->script) || '--' === $this->script;
510
        }
511
512
        if (file_exists($this->script = $_SERVER['argv'][0])) {
513
            return true;
514
        }
515
516
        // Use a backtrace to resolve Phar and chdir issues
517
        $options = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : false;
518
        $trace = debug_backtrace($options);
0 ignored issues
show
Bug introduced by
It seems like $options can also be of type false; however, parameter $options of debug_backtrace() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

518
        $trace = debug_backtrace(/** @scrutinizer ignore-type */ $options);
Loading history...
519
520
        if (($main = end($trace)) && isset($main['file'])) {
521
            return file_exists($this->script = $main['file']);
522
        }
523
524
        return false;
525
    }
526
527
    /**
528
     * Adds restart settings to the environment
529
     *
530
     * @param string[] $envArgs
531
     */
532
    private function setEnvRestartSettings($envArgs)
533
    {
534
        $settings = array(
535
            php_ini_loaded_file(),
536
            $envArgs[2],
537
            $envArgs[3],
538
            $envArgs[4],
539
            getenv($this->envOriginalInis),
540
            self::$skipped,
541
        );
542
543
        Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
544
    }
545
546
    /**
547
     * Syncs settings and the environment if called with existing settings
548
     *
549
     * @param array $settings
550
     */
551
    private function syncSettings(array $settings)
552
    {
553
        if (false === getenv($this->envOriginalInis)) {
554
            // Called by another app, so make original inis available
555
            Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
556
        }
557
558
        self::$skipped = $settings['skipped'];
559
        $this->notify(Status::INFO, 'Process called with existing restart settings');
560
    }
561
562
    /**
563
     * Returns true if there are scanned inis and PHP is able to report them
564
     *
565
     * php_ini_scanned_files will fail when PHP_CONFIG_FILE_SCAN_DIR is empty.
566
     * Fixed in 7.1.13 and 7.2.1
567
     *
568
     * @return bool
569
     */
570
    private function checkScanDirConfig()
571
    {
572
        return !(getenv('PHP_INI_SCAN_DIR')
573
            && !PHP_CONFIG_FILE_SCAN_DIR
574
            && (PHP_VERSION_ID < 70113
575
            || PHP_VERSION_ID === 70200));
576
    }
577
578
    /**
579
     * Returns true if there are no known configuration issues
580
     *
581
     * @param string $info Set by method
582
     * @return bool
583
     */
584
    private function checkConfiguration(&$info)
585
    {
586
        if (!function_exists('proc_open')) {
587
            $info = 'proc_open function is disabled';
588
            return false;
589
        }
590
591
        if (extension_loaded('uopz') && !ini_get('uopz.disable')) {
592
            // uopz works at opcode level and disables exit calls
593
            if (function_exists('uopz_allow_exit')) {
594
                @uopz_allow_exit(true);
0 ignored issues
show
Bug introduced by
Are you sure the usage of uopz_allow_exit(true) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Security Best Practice introduced by
It seems like you do not handle an error condition for uopz_allow_exit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

594
                /** @scrutinizer ignore-unhandled */ @uopz_allow_exit(true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
595
            } else {
596
                $info = 'uopz extension is not compatible';
597
                return false;
598
            }
599
        }
600
601
602
        $workingDir = getcwd();
603
        if (0 === strpos($workingDir, '\\\\')) {
604
            if (defined('PHP_WINDOWS_VERSION_BUILD') && PHP_VERSION_ID < 70400) {
605
                $info = 'cmd.exe does not support UNC paths: '.$workingDir;
606
                return false;
607
            }
608
        }
609
610
        return true;
611
    }
612
613
    /**
614
     * Enables async signals and control interrupts in the restarted process
615
     *
616
     * Available on Unix PHP 7.1+ with the pcntl extension and Windows PHP 7.4+.
617
     */
618
    private function tryEnableSignals()
619
    {
620
        if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
621
            pcntl_async_signals(true);
622
            $message = 'Async signals enabled';
0 ignored issues
show
Unused Code introduced by
The assignment to $message is dead and can be removed.
Loading history...
623
624
            if (!self::$inRestart) {
625
                // Restarting, so ignore SIGINT in parent
626
                pcntl_signal(SIGINT, SIG_IGN);
627
            } elseif (is_int(pcntl_signal_get_handler(SIGINT))) {
0 ignored issues
show
introduced by
The condition is_int(pcntl_signal_get_...\XdebugHandler\SIGINT)) is always false.
Loading history...
628
                // Restarted, no handler set so force default action
629
                pcntl_signal(SIGINT, SIG_DFL);
630
            }
631
        }
632
633
        if (!self::$inRestart && function_exists('sapi_windows_set_ctrl_handler')) {
634
            // Restarting, so set a handler to ignore CTRL events in the parent.
635
            // This ensures that CTRL+C events will be available in the child
636
            // process without having to enable them there, which is unreliable.
637
            sapi_windows_set_ctrl_handler(function ($evt) {});
0 ignored issues
show
Unused Code introduced by
The parameter $evt is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

637
            sapi_windows_set_ctrl_handler(function (/** @scrutinizer ignore-unused */ $evt) {});

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
638
        }
639
    }
640
}
641