From 22c9f862a479aa316a03da813db4c0fbf59ce2db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Kvas=C5=88ovsk=C3=BD?= Date: Mon, 9 Feb 2026 01:39:02 +0100 Subject: [PATCH] fix: use serialize/unserialize for cache to prevent __set_state crashes The cache uses var_export() to persist PHPStan analysis results. When errors include PhpParser node objects, var_export() generates __set_state() calls. Since PhpParser\Node\Name (nikic/php-parser v5) does not implement __set_state(), loading the cache crashes with: Call to undefined method PhpParser\Node\Name::__set_state() In Pokio fork mode, this causes zend_mm_heap corrupted. Replace var_export($cache, true) with serialize()/unserialize() and bump cache version from v3 to v4 to invalidate corrupted caches. --- src/Support/Cache.php | 4 ++-- tests/Support/Cache.php | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/Support/Cache.php diff --git a/src/Support/Cache.php b/src/Support/Cache.php index ef51b17..1fa00b3 100644 --- a/src/Support/Cache.php +++ b/src/Support/Cache.php @@ -15,7 +15,7 @@ final class Cache /** * The cache version. */ - private const string CACHE_VERSION = 'v3'; + private const string CACHE_VERSION = 'v4'; /** * The cache instance. @@ -138,7 +138,7 @@ public function persist(string $file, array $values): void $cache[$fileHash] = $values; - $content = 'cache = Cache::instance(); + $this->cache->flush(); +}); + +afterEach(function () { + $this->cache->flush(); +}); + +test('it persists and retrieves cached results', function () { + $file = __DIR__.'/../Fixtures/All.php'; + $error = new Error('Test error', $file, 10); + + $this->cache->persist($file, [$file, [$error], []]); + + expect($this->cache->has($file))->toBeTrue() + ->and($this->cache->get($file))->toBeArray() + ->and($this->cache->get($file)[0])->toBe($file) + ->and($this->cache->get($file)[1])->toHaveCount(1) + ->and($this->cache->get($file)[1][0])->toBeInstanceOf(Error::class) + ->and($this->cache->get($file)[1][0]->getMessage())->toBe('Test error'); +}); + +test('it persists and retrieves errors containing PhpParser node metadata', function () { + $file = __DIR__.'/../Fixtures/All.php'; + $nodeName = new PhpParser\Node\Name('Tests\Fixtures\All'); + $error = new Error('Type mismatch', $file, 10, metadata: ['type' => $nodeName]); + + $this->cache->persist($file, [$file, [$error], []]); + + $cached = $this->cache->get($file); + + expect($cached[1])->toHaveCount(1) + ->and($cached[1][0])->toBeInstanceOf(Error::class) + ->and($cached[1][0]->getMessage())->toBe('Type mismatch'); +});