feat(stdlib): lower core datetime calls directly

master
韩天峰 13 hours ago
parent 27aa8ea930
commit 684c47458b
  1. 10
      phpunit/code/datetime-direct-calls.php
  2. 26
      phpunit/src/DatetimeOptimizerTest.php
  3. 35
      src/Optimizer/FuncCallOptimizer.php
  4. 18
      tests/compiler/stdlib/datetime-direct.phpt

@ -0,0 +1,10 @@
<?php
function datetimeDirectCalls(int $timestamp): string
{
$now = time();
return date('Y-m-d', $timestamp)
. gmdate('Y-m-d H:i:s', $timestamp)
. date('U', $timestamp)
. $now;
}

@ -0,0 +1,26 @@
<?php
use TypePhp\CompilerTest;
final class DatetimeOptimizerTest extends BaseTest
{
public function testCoreDatetimeCallsUseDirectPhpxWrappers(): void
{
global $translator;
$compiler = CompilerTest::create(TYPEPHP_ROOT_PATH);
$translator = $compiler;
$source = TYPEPHP_ROOT_PATH . '/phpunit/code/datetime-direct-calls.php';
$compiler->addFiles([$source]);
$compiler->prepareFile($source);
$generated = $compiler->convertFile($source);
$code = file_get_contents($generated);
self::assertIsString($code);
self::assertSame(1, substr_count($code, 'php::fn::time('));
self::assertSame(2, substr_count($code, 'php::fn::date('));
self::assertSame(1, substr_count($code, 'php::fn::gmdate('));
self::assertStringNotContainsString('get_persistent_func', $code);
self::assertStringNotContainsString('php::call(', $code);
}
}

@ -81,9 +81,9 @@ trait FuncCallOptimizer
'version_compare', 'gettype', 'version_compare', 'gettype',
'is_array', 'is_string', 'is_object', 'is_resource', 'is_array', 'is_string', 'is_object', 'is_resource',
'is_scalar', 'is_numeric', 'is_countable', 'is_iterable', 'is_scalar', 'is_numeric', 'is_countable', 'is_iterable',
'array_is_list', 'is_dir', 'is_file', 'file_exists', 'realpath', 'time', 'array_is_list', 'is_dir', 'is_file', 'file_exists', 'realpath',
'in_array', 'array_search', 'in_array', 'array_search',
'date', 'strtotime', 'md5', 'sha1', 'hash', 'print_r', 'strtotime', 'md5', 'sha1', 'hash', 'print_r',
'base64_encode', 'base64_decode', 'base64_encode', 'base64_decode',
'urlencode', 'urldecode', 'rawurlencode', 'rawurldecode', 'urlencode', 'urldecode', 'rawurlencode', 'rawurldecode',
'json_encode', 'json_decode', 'serialize', 'unserialize', 'json_encode', 'json_decode', 'serialize', 'unserialize',
@ -121,6 +121,31 @@ trait FuncCallOptimizer
'str_ends_with' => [], 'str_ends_with' => [],
'str_contains' => [], 'str_contains' => [],
// Date/time core functions. Keep their ABI explicit so these
// calls never depend on runtime Reflection metadata or fall back
// to php::call() when the arguments have proven scalar types.
'time' => [
'args' => '',
'minArgs' => 0,
'maxArgs' => 0,
'returnType' => Type::INT,
'intrinsic' => true,
],
'date' => [
'args' => 's_?i',
'minArgs' => 1,
'maxArgs' => 2,
'returnType' => Type::STR,
'intrinsic' => true,
],
'gmdate' => [
'args' => 's_?i',
'minArgs' => 1,
'maxArgs' => 2,
'returnType' => Type::STR,
'intrinsic' => true,
],
'strncmp' => ['constFold' => self::FOLD_CMP3], 'strncmp' => ['constFold' => self::FOLD_CMP3],
'strncasecmp' => ['constFold' => self::FOLD_CMP3], 'strncasecmp' => ['constFold' => self::FOLD_CMP3],
'explode' => [], 'explode' => [],
@ -361,7 +386,11 @@ trait FuncCallOptimizer
if ($argCount < $minArgs) { if ($argCount < $minArgs) {
$this->fatalError($expr, "{$name}() expects at least {$minArgs} argument(s), {$argCount} given"); $this->fatalError($expr, "{$name}() expects at least {$minArgs} argument(s), {$argCount} given");
} }
if ($maxArgs > 0 && $argCount > $maxArgs) { // An explicit zero is a real zero-argument limit (for example
// time()). Reflection lookup failure also uses zero as its
// unknown sentinel, so only enforce that implicit value when it
// is greater than zero.
if ((array_key_exists('maxArgs', $config) || $maxArgs > 0) && $argCount > $maxArgs) {
$this->fatalError($expr, "{$name}() expects at most {$maxArgs} argument(s), {$argCount} given"); $this->fatalError($expr, "{$name}() expects at most {$maxArgs} argument(s), {$argCount} given");
} }
} }

@ -0,0 +1,18 @@
--TEST--
date, gmdate and time use direct PHPX wrappers
--FILE--
<?php
function main(): void
{
date_default_timezone_set('Asia/Shanghai');
var_dump(date('Y-m-d H:i:s', 0));
var_dump(gmdate('Y-m-d H:i:s', 0));
var_dump(time() > 0);
}
?>
--EXPECT--
string(19) "1970-01-01 08:00:00"
string(19) "1970-01-01 00:00:00"
bool(true)
Loading…
Cancel
Save