feat(php): 添加PHP类型声明解析功能

- 新增DECL_TYPE_OF_RETURN、DECL_TYPE_OF_PROPERTY、DECL_TYPE_OF_CONST、DECL_TYPE_OF_PARAM常量用于标识类型声明上下文
- 扩展zendTypeMap映射表,支持false、true、never、null、callable、iterable等类型
- 修改parseTypeDecl方法,增加$what参数以区分不同的类型声明场景
- 实现对属性和常量类型声明中void/never类型的验证和错误提示
- 更新函数参数类型解析逻辑,统一使用类型声明解析方法
- 在类常量和属性解析中使用新的类型声明解析方法
pull/1/head
韩天峰 6 months ago
parent 12696eeed4
commit 86055c3bf1
  1. 93
      src/Php/CompilerBase.php
  2. 4
      src/Php/Translator.php

@ -59,6 +59,10 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string TYPE_STR = 'php::Str'; public const string TYPE_STR = 'php::Str';
public const string TYPE_REF = 'php::Ref'; public const string TYPE_REF = 'php::Ref';
public const string TYPE_VOID = 'void'; public const string TYPE_VOID = 'void';
public const int DECL_TYPE_OF_RETURN = 1;
public const int DECL_TYPE_OF_PROPERTY = 2;
public const int DECL_TYPE_OF_CONST = 3;
public const int DECL_TYPE_OF_PARAM = 4;
public const string VALUE_NAN = 'std::numeric_limits<double>::quiet_NaN()'; public const string VALUE_NAN = 'std::numeric_limits<double>::quiet_NaN()';
public const string VALUE_INF = 'std::numeric_limits<double>::infinity()'; public const string VALUE_INF = 'std::numeric_limits<double>::infinity()';
public const string VALUE_NULL = 'php::null'; public const string VALUE_NULL = 'php::null';
@ -103,14 +107,23 @@ class CompilerBase extends \PhpAot\Core\Translator
protected int $propIndex = 0; protected int $propIndex = 0;
protected array $propMap = []; protected array $propMap = [];
protected array $zendTypeMap = [ protected array $zendTypeMap = [
'int' => self::TYPE_INT, 'int' => self::TYPE_INT,
'float' => self::TYPE_FLOAT, 'float' => self::TYPE_FLOAT,
'bool' => self::TYPE_BOOL, 'bool' => self::TYPE_BOOL,
'void' => self::TYPE_VOID, 'false' => self::TYPE_BOOL,
'true' => self::TYPE_BOOL,
'void' => self::TYPE_VOID,
'never' => self::TYPE_VOID,
'string' => self::TYPE_STR, 'string' => self::TYPE_STR,
'array' => self::TYPE_ARRAY, 'array' => self::TYPE_ARRAY,
'object' => self::TYPE_OBJECT, 'object' => self::TYPE_OBJECT,
'mixed' => self::TYPE_VAR, 'mixed' => self::TYPE_VAR,
'null' => self::TYPE_VAR,
// callable 类型,可以是字符串、数组、对象
// 1) 'foo' 函数名称字符串, 2) [ $obj, 'bar' ] 对象方法数组, 3) Closure 对象, 4) [ 'class', 'staticMethod'] 类名+静态方法数组
'callable' => self::TYPE_VAR,
// iterable 类型,可以是数组或者对象
'iterable' => self::TYPE_VAR,
]; ];
protected array $globalHeaders = [ protected array $globalHeaders = [
'phpx.h', 'phpx.h',
@ -732,13 +745,22 @@ class CompilerBase extends \PhpAot\Core\Translator
return 'php_get_prop(' . $funcId . ', ' . $this->getLiteralString($prop) . ', ' . $classId . ', ' . $this->getLiteralString($class) . ')'; return 'php_get_prop(' . $funcId . ', ' . $this->getLiteralString($prop) . ', ' . $classId . ', ' . $this->getLiteralString($class) . ')';
} }
protected function parseTypeDecl(?NodeAbstract $type): string protected function parseTypeDecl(?NodeAbstract $type, int $what): string
{ {
// 联合类型暂时不支持,使用 var 类型代替 // 未定义类型,默认是 var (mixed, any)
if ($type instanceof UnionType or $type instanceof NullableType) { if ($type === null) {
return self::TYPE_VAR;
} elseif ($type instanceof UnionType or $type instanceof NullableType) {
// 联合类型暂时不支持,使用 var 类型代替
return self::TYPE_VAR; return self::TYPE_VAR;
} else { } else {
return $type ? $this->getTypeFromZendType($this->parseIdentifier($type)) : self::TYPE_VOID; $typeName = $this->parseIdentifier($type);
// 属性和类常量的类型不能声明为 void/never ,只有返回值可以
if ($what !== self::DECL_TYPE_OF_RETURN and ($typeName === 'void' or $typeName === 'never')) {
$this->fatalError($type, 'The type `void`/`never` is allowed only for return type');
} else {
return $this->getTypeFromZendType($typeName);
}
} }
} }
@ -750,7 +772,7 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
$fnName = $this->parseIdentifier($v->name); $fnName = $this->parseIdentifier($v->name);
$returnType = $this->parseTypeDecl($v->returnType); $returnType = $this->parseTypeDecl($v->returnType, self::DECL_TYPE_OF_RETURN);
$functionDef = new FunctionDef($fnName, $returnType, $this->namespace); $functionDef = new FunctionDef($fnName, $returnType, $this->namespace);
$this->functionDef = $functionDef; $this->functionDef = $functionDef;
@ -1756,44 +1778,21 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($param->byRef) { if ($param->byRef) {
return self::TYPE_REF; return self::TYPE_REF;
} }
$type = $param->type; if ($param->type === null or $param->type instanceof Node\NullableType or $param->type instanceof UnionType) {
if ($type == null) {
return self::TYPE_VAR;
}
if ($type instanceof NullableType or $type instanceof UnionType) {
return self::TYPE_VAR; return self::TYPE_VAR;
} }
$name = $type->name; $type = $param->type;
switch ($name) { $typeName = $type->name;
case 'int': if ($typeName === 'void' or $typeName === 'never') {
return self::TYPE_INT; $this->fatalError($param, 'Cannot use `void`/`never` as a parameter type.');
case 'array': } elseif ($typeName === 'self') {
return self::TYPE_ARRAY; $this->addObject($var, $this->classDef->getNamespacedName(false));
case 'float': return self::TYPE_OBJECT;
return self::TYPE_FLOAT; } elseif (isset($this->zendTypeMap[$typeName])) {
case 'bool': return $this->getTypeFromZendType($typeName);
return self::TYPE_BOOL; } else {
case 'string': $this->addObject($var, $this->getNamespacedClassName($typeName));
return self::TYPE_STR; return self::TYPE_OBJECT;
case 'void':
$this->fatalError($param, 'Cannot use `void` as a parameter type.');
// no break
// callable 类型,可以是字符串、数组、对象
// 1) 'foo' 函数名称字符串, 2) [ $obj, 'bar' ] 对象方法数组, 3) Closure 对象, 4) [ 'class', 'staticMethod'] 类名+静态方法数组
case 'callable':
// iterable 类型,可以是数组或者对象
case 'iterable':
case 'mixed':
return self::TYPE_VAR;
case 'self':
$this->addObject($var, $this->classDef->getNamespacedName(false));
return self::TYPE_OBJECT;
case 'resource':
$this->fatalError($param, 'Cannot use `resource` as a parameter type.');
// no break
default:
$this->addObject($var, $this->getNamespacedClassName($name));
return self::TYPE_OBJECT;
} }
} }

