feat(compiler): 添加对mixed类型支持和优化函数调用解析

- 在解析函数声明时调整了返回类型检查逻辑,先验证类型存在性再进行类型转换
- 新增对mixed类型的参数类型解析,映射到TYPE_VAR类型
- 添加对resource类型的错误处理机制
- 将原parseCallArgs方法替换为专门的parseNativeCallArgs方法用于本地函数调用
- 在C++主程序中添加php::request_init()初始化调用
- 新增埃拉托斯特尼筛法求素数示例程序及对应的vector扩展实现
- 添加vector.stub.php存根文件定义vector相关函数接口
pull/1/head
韩天峰 7 months ago
parent 6878ecc517
commit 1fc07ee729
  1. 51
      examples/prime.php
  2. 54
      examples/prime/main.php
  3. 32
      examples/prime/vector.cc
  4. 15
      examples/prime/vector.stub.php
  5. 11
      src/Php/CompilerBase.php
  6. 1
      src/cpp/main.cc

@ -0,0 +1,51 @@
<?php
// 埃拉托斯特尼筛法求素数
function sieveOfEratosthenes(int $limit)
{
if ($limit < 2) return [];
// 初始化布尔数组,索引代表数字,值代表是否为素数
$isPrime = array_fill(0, $limit + 1, true);
$isPrime[0] = false;
$isPrime[1] = false; // 0 和 1 不是素数
for ($i = 2; $i * $i <= $limit; $i++) {
if ($isPrime[$i]) {
// 标记 i 的所有倍数为非素数
for ($j = $i * $i; $j <= $limit; $j += $i) {
$isPrime[$j] = false;
}
}
}
// 收集所有素数
$primes = [];
for ($num = 2; $num <= $limit; $num++) {
if ($isPrime[$num]) {
$primes[] = $num;
}
}
return $primes;
}
function main()
{
global $argv;
$n = isset($argv[2]) ? (int)$argv[2] : 10000000;
$begin = microtime(true);
// 参数校验
if ($n < 2) {
fwrite(STDERR, "请输入一个大于等于2的整数作为上限。\n");
exit(1);
}
$primes = sieveOfEratosthenes($n);
var_dump(count($primes));
var_dump(microtime(true) - $begin);
// 输出每个素数(每行一个)
// foreach ($primes as $prime) {
// echo $prime . "\n";
// }
}

@ -0,0 +1,54 @@
<?php
// 埃拉托斯特尼筛法求素数
function sieveOfEratosthenes(int $limit)
{
if ($limit < 2) return [];
// 初始化布尔数组,索引代表数字,值代表是否为素数
$isPrime = vector_new($limit + 1, true);
// 0 和 1 不是素数
vector_set($isPrime, 0, false);
vector_set($isPrime, 1, false);
for ($i = 2; $i * $i <= $limit; $i++) {
if (vector_get($isPrime, $i)) {
// 标记 i 的所有倍数为非素数
for ($j = $i * $i; $j <= $limit; $j += $i) {
vector_set($isPrime, $j, false);
}
}
}
// 收集所有素数
$primes = [];
for ($num = 2; $num <= $limit; $num++) {
if (vector_get($isPrime, $num)) {
$primes[] = $num;
}
}
return $primes;
}
function main()
{
global $argv;
$n = isset($argv[2]) ? (int)$argv[2] : 100000;
$begin = microtime(true);
// 参数校验
if ($n < 2) {
fwrite(STDERR, "请输入一个大于等于2的整数作为上限。\n");
exit(1);
}
$primes = sieveOfEratosthenes($n);
var_dump(count($primes));
var_dump(microtime(true) - $begin);
// 输出每个素数(每行一个)
// foreach ($primes as $prime) {
// echo $prime . "\n";
// }
}

@ -0,0 +1,32 @@
#include <phpx.h>
using namespace php;
class VectorBox : public Box {
public:
std::vector<bool> vec;
VectorBox(size_t size, bool init) {
vec.resize(size, init);
}
void checkOffset(Int offset) {
if (offset >= vec.size()) {
zend_throw_error(NULL, "index[%ld] is out of range()", offset);
}
}
};
var php_vector_new(Int size, Bool init) {
return {new VectorBox(size, init)};
}
Bool php_vector_get(var box, Int offset) {
auto vecbox = box.toBox<VectorBox>();
vecbox->checkOffset(offset);
return vecbox->vec.at(offset);
}
void php_vector_set(var box, Int offset, Bool value) {
auto vecbox = box.toBox<VectorBox>();
vecbox->checkOffset(offset);
vecbox->vec.at(offset) = value;
}

@ -0,0 +1,15 @@
<?php
function vector_new(int $size, bool $init = false): mixed
{
}
function vector_get(mixed $vector, int $offset): bool
{
}
function vector_set(mixed $vector, int $offset, bool $value): void
{
}

@ -284,11 +284,11 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseFunctionDeclaration(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): FunctionDef
{
$returnType = $v->returnType ? $this->getTypeFromZendType($this->parseIdentifier($v->returnType)) : self::TYPE_VOID;
// .stub 存根定义 C++ Native 函数,必须设置返回值类型
if ($returnType === self::TYPE_VOID && $this->stubFile) {
if (!$v->returnType && $this->stubFile) {
throw new Exception('No return type for ' . $v->name);
}
$returnType = $v->returnType ? $this->getTypeFromZendType($this->parseIdentifier($v->returnType)) : self::TYPE_VOID;
$functionDef = new FunctionDef($this->parseIdentifier($v->name), $returnType);
$this->functionDef = $functionDef;
$this->parseParams($v->params, $functionDef);
@ -1182,6 +1182,11 @@ class CompilerBase extends \PhpAot\Core\Translator
case 'void':
$this->fatalError($param, 'Cannot use `void` as a parameter type.');
break;
case 'mixed':
return self::TYPE_VAR;
case 'resource':
$this->fatalError($param, 'Cannot use `resource` as a parameter type.');
break;
default:
$this->objects[$var] = $name;
return self::TYPE_OBJECT;
@ -1509,7 +1514,7 @@ class CompilerBase extends \PhpAot\Core\Translator
}
$nativeFn = $this->findNativeFunction($name);
if ($nativeFn) {
return self::PREFIX . $nativeFn . '(' . $this->parseCallArgs($expr->args, $name) . ')';
return self::PREFIX . $nativeFn . '(' . $this->parseNativeCallArgs($expr->args, $nativeFn) . ')';
}
if ($this->isInternalFunction($name)) {
$fn = 'php::' . $name;

@ -35,6 +35,7 @@ int main(int cpp_argc, char **cpp_argv) {
ProfilerStart("profile.out");
#endif
zend_first_try {
php::request_init();
php_app_init();
php::eval("main();");
}

Loading…
Cancel
Save