对象操作,方法调用、静态方法调用、属性读取

pull/1/head
韩天峰 8 months ago
parent 3492a4ebe6
commit 1a1134d974
  1. 1
      bin/compiler.php
  2. 66
      src/Php/Translator.php
  3. 64
      tests/aot/datetime_builtin_class.phpt

@ -39,6 +39,7 @@ foreach ($list as $file) {
}
$sourceFiles[] = $cppFile;
} catch (Unsupported $e) {
echo " unsupported syntax: " . $e->getMessage() . "\n";
echo " skip: " . $file . "\n";
}
}

@ -116,6 +116,7 @@ class Translator extends \PhpAot\Core\Translator
'argv' => self::TYPE_ARRAY,
];
private array $localVars = [];
private array $objectWrappers = [];
const string PREFIX = 'php_';
private string $rootPath;
@ -656,6 +657,10 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseTernary($expr);
case 'Expr_FuncCall':
return $this->parseFuncCall($expr);
case 'Expr_MethodCall':
return $this->parseMethodCall($expr);
case 'Expr_StaticCall':
return $this->parseStaticCall($expr);
case 'Expr_Include':
return $this->parseInclude($expr);
case 'Expr_Eval':
@ -1302,7 +1307,6 @@ class Translator extends \PhpAot\Core\Translator
break;
}
}
if (empty($expr->args)) {
return 'php::call(' . $fn . ')';
} else {
@ -1310,9 +1314,14 @@ class Translator extends \PhpAot\Core\Translator
}
}
private function parseCallArgs(array $args, string $funcName = ''): string
private function parseCallArgs(array $args, string $funcName = '', string $className = ''): string
{
if (!$className) {
$internalFunction = $this->isInternalFunction($funcName);
} else {
$internalFunction = false;
}
$list_args = [];
foreach ($args as $i => $arg) {
if ($arg->value->getType() === self::EXPR_VARIABLE) {
@ -1320,7 +1329,7 @@ class Translator extends \PhpAot\Core\Translator
// 调用了不存在的变量,可能是引用
if (!$this->hasVar($name)) {
$this->addLocalVar($name, self::TYPE_REF);
} else {
} else if ($funcName) {
$funcArg = Reflection::getFunctionParameter($funcName, 0);
// 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数
if ($funcArg and $funcArg->isPassedByReference()) {
@ -1593,7 +1602,7 @@ class Translator extends \PhpAot\Core\Translator
if (empty($args)) {
return 'php::newObject("' . $className . '")';
} else {
return 'php::newObject("' . $className . '"(' . $this->parseCallArgs($args) . ')';
return 'php::newObject("' . $className . '", ' . $this->parseCallArgs($args) . ')';
}
}
@ -1795,7 +1804,7 @@ class Translator extends \PhpAot\Core\Translator
private function parsePropertyFetch(Node $expr): string
{
return $this->parseIdentifier($expr->var) . '.getProperty(' . $this->parseIdentifier($expr->name) . ')';
return $this->convertToObject($expr->var) . '.getProperty("' . $this->parseIdentifier($expr->name) . '")';
}
private function parseAssignOpShiftRight(Node $node): string
@ -2069,6 +2078,30 @@ class Translator extends \PhpAot\Core\Translator
return $expr;
}
private function convertToObject(Node $object): string
{
$id = $this->parseIdentifier($object);
if (!$this->hasVar($id)) {
$this->addLocalVar($id, self::TYPE_OBJECT);
return $id;
}
$type = $this->getVarType($id);
if ($type === self::TYPE_OBJECT) {
return $id;
}
if (isset($this->objectWrappers[$id])) {
return $this->objectWrappers[$id];
}
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_OBJECT);
$this->beforeStmtLines[] = $this->getIndent() . $tmpVar . ' = ' . $id . ';';
$this->objectWrappers[$id] = $tmpVar;
return $tmpVar;
}
public function genFunctionDeclaration(string $file): void
{
$code = '';
@ -2101,4 +2134,27 @@ class Translator extends \PhpAot\Core\Translator
}
abort($expr);
}
private function parseMethodCall(mixed $expr): string
{
$object = $this->convertToObject($expr->var);
$method = $this->parseIdentifier($expr->name);
if (empty($expr->args)) {
return $object . '.exec("' . $method . '")';
} else {
return $object . '.exec("' . $method . '", ' . $this->parseCallArgs($expr->args) . ')';
}
}
private function parseStaticCall(mixed $expr): string
{
$class = $this->parseIdentifier($expr->class);
$method = $this->parseIdentifier($expr->name);
$fn = $class . '::' . $method;
if (empty($expr->args)) {
return 'php::call("' . $fn . '")';
} else {
return 'php::call("' . $fn . '", {' . $this->parseCallArgs($expr->args) . '})';
}
}
}

@ -0,0 +1,64 @@
--TEST--
DateTime Built-in Class - Creating objects, calling methods, reading/writing properties
--FILE--
<?php
// Test DateTime class basic functionality
$date = new DateTime('2023-06-15 10:30:45');
echo $date->format('Y-m-d H:i:s') . "\n";
// Test modifying date
$date->modify('+1 day');
echo $date->format('Y-m-d H:i:s') . "\n";
// Test setting date and time
$date->setDate(2024, 1, 1);
$date->setTime(12, 0, 0);
echo $date->format('Y-m-d H:i:s') . "\n";
// Test timestamp
$timestamp = $date->getTimestamp();
echo $timestamp . "\n";
// Create from timestamp
$date2 = new DateTime();
$date2->setTimestamp($timestamp);
echo $date2->format('Y-m-d H:i:s') . "\n";
// Test timezone
$date->setTimezone(new DateTimeZone('UTC'));
echo $date->format('Y-m-d H:i:s T') . "\n";
// Test diff method
$date3 = new DateTime('2023-01-01');
$date4 = new DateTime('2023-12-31');
$interval = $date3->diff($date4);
echo $interval->days . " days\n";
// Test static create methods
$now = DateTime::createFromFormat('U', time());
echo $now->format('Y-m-d H:i:s') . "\n";
// Test add/subtract intervals
$date->add(new DateInterval('P1D')); // Add 1 day
echo $date->format('Y-m-d H:i:s') . "\n";
$date->sub(new DateInterval('P1D')); // Subtract 1 day
echo $date->format('Y-m-d H:i:s') . "\n";
// Test formatting options
echo $date->format('c') . "\n"; // ISO 8601 format
echo $date->format('r') . "\n"; // RFC 2822 format
?>
--EXPECTF--
2023-06-15 10:30:45
2023-06-16 10:30:45
2024-01-01 12:00:00
1704110400
2024-01-01 12:00:00
2024-01-01 12:00:00 UTC
364 days
%d-%d-%d %d:%d:%d
2024-01-02 12:00:00
2024-01-01 12:00:00
2024-01-01T12:00:00+00:00
Mon, 01 Jan 2024 12:00:00 +0000
Loading…
Cancel
Save