From 79646304be76d925f51916ed42b0594a7a61e56f Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Mon, 20 Feb 2023 17:41:38 +0100 Subject: [PATCH] Load opcache extension if it is loadable --- src/Psalm/Internal/Fork/PsalmRestarter.php | 106 +++++++++++++++------ 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/src/Psalm/Internal/Fork/PsalmRestarter.php b/src/Psalm/Internal/Fork/PsalmRestarter.php index 36457a796..8d255f608 100644 --- a/src/Psalm/Internal/Fork/PsalmRestarter.php +++ b/src/Psalm/Internal/Fork/PsalmRestarter.php @@ -2,19 +2,28 @@ namespace Psalm\Internal\Fork; +use Composer\XdebugHandler\Process; use Composer\XdebugHandler\XdebugHandler; use function array_filter; use function array_merge; use function array_splice; +use function defined; use function extension_loaded; +use function fgets; use function file_get_contents; use function file_put_contents; +use function function_exists; use function implode; use function in_array; use function ini_get; +use function is_resource; use function preg_replace; +use function proc_close; +use function proc_open; +use function trim; +use const PHP_BINARY; use const PHP_VERSION_ID; /** @@ -23,6 +32,7 @@ use const PHP_VERSION_ID; class PsalmRestarter extends XdebugHandler { private bool $required = false; + private ?bool $needOPcache = null; /** * @var string[] @@ -40,6 +50,41 @@ class PsalmRestarter extends XdebugHandler $this->disabled_extensions = array_merge($this->disabled_extensions, $disable_extensions); } + /** + * Returns true if the opcache extension is not currently loaded and *can* be loaded. + */ + private function canAndNeedToLoadOpcache(): bool + { + if (function_exists('opcache_get_status')) { + return false; + } + if ($this->needOPcache !== null) { + return $this->needOPcache; + } + $cmd = [PHP_BINARY, '-n', '-dzend_extension=opcache', '-r', 'var_dump(function_exists("opcache_get_status"));']; + + if (PHP_VERSION_ID >= 70400) { + $cmd = $cmd; + } else { + $cmd = Process::escapeShellCommand($cmd); + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + // Outer quotes required on cmd string below PHP 8 + $cmd = '"'.$cmd.'"'; + } + } + + $process = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes); + $this->needOPcache = + isset($pipes[1]) + && trim(fgets($pipes[1]) ?: '') === 'bool(true)'; + + if (is_resource($process)) { + proc_close($process); + } + + return $this->needOPcache; + } + /** * No type hint to allow xdebug-handler v1 and v2 usage * @@ -53,23 +98,25 @@ class PsalmRestarter extends XdebugHandler static fn(string $extension): bool => extension_loaded($extension) ); - if (PHP_VERSION_ID >= 8_00_00 && (extension_loaded('opcache') || extension_loaded('Zend OPcache'))) { - // restart to enable JIT if it's not configured in the optimal way - if (!in_array(ini_get('opcache.enable_cli'), ['1', 'true', true, 1])) { - return true; - } + if ($this->canAndNeedToLoadOpcache()) { + return true; + } - if (((int) ini_get('opcache.jit')) !== 1205) { - return true; - } + // restart to enable JIT if it's not configured in the optimal way + if (!in_array(ini_get('opcache.enable_cli'), ['1', 'true', true, 1])) { + return true; + } - if (((int) ini_get('opcache.jit')) === 0) { - return true; - } + if (((int) ini_get('opcache.jit')) !== 1205) { + return true; + } - if (ini_get('opcache.optimization_level') !== '0x7FFEBFFF') { - return true; - } + if (((int) ini_get('opcache.jit')) === 0) { + return true; + } + + if (ini_get('opcache.optimization_level') !== '0x7FFEBFFF') { + return true; } return $default || $this->required; @@ -92,28 +139,27 @@ class PsalmRestarter extends XdebugHandler file_put_contents($this->tmpIni, $content); } - $additional_options = []; - - // executed in the parent process (before restart) - // if it wasn't loaded then we apparently don't have opcache installed and there's no point trying - // to tweak it - // If we're running on 7.4 there's no JIT available - if (PHP_VERSION_ID >= 8_00_00 && (extension_loaded('opcache') || extension_loaded('Zend OPcache'))) { - $additional_options = [ - '-dopcache.enable_cli=true', - '-dopcache.jit_buffer_size=512M', - '-dopcache.jit=1205', - '-dopcache.optimization_level=0x7FFEBFFF', - ]; - } - array_splice( $command, 1, 0, - $additional_options, + [ + '-dopcache.enable_cli=true', + '-dopcache.jit_buffer_size=512M', + '-dopcache.jit=1205', + '-dopcache.optimization_level=0x7FFEBFFF', + ], ); + if ($this->canAndNeedToLoadOpcache()) { + array_splice( + $command, + 1, + 0, + ['-dzend_extension=opcache'], + ); + } + parent::restart($command); } }