Skip to content

Commit 157e4f2

Browse files
committed
Fix isXdebugActive if used before instantiation
1 parent ec6aa89 commit 157e4f2

File tree

4 files changed

+46
-42
lines changed

4 files changed

+46
-42
lines changed

src/XdebugHandler.php

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ class XdebugHandler
4444
/** @var bool */
4545
private static $xdebugActive;
4646

47+
/** @var string|null */
48+
private static $xdebugMode;
49+
50+
/** @var string|null */
51+
private static $xdebugVersion;
52+
4753
/** @var bool */
4854
private $cli;
4955

@@ -56,12 +62,6 @@ class XdebugHandler
5662
/** @var string */
5763
private $envOriginalInis;
5864

59-
/** @var string|null */
60-
private $loaded;
61-
62-
/** @var string|null */
63-
private $mode;
64-
6565
/** @var bool */
6666
private $persistent;
6767

@@ -91,13 +91,7 @@ public function __construct(string $envPrefix)
9191
$this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
9292
$this->envOriginalInis = self::$name.self::SUFFIX_INIS;
9393

94-
if (extension_loaded('xdebug')) {
95-
$version = phpversion('xdebug');
96-
$this->loaded = $version !== false ? $version : 'unknown';
97-
$this->mode = $this->getXdebugMode($this->loaded);
98-
}
99-
100-
self::$xdebugActive = $this->loaded !== null && $this->mode !== 'off';
94+
self::setXdebugDetails();
10195
self::$inRestart = false;
10296

