From f3999413f2289ce0a94e049b8527eb76f53a0dc7 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Mon, 21 Sep 2026 10:56:01 +0800 Subject: [PATCH] perf(build): skip opcode work for ordinary PHP sources --- phpunit/src/EmptyTranslationUnitTest.php | 8 ++++++-- src/Build/SourcePipelineTrait.php | 19 ++++++++++++------- src/Translator.php | 5 +++++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/phpunit/src/EmptyTranslationUnitTest.php b/phpunit/src/EmptyTranslationUnitTest.php index 3e44440d..59229e27 100644 --- a/phpunit/src/EmptyTranslationUnitTest.php +++ b/phpunit/src/EmptyTranslationUnitTest.php @@ -118,9 +118,13 @@ PHP); $this->compiler->prepareFile($source); $sources = $this->compiler->convert([$source]); - self::assertCount(2, $sources); + self::assertCount(1, $sources); self::assertContains($this->compiler->getBuildDir() . '/extension-app.cc', $sources); - self::assertContains($this->compiler->getBuildDir() . '/embedded-opcodes-app.cc', $sources); + self::assertNotContains($this->compiler->getBuildDir() . '/embedded-opcodes-app.cc', $sources); + self::assertStringContainsString( + 'void typephp_opcode_table_install(void) {}', + file_get_contents($this->compiler->getBuildDir() . '/extension-app.cc'), + ); foreach ($sources as $generatedSource) { self::assertFileExists($generatedSource); } diff --git a/src/Build/SourcePipelineTrait.php b/src/Build/SourcePipelineTrait.php index df98d87d..1c3dd79d 100644 --- a/src/Build/SourcePipelineTrait.php +++ b/src/Build/SourcePipelineTrait.php @@ -1013,12 +1013,16 @@ PHP && file_get_contents($anonymousManifest) === '[]') { unlink($anonymousManifest); } - $needsAnonymousRefresh = is_file($legacyAnonymousManifest) - || ($this->canEmbedAnonymousClassOpcode() - && !is_file($anonymousManifest) - && preg_match('/new\s+class\b/', (string) file_get_contents($path)) === 1); - if (!$this->shouldRegeneratePhpFile($path) && !$needsAnonymousRefresh) { - if ($this->canEmbedAnonymousClassOpcode()) { + $shouldRegenerate = $this->shouldRegeneratePhpFile($path); + $hasAnonymousManifest = is_file($anonymousManifest); + $needsAnonymousRefresh = !$shouldRegenerate + && (is_file($legacyAnonymousManifest) + || ($hasAnonymousManifest + ? !$this->canEmbedAnonymousClassOpcode() + : (preg_match('/new\s+class\b/', (string) file_get_contents($path)) === 1 + && $this->canEmbedAnonymousClassOpcode()))); + if (!$shouldRegenerate && !$needsAnonymousRefresh) { + if ($hasAnonymousManifest) { $this->restoreAnonymousManifest($path); } $validSourceCount++; @@ -1114,7 +1118,8 @@ PHP // Nano keeps the ordinary statically registered Zend class/module // metadata, then adds a direct native process entry beside it. $sourceFiles[] = $this->genExtension(); - if ($this->isBuildModeEmbed() && !$this->isNanoMode()) { + if ($this->isBuildModeEmbed() && !$this->isNanoMode() + && ($this->bundledFiles !== [] || $this->embeddedOpcodeFiles !== [])) { array_push($sourceFiles, ...$this->genEmbeddedOpcodeTable()); } if ($this->isNanoMode()) { diff --git a/src/Translator.php b/src/Translator.php index b2bbf813..af750a84 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -1234,6 +1234,11 @@ class Translator extends Preprocessor if ($this->isBuildModeEmbed() && !$this->isNanoMode()) { $code .= '#include ' . PHP_EOL; + if ($this->bundledFiles === [] && $this->embeddedOpcodeFiles === []) { + // The runtime still calls these hooks; keep empty builds in this translation unit. + $code .= 'extern "C" void typephp_opcode_table_install(void) {}' . PHP_EOL; + $code .= 'extern "C" void typephp_opcode_table_uninstall(void) {}' . PHP_EOL; + } } if ($this->isBuildModeLib() && !$this->isWindows()) {