feat(compiler): 添加构造方法属性提升支持

- 在 ArgInfo 中添加 property 属性标识参数是否为属性提升
- 引入 PropertyPromotion trait 处理属性提升代码生成
- 在编译器中实现构造方法属性提升的解析和代码生成逻辑
- 支持将 promoted 参数转换为类属性定义
- 生成对应的 this_.setProperty 调用代码
- 更新函数信息解析以处理属性提升参数
pull/1/head
韩天峰 6 months ago
parent 15ea7023f0
commit 35117d5c14
  1. 21
      bin/gen_stub.php
  2. 1
      src/Php/ArgInfo.php
  3. 19
      src/Php/CompilerBase.php
  4. 16
      src/Php/Generator/PropertyPromotion.php

@ -81,7 +81,6 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly =
global $translator;
$stubFilenameWithoutExtension = $translator->getArgInfoStubFilename($stubFile);
$arginfoFile = $context->objectFile;
var_dump($arginfoFile);
$legacyFile = "{$stubFilenameWithoutExtension}_legacy_arginfo.h";
$stubCode = file_get_contents($stubFile);
@ -4502,7 +4501,8 @@ class FileInfo {
$classStmt,
$cond,
$this->isUndocumentable,
$this->getMinimumPhpVersionIdCompatibility()
$this->getMinimumPhpVersionIdCompatibility(),
$propertyInfos,
);
} else if ($classStmt instanceof Stmt\EnumCase) {
$enumCaseInfos[] = new EnumCaseInfo(
@ -4738,7 +4738,8 @@ function parseFunctionLike(
Node\FunctionLike $func,
?string $cond,
bool $isUndocumentable,
?int $minimumPhpVersionIdCompatibility
?int $minimumPhpVersionIdCompatibility,
?array &$propertyInfos = null,
): FuncInfo {
try {
$comments = $func->getComments();
@ -4810,7 +4811,19 @@ function parseFunctionLike(
$foundVariadic = false;
foreach ($func->getParams() as $i => $param) {
if ($param->isPromoted()) {
throw new Exception("Promoted properties are not supported");
$propertyItem = new Stmt\PropertyProperty($param->var->name, $param->default);
$property = new Stmt\Property($param->flags, [$propertyItem], $param->getAttributes(), $param->type, $param->attrGroups);
$propertyInfos[] = parseProperty(
$name->className,
$classFlags,
$param->flags,
$propertyItem,
$property->type,
$property->getComments(),
$prettyPrinter,
$minimumPhpVersionIdCompatibility,
AttributeInfo::createFromGroups($property->attrGroups)
);
}
$varName = $param->var->name;

@ -15,4 +15,5 @@ class ArgInfo
public string $default = '';
public bool $byRef = false;
public bool $variadic = false;
public bool $property = false;
}

@ -19,6 +19,7 @@ use PhpAot\Php\Exception\Redo;
use PhpAot\Php\Exception\Skip;
use PhpAot\Php\Generator\ClosureGenerator;
use PhpAot\Php\Generator\PlaceHolderGenerator;
use PhpAot\Php\Generator\PropertyPromotion;
use PhpAot\Php\Generator\Utils;
use PhpParser\Modifiers;
use PhpParser\Node;
@ -39,6 +40,7 @@ class CompilerBase extends \PhpAot\Core\Translator
use FuncCallOptimizer;
use ClosureGenerator;
use PlaceHolderGenerator;
use PropertyPromotion;
use Utils;
public const string TYPE_VAR = 'php::Var';
@ -831,6 +833,13 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->indentLevel++;
$code .= $this->genLocalVarDecl();
$code .= "\n";
// Constructor Property Promotion
foreach ($this->functionDef->argInfoList as $argInfo) {
if (!$argInfo->property) {
continue;
}
$code .= $this->genPropertyPromotion($argInfo);
}
$this->indentLevel--;
$code .= $this->genDebugInfo();
$code .= $stmts;
@ -924,6 +933,15 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->stubFile and !$param->type) {
throw new \RuntimeException('No type for ' . $this->parseIdentifier($param->var));
}
// 构造方法属性定义语法(Constructor Property Promotion)
if ($param->isPromoted()) {
if (!$this->classDef or !$this->methodDef or $this->methodDef->name !== '__construct') {
$this->fatalError($param, 'Promoted properties are not supported');
}
$name = $this->parseIdentifier($param->var);
$propertyDef = new PropertyDef($name, $param->flags, $param->type, $param->default);
$this->classDef->properties[$name] = $propertyDef;
}
if ($param->variadic and $i !== $last) {
$this->fatalError($param, 'Variadic parameters must be the last parameter');
}
@ -939,6 +957,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$argInfo->type = $type;
$argInfo->byRef = $param->byRef;
$argInfo->variadic = $param->variadic;
$argInfo->property = $param->isPromoted();
if (isset($param->default)) {
$functionDef->argCountRequired = count($list) - 1;
/**

@ -0,0 +1,16 @@
<?php
namespace PhpAot\Php\Generator;
use PhpAot\Php\ArgInfo;
trait PropertyPromotion
{
protected function genPropertyPromotion(ArgInfo $argInfo): string
{
$code = '';
$code .= "this_.setProperty(" . $this->genCharPtr($argInfo->name) . ", " . $argInfo->name . ")";
$code .= ";\n";
return $code;
}
}
Loading…
Cancel
Save