mirror of
https://github.com/twigphp/Twig.git
synced 2026-10-02 01:47:10 +00:00
Speed up loading compiled templates that OPcache already holds
This commit is contained in:
committed by
Fabien Potencier
parent
c471d2ad58
commit
ef3780c2e0
@@ -10,6 +10,7 @@
|
||||
* Fix the `deprecated` tag generating invalid PHP for an integer message
|
||||
* Add a third argument to `FilesystemLoader::addPath()` and `FilesystemLoader::prependPath()` to skip checking that the directory exists
|
||||
* Speed up traversing nodes with node visitors
|
||||
* Speed up loading compiled templates that OPcache already holds
|
||||
|
||||
# 3.30.0 (2026-09-25)
|
||||
|
||||
|
||||
@@ -22,11 +22,18 @@ class FilesystemCache implements CacheInterface, RemovableCacheInterface
|
||||
|
||||
private $directory;
|
||||
private $options;
|
||||
private bool $checkOpcache;
|
||||
|
||||
public function __construct(string $directory, int $options = 0)
|
||||
{
|
||||
$this->directory = rtrim($directory, '\/').'/';
|
||||
$this->options = $options;
|
||||
// OPcache can still hold a compiled file removed from disk, which FORCE_BYTECODE_INVALIDATION wants compiled again.
|
||||
// Its API also warns on each call when restricted, and it checks the file anyway when it validates timestamps on each call.
|
||||
$this->checkOpcache = !($options & self::FORCE_BYTECODE_INVALIDATION)
|
||||
&& \function_exists('opcache_is_script_cached')
|
||||
&& !\ini_get('opcache.restrict_api')
|
||||
&& (!filter_var(\ini_get('opcache.validate_timestamps'), \FILTER_VALIDATE_BOOLEAN) || \ini_get('opcache.revalidate_freq'));
|
||||
}
|
||||
|
||||
public function generateKey(string $name, string $className): string
|
||||
@@ -38,7 +45,7 @@ class FilesystemCache implements CacheInterface, RemovableCacheInterface
|
||||
|
||||
public function load(string $key): void
|
||||
{
|
||||
if (is_file($key)) {
|
||||
if (($this->checkOpcache && opcache_is_script_cached($key)) || is_file($key)) {
|
||||
@include_once $key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,21 @@ class FilesystemTest extends TestCase
|
||||
$this->assertFalse(class_exists($this->className, false));
|
||||
}
|
||||
|
||||
public function testLoadSkipsTheFileCheckWhenOpcacheHasTheFile(): void
|
||||
{
|
||||
$this->assertSame('loaded', $this->loadInOpcacheProcess(0, true));
|
||||
}
|
||||
|
||||
public function testLoadChecksTheFileWhenBytecodeInvalidationIsForced(): void
|
||||
{
|
||||
$this->assertSame('', $this->loadInOpcacheProcess(FilesystemCache::FORCE_BYTECODE_INVALIDATION, true));
|
||||
}
|
||||
|
||||
public function testLoadDoesNotWarnWhenTheOpcacheApiIsRestricted(): void
|
||||
{
|
||||
$this->assertSame('loaded', $this->loadInOpcacheProcess(0, false, '/nonexistent'));
|
||||
}
|
||||
|
||||
public function testWrite(): void
|
||||
{
|
||||
$key = $this->directory.'/cache/cachefile.php';
|
||||
@@ -202,4 +217,44 @@ class FilesystemTest extends TestCase
|
||||
'{{class_name}}' => $this->className,
|
||||
]);
|
||||
}
|
||||
|
||||
private function loadInOpcacheProcess(int $options, bool $removeCachedFile, string $restrictApi = ''): string
|
||||
{
|
||||
if (!\function_exists('opcache_compile_file')) {
|
||||
$this->markTestSkipped('OPcache is not loaded.');
|
||||
}
|
||||
|
||||
$code = <<<'PHP'
|
||||
require $argv[1];
|
||||
$cache = new Twig\Cache\FilesystemCache($argv[2], (int) $argv[3]);
|
||||
$key = $cache->generateKey('index', 'Foo');
|
||||
$cache->write($key, '<?php echo "loaded";');
|
||||
if ($argv[4]) {
|
||||
opcache_compile_file($key);
|
||||
unlink($key);
|
||||
}
|
||||
$cache->load($key);
|
||||
PHP;
|
||||
|
||||
$process = proc_open([
|
||||
\PHP_BINARY,
|
||||
'-d', 'opcache.enable=1',
|
||||
'-d', 'opcache.enable_cli=1',
|
||||
'-d', 'opcache.file_update_protection=0',
|
||||
'-d', 'opcache.validate_timestamps=0',
|
||||
'-d', 'opcache.restrict_api='.$restrictApi,
|
||||
'-d', 'display_errors=1',
|
||||
'-d', 'error_reporting=-1',
|
||||
'-r', $code,
|
||||
\dirname(__DIR__, 2).'/vendor/autoload.php',
|
||||
$this->directory,
|
||||
(string) $options,
|
||||
$removeCachedFile ? '1' : '0',
|
||||
], [1 => ['pipe', 'w'], 2 => ['redirect', 1]], $pipes);
|
||||
|
||||
$output = stream_get_contents($pipes[1]);
|
||||
proc_close($process);
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user