feat(translator): 增强PHP到C++编译器功能

- 在ClassLikeDef中添加getNamespacedName方法的symbolic参数支持
- 简化compiler.php中的文件扫描逻辑并移除冗余代码
- 在CompilerBase中添加函数定义存储数组和相关属性
- 更新错误处理方法结构并分离基本错误和致命错误处理
- 在extension.cc模板中移除类信息函数声明并添加函数入口表
- 修改属性偏移获取逻辑以支持非符号化命名空间
- 添加嵌入式模块获取函数实现
- 重构gen_stub.php中的类和函数信息生成逻辑
- 移除全局变量genClass并更新命令行选项处理
- 重命名examples/class/test.php为examples/appx/test.php并添加测试常量和函数
- 在Translator中添加PHP源文件和arginfo头文件数组管理
- 更新目标名称验证以检查C++保留关键字
- 实现getFiles方法统一文件路径处理逻辑
- 添加函数包装器生成功能和类注册函数提取
- 优化类CE列表生成逻辑并修复头文件包含顺序问题
- 重构存根文件生成流程并改进错误报告机制
pull/1/head
韩天峰 7 months ago
parent ea77b6d746
commit a6a06ca859
  1. 19
      bin/compiler.php
  2. 25
      bin/gen_stub.php
  3. 0
      examples/appx/MyClass.php
  4. 0
      examples/appx/main.php
  5. 7
      examples/appx/test.php
  6. 5
      src/Php/ClassLikeDef.php
  7. 22
      src/Php/CompilerBase.php
  8. 95
      src/Php/Translator.php
  9. 11
      src/cpp/main.cc
  10. 27
      src/template/extension.cc.php