10397
if ($this->cli = PHP_SAPI === 'cli') {
@@ -143,7 +137,7 @@ public function setPersistent(): self
143137
*/
144138
public function check(): void
145139
{
146-
$this->notify(Status::CHECK, $this->loaded.'|'.$this->mode);
140+
$this->notify(Status::CHECK, self::$xdebugVersion.'|'.self::$xdebugMode);
147141
$envArgs = explode('|', (string) getenv($this->envAllowXdebug));
148142

149143
if (!((bool) $envArgs[0]) && $this->requiresRestart(self::$xdebugActive)) {
@@ -164,7 +158,7 @@ public function check(): void
164158
Process::setEnv($this->envAllowXdebug);
165159
self::$inRestart = true;
166160

167-
if ($this->loaded === null) {
161+
if (self::$xdebugVersion === null) {
168162
// Skipped version is only set if Xdebug is not loaded
169163
self::$skipped = $envArgs[1];
170164
}
@@ -256,6 +250,7 @@ public static function getSkippedVersion(): string
256250
*/
257251
public static function isXdebugActive(): bool
258252
{
253+
self::setXdebugDetails();
259254
return self::$xdebugActive;
260255
}
261256

@@ -453,7 +448,7 @@ private function setEnvironment(bool $scannedInis, array $iniFiles): bool
453448
// Flag restarted process and save values for it to use
454449
$envArgs = [
455450
self::RESTART_ID,
456-
$this->loaded,
451+
self::$xdebugVersion,
457452
(int) $scannedInis,
458453
false === $scanDir ? '*' : $scanDir,
459454
false === $phprc ? '*' : $phprc,
@@ -625,34 +620,48 @@ private function tryEnableSignals(): void
625620
}
626621

627622
/**
628-
* Returns the Xdebug mode if available
623+
* Sets static properties $xdebugActive, $xdebugVersion and $xdebugMode
629624
*/
630-
private function getXdebugMode(string $version): ?string
625+
private static function setXdebugDetails(): void
631626
{
632-
if (version_compare($version, '3.1', '>=')) {
627+
if (self::$xdebugActive !== null) {
628+
return;
629+
}
630+
631+
self::$xdebugActive = false;
632+
if (!extension_loaded('xdebug')) {
633+
return;
634+
}
635+
636+
$version = phpversion('xdebug');
637+
self::$xdebugVersion = $version !== false ? $version : 'unknown';
638+
639+
if (version_compare(self::$xdebugVersion, '3.1', '>=')) {
633640
$modes = xdebug_info('mode');
634-
return count($modes) === 0 ? 'off' : implode(',', $modes);
641+
self::$xdebugMode = count($modes) === 0 ? 'off' : implode(',', $modes);
642+
self::$xdebugActive = self::$xdebugMode !== 'off';
643+
return;
635644
}
636645

637646
// See if xdebug.mode is supported in this version
638647
$iniMode = ini_get('xdebug.mode');
639648
if ($iniMode === false) {
640-
return null;
649+
return;
641650
}
642651

643652
// Environment value wins but cannot be empty
644653
$envMode = (string) getenv('XDEBUG_MODE');
645654
if ($envMode !== '') {
646-
$mode = $envMode;
655+
self::$xdebugMode = $envMode;
647656
} else {
648-
$mode = $iniMode !== '' ? $iniMode : 'off';
657+
self::$xdebugMode = $iniMode !== '' ? $iniMode : 'off';
649658
}
650659

651660
// An empty comma-separated list is treated as mode 'off'
652-
if (Preg::isMatch('/^,+$/', str_replace(' ', '', $mode))) {
653-
$mode = 'off';
661+
if (Preg::isMatch('/^,+$/', str_replace(' ', '', self::$xdebugMode))) {
662+
self::$xdebugMode = 'off';
654663
}
655664

656-
return $mode;
665+
self::$xdebugActive = self::$xdebugMode !== 'off';
657666
}
658667
}

tests/Helpers/BaseTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ protected function checkRestart(CoreMock $xdebug)
132132
self::assertArrayHasKey(CoreMock::ORIGINAL_INIS, $_SERVER);
133133

134134
// Skipped version must only be reported if it was unloaded in the restart
135-
if (!$xdebug->parentLoaded) {
135+
if ($xdebug->parentXdebugVersion === null) {
136136
// Mocked successful restart without Xdebug
137137
$version = '';
138138
} elseif ($xdebug instanceof FailMock) {

tests/Mocks/CoreMock.php

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class CoreMock extends XdebugHandler
3737
/** @var bool */
3838
public $restarted;
3939

40-
/** @var bool */
41-
public $parentLoaded;
40+
/** @var string|null */
41+
public $parentXdebugVersion;
4242

4343
/** @var null|static */
4444
protected $childProcess;
@@ -81,7 +81,7 @@ public static function createAndCheck($loaded, ?self $parentProcess = null, arra
8181
// properties on the parent and child
8282
$parentProcess->restarted = true;
8383
$xdebug->restarted = true;
84-
$xdebug->parentLoaded = $parentProcess->parentLoaded;
84+
$xdebug->parentXdebugVersion = $parentProcess->parentXdebugVersion;
8585

8686
// Make the child available
8787
$parentProcess->childProcess = $xdebug;
@@ -105,15 +105,15 @@ final public function __construct(bool $loaded, ?string $mode)
105105
parent::__construct('mock');
106106

107107
$this->refClass = new \ReflectionClass('Composer\XdebugHandler\XdebugHandler');
108-
$this->parentLoaded = $loaded ? static::TEST_VERSION : null;
108+
$this->parentXdebugVersion = $loaded ? static::TEST_VERSION : null;
109109

110-
// Set private loaded
111-
$prop = $this->refClass->getProperty('loaded');
110+
// Set private static xdebugVersion
111+
$prop = $this->refClass->getProperty('xdebugVersion');
112112
$prop->setAccessible(true);
113-
$prop->setValue($this, $this->parentLoaded);
113+
$prop->setValue($this, $this->parentXdebugVersion);
114114

115-
// Set private mode
116-
$prop = $this->refClass->getProperty('mode');
115+
// Set private static xdebugMode
116+
$prop = $this->refClass->getProperty('xdebugMode');
117117
$prop->setAccessible(true);
118118
$prop->setValue($this, $mode);
119119

@@ -127,11 +127,6 @@ final public function __construct(bool $loaded, ?string $mode)
127127
$prop->setAccessible(true);
128128
$prop->setValue($this, null);
129129

130-
// Ensure static private inRestart is unset
131-
$prop = $this->refClass->getProperty('inRestart');
132-
$prop->setAccessible(true);
133-
$prop->setValue($this, null);
134-
135130
$this->restarted = false;
136131
}
137132

tests/SettingsTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function testSyncSettings(): void
7676
putenv(CoreMock::ORIGINAL_INIS);
7777
unset($_SERVER[CoreMock::ORIGINAL_INIS]);
7878

79-
// Mock not loaded ($inRestart and $skipped statics are unset)
79+
// Mock not loaded (static $skipped is unset in mock constructor)
8080
$loaded = false;
8181
CoreMock::createAndCheck($loaded);
8282

0 commit comments

Comments
 (0)