@ -1023,7 +1023,7 @@ class Translator extends Preprocessor
protected function parseClassConstDef(Node\Stmt\ClassConst $v): void protected function parseClassConstDef(Node\Stmt\ClassConst $v): void
{ {
$flags = $v->flags; $flags = $v->flags;
$type = $v->type ? $this->getTypeFromZendType($this->parseIdentifier($v->type)) : self::TYPE_VAR; $type = $this->parseTypeDecl($v->type, self::DECL_TYPE_OF_CONST);
foreach ($v->consts as $const) { foreach ($v->consts as $const) {
$constName = $this->parseIdentifier($const->name); $constName = $this->parseIdentifier($const->name);
$constInfo = new ConstantDef($constName, $flags, $type, $this->parseIdentifier($const->value)); $constInfo = new ConstantDef($constName, $flags, $type, $this->parseIdentifier($const->value));
@ -1034,7 +1034,7 @@ class Translator extends Preprocessor
protected function parsePropertyDef(Node\Stmt\Property $v): void protected function parsePropertyDef(Node\Stmt\Property $v): void
{ {
$flags = $v->flags; $flags = $v->flags;
$type = $this->parseTypeDecl($v->type); $type = $this->parseTypeDecl($v->type, self::DECL_TYPE_OF_PROPERTY);
foreach ($v->props as $prop) { foreach ($v->props as $prop) {
$propDef = new PropertyDef($this->parseIdentifier($prop->name), $flags, $type); $propDef = new PropertyDef($this->parseIdentifier($prop->name), $flags, $type);

Loading…
Cancel
Save