fix(optimizer): preserve class_exists autoload evaluation

master
韩天峰 4 hours ago
parent 3452ddfd6e
commit 057c217800
  1. 21
      phpunit/code/class-exists-autoload-argument.php
  2. 8
      phpunit/src/ClassExistsTraitFoldTest.php
  3. 6
      src/Optimizer/FuncCallOptimizer.php
  4. 29
      tests/compiler/stdlib/class_exists.phpt

@ -0,0 +1,21 @@
<?php
/**
* This file is part of TypePHP(AOT).
*
* @link https://www.swoole.com/aot/
* @contact service@swoole.com
*/
class KnownClass
{
}
function autoloadFlag(): bool
{
return false;
}
function main(): void
{
var_dump(class_exists('KnownClass', autoloadFlag()));
}

@ -35,6 +35,14 @@ class ClassExistsTraitFoldTest extends TestCase
self::assertStringNotContainsString('= false;', $cpp);
}
public function testExplicitAutoloadArgumentUsesNormalCallPath(): void
{
$cpp = $this->compileToCpp('class-exists-autoload-argument.php');
self::assertStringContainsString('php::fn::class_exists(', $cpp);
self::assertStringContainsString('php_autoloadflag()', $cpp);
}
private function compileToCpp(string $file): string
{
global $translator;

@ -663,6 +663,12 @@ trait FuncCallOptimizer
protected function doFoldKnownClass(Node\Expr\FuncCall $expr): string|false
{
// An explicit $autoload argument must still be evaluated, including
// any side effects or exception it produces. Leave that form on the
// normal call path instead of duplicating argument semantics here.
if (count($expr->args) !== 1 || !($expr->args[0] instanceof Node\Arg)) {
return false;
}
$cn = $expr->args[0]->value;
if (!$this->isScalarString($cn) || !$this->hasClass($cn->value)) {
return false;

@ -7,6 +7,18 @@ interface MyInterface {}
trait MyTrait {}
enum MyEnum { case Foo; }
function autoloadFlag(string $label): bool
{
echo "autoload-$label\n";
return false;
}
function throwingAutoloadFlag(): bool
{
echo "autoload-throw\n";
throw new RuntimeException('autoload-argument');
}
function main() {
define("MY_CONST", 42);
@ -22,6 +34,17 @@ function main() {
$traitName = "MyTrait";
var_dump(class_exists($traitName));
// An explicit autoload expression must be evaluated exactly once even
// when the literal name makes the final answer statically known.
var_dump(class_exists("MyClass", autoloadFlag('class')));
var_dump(class_exists("MyTrait", autoloadFlag('trait')));
try {
class_exists("MyClass", throwingAutoloadFlag());
echo "exception-not-thrown\n";
} catch (RuntimeException $e) {
echo "caught=", $e->getMessage(), "\n";
}
// interface_exists
var_dump(interface_exists("MyInterface"));
var_dump(interface_exists("NonexistentInterface"));
@ -46,6 +69,12 @@ bool(false)
bool(false)
bool(false)
bool(false)
autoload-class
bool(true)
autoload-trait
bool(false)
autoload-throw
caught=autoload-argument
bool(true)
bool(false)
bool(false)

Loading…
Cancel
Save