@ -14,22 +14,7 @@ if (empty($argv[1])) {
$path = $argv[1]; $path = $argv[1];
$translator = new Translator(ROOT_PATH); $translator = new Translator(ROOT_PATH);
$translator->setIndent(' '); $translator->setIndent(' ');
$list = $translator->getFiles($path);
$realpath = realpath($path);
if ($realpath === false) {
die("path not exists: $path\n");
}
$path = $realpath;
if (is_dir($path)) {
$scanner = new FileScanner($path);
$list = $scanner->scan();
$targetName = basename($path);
} else {
$list = [$path];
$targetName = FileScanner::getFileName($path);
}
$translator->setTargetName($targetName);
$sourceFiles = []; $sourceFiles = [];
$objectFiles = []; $objectFiles = [];
@ -79,7 +64,7 @@ $translator->genExternGlobalVars($translator->getIncludeDir() . '/php_global_var
// 生成所有全局变量源文件 // 生成所有全局变量源文件
$extensionSourceFile = $translator->getBuildDir() . '/extension.cc'; $extensionSourceFile = $translator->getBuildDir() . '/extension.cc';
$translator->genExtension($extensionSourceFile, $targetName); $translator->genExtension($extensionSourceFile);
$sourceFiles[] = $extensionSourceFile; $sourceFiles[] = $extensionSourceFile;
// 添加 main.cc 文件 // 添加 main.cc 文件

@ -1,6 +1,7 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php declare(strict_types=1); <?php declare(strict_types=1);
use PhpAot\Php\Translator;
use PhpParser\Comment\Doc as DocComment; use PhpParser\Comment\Doc as DocComment;
use PhpParser\ConstExprEvaluator; use PhpParser\ConstExprEvaluator;
use PhpParser\Modifiers; use PhpParser\Modifiers;
@ -3504,7 +3505,7 @@ class ClassInfo {
$code .= "#if {$this->cond}\n"; $code .= "#if {$this->cond}\n";
} }
$code .= "static zend_class_entry *register_class_$escapedName(" . (empty($params) ? "void" : implode(", ", $params)) . ")\n"; $code .= "static zend_class_entry *" . Translator::PREFIX . "register_class_$escapedName(" . (empty($params) ? "void" : implode(", ", $params)) . ")\n";
$code .= "{\n"; $code .= "{\n";
@ -4231,15 +4232,11 @@ class FileInfo {
*/ */
public function getAllFuncInfos(): iterable public function getAllFuncInfos(): iterable
{ {
global $genClass;
if ($genClass) {
foreach ($this->classInfos as $classInfo) { foreach ($this->classInfos as $classInfo) {
yield from $classInfo->funcInfos; yield from $classInfo->funcInfos;
} }
} else {
yield from $this->funcInfos; yield from $this->funcInfos;
} }
}
/** @return array<string, ConstInfo> */ /** @return array<string, ConstInfo> */
public function getAllConstInfos(): array { public function getAllConstInfos(): array {
@ -5168,8 +5165,6 @@ function generateArgInfoCode(
$generatedFuncInfos = []; $generatedFuncInfos = [];
global $genClass;
$argInfoCode = generateCodeWithConditions( $argInfoCode = generateCodeWithConditions(
$fileInfo->getAllFuncInfos(), "\n", $fileInfo->getAllFuncInfos(), "\n",
static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) { static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) {
@ -5220,16 +5215,14 @@ function generateArgInfoCode(
$code .= generateFunctionEntries(null, $fileInfo->funcInfos); $code .= generateFunctionEntries(null, $fileInfo->funcInfos);
if ($genClass) {
foreach ($fileInfo->classInfos as $classInfo) { foreach ($fileInfo->classInfos as $classInfo) {
$code .= generateFunctionEntries($classInfo->name, $classInfo->funcInfos, $classInfo->cond); $code .= generateFunctionEntries($classInfo->name, $classInfo->funcInfos, $classInfo->cond);
} }
} }
}
$php80MinimumCompatibility = $fileInfo->getMinimumPhpVersionIdCompatibility() === null || $fileInfo->getMinimumPhpVersionIdCompatibility() >= PHP_80_VERSION_ID; $php80MinimumCompatibility = $fileInfo->getMinimumPhpVersionIdCompatibility() === null || $fileInfo->getMinimumPhpVersionIdCompatibility() >= PHP_80_VERSION_ID;
if ($genClass and $fileInfo->generateClassEntries) { if ($fileInfo->generateClassEntries) {
$declaredStrings = []; $declaredStrings = [];
$attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings); $attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings);
$attributeInitializationCode .= generateGlobalConstantAttributeInitialization($fileInfo->constInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings); $attributeInitializationCode .= generateGlobalConstantAttributeInitialization($fileInfo->constInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings);
@ -6100,7 +6093,7 @@ function initPhpParser() {
function main() function main()
{ {
global $argv, $argc, $genClass, $translator; global $argv, $argc, $translator;
error_reporting(E_ALL); error_reporting(E_ALL);
ini_set("precision", "-1"); ini_set("precision", "-1");
@ -6116,7 +6109,7 @@ function main()
[ [
"force-regeneration", "parameter-stats", "help", "verify", "verify-manual", "replace-predefined-constants", "force-regeneration", "parameter-stats", "help", "verify", "verify-manual", "replace-predefined-constants",
"generate-classsynopses", "replace-classsynopses", "generate-methodsynopses", "replace-methodsynopses", "generate-classsynopses", "replace-classsynopses", "generate-methodsynopses", "replace-methodsynopses",
"generate-optimizer-info", "gen-class-info", "gen-func-info", "generate-optimizer-info",
], ],
$opt_index $opt_index
); );
@ -6132,14 +6125,6 @@ function main()
$replaceMethodSynopses = isset($options["replace-methodsynopses"]); $replaceMethodSynopses = isset($options["replace-methodsynopses"]);
$generateOptimizerInfo = isset($options["generate-optimizer-info"]); $generateOptimizerInfo = isset($options["generate-optimizer-info"]);
if (isset($options["gen-class-info"])) {
$genClass = true;
} elseif (isset($options["gen-func-info"])) {
$genClass = false;
} else {
die("Please specify whether to generate class or function info\n");
}
$context->forceRegeneration = isset($options["f"]) || isset($options["force-regeneration"]); $context->forceRegeneration = isset($options["f"]) || isset($options["force-regeneration"]);
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify || $verifyManual || $replacePredefinedConstants || $generateClassSynopses || $generateOptimizerInfo || $replaceClassSynopses || $generateMethodSynopses || $replaceMethodSynopses; $context->forceParse = $context->forceRegeneration || $printParameterStats || $verify || $verifyManual || $replacePredefinedConstants || $generateClassSynopses || $generateOptimizerInfo || $replaceClassSynopses || $generateMethodSynopses || $replaceMethodSynopses;

@ -37,3 +37,10 @@ class Test
} }
} }
const TEST_CONST = 1.001;
function my_sum(int $a, int $b)
{
return $a + $b;
}

@ -15,11 +15,14 @@ class ClassLikeDef
$this->namespace = $namespace; $this->namespace = $namespace;
} }
public function getNamespacedName(): string public function getNamespacedName(bool $symbolic = true): string
{ {
if ($this->namespace === '') { if ($this->namespace === '') {
return $this->name; return $this->name;
} }
if ($symbolic) {
return str_replace('\\', '_', $this->namespace . '_' . $this->name); return str_replace('\\', '_', $this->namespace . '_' . $this->name);
} }
return $this->namespace . '\\\\' . $this->name;
}
} }

@ -104,6 +104,10 @@ class CompilerBase extends \PhpAot\Core\Translator
*/ */
protected array $classes = []; protected array $classes = [];
protected array $interfaces = []; protected array $interfaces = [];
/**
* @var array<string, FunctionDef>
*/
protected array $functions = [];
/** /**
* @var array<string, ClassDef> * @var array<string, ClassDef>
*/ */
@ -112,6 +116,10 @@ class CompilerBase extends \PhpAot\Core\Translator
* @var array<string, InterfaceDef> * @var array<string, InterfaceDef>
*/ */
protected array $interfacesDefineInFile = []; protected array $interfacesDefineInFile = [];
/**
* @var array<string, FunctionDef>
*/
protected array $functionDefineInFile = [];
/** /**
* @var array<string> * @var array<string>
*/ */
@ -151,7 +159,6 @@ class CompilerBase extends \PhpAot\Core\Translator
protected bool $inLoop = false; protected bool $inLoop = false;
protected bool $inAssignExpr = false; protected bool $inAssignExpr = false;
protected bool $stubFile = false; protected bool $stubFile = false;
protected bool $stubFileIncluded = false;
protected bool $enableProfiler = false; protected bool $enableProfiler = false;
protected Parser $parser; protected Parser $parser;
@ -238,6 +245,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->strictTypes = false; $this->strictTypes = false;
$this->classesDefineInFile = []; $this->classesDefineInFile = [];
$this->interfacesDefineInFile = []; $this->interfacesDefineInFile = [];
$this->functionDefineInFile = [];
} }
protected function resetNamespace(): void protected function resetNamespace(): void
@ -301,6 +309,9 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->class) { if ($this->class) {
$this->arguments['this_'] = self::TYPE_OBJECT; $this->arguments['this_'] = self::TYPE_OBJECT;
$this->addLocalVar('this_', self::TYPE_OBJECT); $this->addLocalVar('this_', self::TYPE_OBJECT);
} else {
$this->functions[$name] = $this->functionDef;
$this->functionDefineInFile[$name] = $this->functionDef;
} }
foreach ($this->functionDef->argInfoList as $argInfo) { foreach ($this->functionDef->argInfoList as $argInfo) {
@ -1372,13 +1383,18 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->parseAssignOp($expr, '**='); return $this->parseAssignOp($expr, '**=');
} }
protected function fatalError(Node $node, string $msg): void protected function error(string $msg): void
{ {
$this->climate->red("Fatal error: $msg in {$this->file}:" . $node->getStartLine()); $this->climate->red("Fatal error: $msg");
debug_print_backtrace(); debug_print_backtrace();
exit(255); exit(255);
} }
protected function fatalError(Node $node, string $msg): void
{
$this->error("$msg in {$this->file}:{$node->getStartLine()}");
}
protected function dump(NodeAbstract $v): void protected function dump(NodeAbstract $v): void
{ {
if ($this->debugLine == $v->getStartLine()) { if ($this->debugLine == $v->getStartLine()) {

@ -15,6 +15,9 @@ class Translator extends Preprocessor
protected string $targetName = 'app'; protected string $targetName = 'app';
protected bool $verbose = false; protected bool $verbose = false;
protected array $phpSrcFiles = [];
protected array $argInfoHeaderFiles = [];
protected array $unsupportedFunctions = [ protected array $unsupportedFunctions = [
'compact', 'compact',
'extract', 'extract',
@ -129,13 +132,14 @@ class Translator extends Preprocessor
return $this->getCppFile($file); return $this->getCppFile($file);
} }
$phpCode = $this->loadFile($file); $phpCode = $this->loadFile($file);
$this->stubFileIncluded = false; $this->genStubFile($this->file);
$this->localHeaders = []; $this->localHeaders = [];
while (true) { while (true) {
try { try {
$cppCode = $this->doConvert($phpCode); $cppCode = $this->doConvert($phpCode);
$cppFile = $this->getCppFile($file); $cppFile = $this->getCppFile($file);
$this->save($cppCode, $cppFile); $this->save($cppCode, $cppFile);
$this->phpSrcFiles[] = $file;
return $cppFile; return $cppFile;
} catch (RedoException $e) { } catch (RedoException $e) {
continue; continue;
@ -191,9 +195,33 @@ class Translator extends Preprocessor
$this->climate->red('The target name must be a valid identifier'); $this->climate->red('The target name must be a valid identifier');
exit(1); exit(1);
} }
if (in_array($name, Constants::CPP_RESERVED_NAMES)) {
$this->climate->red('The target name must not be a reserved keyword');
exit(1);
}
$this->targetName = $name; $this->targetName = $name;
} }
public function getFiles(string $path): array
{
$realpath = realpath($path);
if ($realpath === false) {
die("path not exists: $path\n");
}
$path = $realpath;
if (is_dir($path)) {
$scanner = new FileScanner($path);
$list = $scanner->scan();
$targetName = basename($path);
} else {
$list = [$path];
$targetName = FileScanner::getFileName($path);
}
$this->setTargetName($targetName);
return $list;
}
protected function getInternalCeInfo(string $ce): array protected function getInternalCeInfo(string $ce): array
{ {
return [ return [
@ -273,6 +301,10 @@ class Translator extends Preprocessor
$cppCode .= $this->genClassWrapper($interfaceDef); $cppCode .= $this->genClassWrapper($interfaceDef);
} }
foreach ($this->functionDefineInFile as $functionDef) {
$cppCode .= $this->genFunctionWrapper($functionDef);
}
return $this->genIncludeHeaderFiles() . $cppCode; return $this->genIncludeHeaderFiles() . $cppCode;
} }
@ -330,13 +362,13 @@ class Translator extends Preprocessor
protected function genClassCeList(): void protected function genClassCeList(): void
{ {
if (empty($this->interfacesDefineInFile) and empty($this->classesDefineInFile)) { if (empty($this->interfaces) and empty($this->classes)) {
return; return;
} }
$sorter = new StringSort(); $sorter = new StringSort();
foreach ($this->interfacesDefineInFile as $interfaceDef) { foreach ($this->interfaces as $interfaceDef) {
$parent = $interfaceDef->extends; $parent = $interfaceDef->extends;
$ce = $this->getClassCe($interfaceDef); $ce = $this->getClassCe($interfaceDef);
$deps = []; $deps = [];
@ -359,7 +391,7 @@ class Translator extends Preprocessor
$sorter->add($ce, $deps); $sorter->add($ce, $deps);
} }
foreach ($this->classesDefineInFile as $classDef) { foreach ($this->classes as $classDef) {
$ce = $this->getClassCe($classDef); $ce = $this->getClassCe($classDef);
$deps = []; $deps = [];
$parent = $classDef->extends; $parent = $classDef->extends;
@ -403,11 +435,12 @@ class Translator extends Preprocessor
exit(1); exit(1);
} }
} }
$this->localHeaders = []; $this->localHeaders = $this->argInfoHeaderFiles;
$this->genClassCeList(); $this->genClassCeList();
$code = $this->render('extension.cc.php'); $code = $this->render('extension.cc.php');
$this->writeFile($file, $code); $this->writeFile($file, $code);
$this->formatCppCode($file); $this->formatCppCode($file);
$this->localHeaders = [];
} }
public function hasObjectFileCache(string $cppFile): bool public function hasObjectFileCache(string $cppFile): bool
@ -537,28 +570,23 @@ class Translator extends Preprocessor
return $code; return $code;
} }
protected function genClassStubFile(Node\Stmt\Class_|Node\Stmt\Trait_ $class, string $file): void protected function genStubFile(string $file): void
{ {
$genStubCmd = PHP_BINARY. ' ' . $this->rootPath . '/bin/gen_stub.php --gen-class-info -f ' . $file; $genStubCmd = PHP_BINARY. ' ' . $this->rootPath . '/bin/gen_stub.php -f ' . $file;
$output = shell_exec($genStubCmd); $output = shell_exec($genStubCmd);
$this->climate->info('generate stub file: ' . $file); $this->climate->info('generate stub file: ' . $file);
$this->climate->comment($genStubCmd); $this->climate->comment($genStubCmd);
$stubFilenameWithoutExtension = str_replace([".stub.php", '.php'], "", $file); $stubFilenameWithoutExtension = str_replace([".stub.php", '.php'], "", $file);
$headerFile = $this->getArgInfoHeaderFile($stubFilenameWithoutExtension, true); $headerFile = $this->getArgInfoHeaderFile($stubFilenameWithoutExtension, true);
if (!str_starts_with($output, "Saved")) { if (!str_starts_with($output, "Saved")) {
$this->fatalError($class, "failed to generate arginfo header file: `$headerFile`, output: $output"); $this->error("failed to generate arginfo header file: `$headerFile`, output: $output");
} }
$this->localHeaders[] = $headerFile; $this->argInfoHeaderFiles[] = $headerFile;
$this->stubFileIncluded = true;
} }
protected function parseClass(Node\Stmt\Class_|Node\Stmt\Trait_ $class): string protected function parseClass(Node\Stmt\Class_|Node\Stmt\Trait_ $class): string
{ {
$this->class = $this->parseIdentifier($class->name); $this->class = $this->parseIdentifier($class->name);
if (!$this->stubFileIncluded) {
$this->genClassStubFile($class, $this->file);
}
$this->classDef = new ClassDef($this->class, $class->flags, $this->namespace); $this->classDef = new ClassDef($this->class, $class->flags, $this->namespace);
if ($class->extends) { if ($class->extends) {
$this->classDef->extends = $this->parseIdentifier($class->extends); $this->classDef->extends = $this->parseIdentifier($class->extends);
@ -607,7 +635,7 @@ class Translator extends Preprocessor
public function getArgInfoHeaderFile(string $stubFilenameWithoutExtension, bool $relative = false): string public function getArgInfoHeaderFile(string $stubFilenameWithoutExtension, bool $relative = false): string
{ {
$basename = basename($stubFilenameWithoutExtension); $basename = self::PREFIX . basename($stubFilenameWithoutExtension);
$absPath = $this->getIncludeDir() . "/{$basename}_arginfo.h"; $absPath = $this->getIncludeDir() . "/{$basename}_arginfo.h";
if ($relative) { if ($relative) {
return ltrim($this->removeCommonPrefix($this->getIncludeDir(), $absPath), '/'); return ltrim($this->removeCommonPrefix($this->getIncludeDir(), $absPath), '/');
@ -659,8 +687,37 @@ class Translator extends Preprocessor
return $cppCode; return $cppCode;
} }
private function genFunctionWrapper(FunctionDef $functionDef)
{
$name = $functionDef->name;
$cppCode = 'ZEND_FUNCTION(' . $name . '){' . PHP_EOL;
$fn = self::PREFIX . $this->getNativeName($functionDef->name);
protected function genClassWrapper(ClassDef|InterfaceDef $classDef): string $callParams = '';
foreach ($functionDef->argInfoList as $k => $argInfo) {
if ($argInfo->default) {
$argExpr = 'php::getCallArg(' . $k . ', ' . $argInfo->default . ')';
} else {
$argExpr = 'php::getCallArg(' . $k . ')';
}
$expr = $this->convertExprFromType($argInfo->type, $argExpr);
$cppCode .= $this->getIndent() . $argInfo->type . ' arg_' . $argInfo->name . ' = ' . $expr . ';' . PHP_EOL;
$callParams .= 'arg_' . $argInfo->name . ',';
}
$callParams = $functionDef->argInfoList ? rtrim($callParams, ',') : '';
if ($functionDef->returnType !== self::TYPE_VOID) {
$cppCode .= $this->getIndent() . 'auto retval = ' . $fn . '(' . $callParams . ');' . PHP_EOL;
$cppCode .= $this->getIndent() . 'php::move(retval, return_value);' . PHP_EOL;
} else {
$cppCode .= $this->getIndent() . $fn . '(' . $callParams . ');' . PHP_EOL;
}
$cppCode .= '}' . PHP_EOL . PHP_EOL;
return $cppCode;
}
protected function getClassRegisterCeFunc(ClassDef|InterfaceDef $classDef): void
{ {
$cppCode = ''; $cppCode = '';
$name = $classDef->getNamespacedName(); $name = $classDef->getNamespacedName();
@ -669,6 +726,12 @@ class Translator extends Preprocessor
$cppCode .= 'zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $argsDef . ') {' . PHP_EOL; $cppCode .= 'zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $argsDef . ') {' . PHP_EOL;
$cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL; $cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL;
$cppCode .= '}' . PHP_EOL . PHP_EOL; $cppCode .= '}' . PHP_EOL . PHP_EOL;
}
protected function genClassWrapper(ClassDef|InterfaceDef $classDef): string
{
$cppCode = '';
// 接口没有方法实体 // 接口没有方法实体
if ($classDef instanceof ClassDef) { if ($classDef instanceof ClassDef) {

@ -9,7 +9,7 @@ extern php::Var argv;
extern void php_app_init(); extern void php_app_init();
extern void php_app_clean(); extern void php_app_clean();
extern zend_module_entry app_module_entry; extern zend_module_entry *php_embed_get_module();
static void throw_exception(zend_object *ex) { static void throw_exception(zend_object *ex) {
zend_bailout(); zend_bailout();
@ -18,13 +18,14 @@ static void throw_exception(zend_object *ex) {
int main(int cpp_argc, char **cpp_argv) { int main(int cpp_argc, char **cpp_argv) {
php_embed_init(cpp_argc, cpp_argv); php_embed_init(cpp_argc, cpp_argv);
zend_throw_exception_hook = throw_exception; zend_throw_exception_hook = throw_exception;
zend_module_entry *module = php_embed_get_module();
if (zend_register_module_ex(&app_module_entry, MODULE_TEMPORARY) == NULL) { if (zend_register_module_ex(module, MODULE_TEMPORARY) == NULL) {
zend_error(E_ERROR, "Failed to register module"); zend_error(E_ERROR, "Failed to register module [%s]", module->name);
} }
if (zend_startup_module_ex(&app_module_entry) == FAILURE) { if (zend_startup_module_ex(module) == FAILURE) {
zend_error(E_ERROR, "Failed to startup module"); zend_error(E_ERROR, "Failed to startup module [%s]", module->name);
} }
int rc = 0; int rc = 0;

@ -19,12 +19,6 @@ foreach ($this->globalVars as $name => $type):
foreach ($this->classCeList as $ce): foreach ($this->classCeList as $ce):
?> ?>
zend_class_entry * <?= $ce ?>; zend_class_entry * <?= $ce ?>;
<?php
if (isset($this->classCeInfo[$ce])):
$info = $this->classCeInfo[$ce];
?>
extern zend_class_entry *<?= $info['func'] ?>(<?= $info['argDef'] ?>);
<?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
// literal strings // literal strings
@ -54,17 +48,16 @@ uint32_t <?=Translator::PREFIX . $this->getPropertyOffset($propertyDef->name, $c
endforeach; endforeach;
?> ?>
static ZEND_FUNCTION(main) { // clang-format off
php_main();
}
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_void, 0, 0, IS_VOID, 0)
ZEND_END_ARG_INFO()
static const zend_function_entry ext_functions[] = { static const zend_function_entry ext_functions[] = {
ZEND_FE(main, arginfo_void) <?php
foreach ($this->functions as $functionDef):
?>
ZEND_FE(<?=$functionDef->name?>, arginfo_<?=$functionDef->name?>)
<?php endforeach;?>
ZEND_FE_END ZEND_FE_END
}; };
// clang-format on
static PHP_MINIT_FUNCTION(<?=$this->targetName?>) { static PHP_MINIT_FUNCTION(<?=$this->targetName?>) {
// class/interface class entries // class/interface class entries
@ -99,7 +92,7 @@ foreach ($this->globalVars as $name => $type):
foreach ($this->classes as $classDef): foreach ($this->classes as $classDef):
foreach ($classDef->properties as $propertyDef): foreach ($classDef->properties as $propertyDef):
?> ?>
<?=Translator::PREFIX . $this->getPropertyOffset($propertyDef->name, $classDef->name, $classDef->namespace)?> = php::getPropertyOffset("<?=$classDef->getNamespacedName()?>", "<?=$propertyDef->name?>"); <?=Translator::PREFIX . $this->getPropertyOffset($propertyDef->name, $classDef->name, $classDef->namespace)?> = php::getPropertyOffset("<?=$classDef->getNamespacedName(false)?>", "<?=$propertyDef->name?>");
<?php <?php
endforeach; endforeach;
endforeach; endforeach;
@ -137,4 +130,8 @@ zend_module_entry <?=$this->targetName?>_module_entry = {
#ifdef BUILD_PHP_EXTENSION #ifdef BUILD_PHP_EXTENSION
ZEND_GET_MODULE(<?=$this->targetName?>); ZEND_GET_MODULE(<?=$this->targetName?>);
#else
zend_module_entry *<?= self::PREFIX . 'embed_' ?>get_module() {
return &<?= $this->targetName ?>_module_entry;
}
#endif #endif
Loading…
Cancel
Save