diff --git a/src/Php/AstNodeType.php b/src/Php/AstNodeType.php index 1157f976..d7399224 100644 --- a/src/Php/AstNodeType.php +++ b/src/Php/AstNodeType.php @@ -11,6 +11,7 @@ namespace PhpAot\Php; use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\NodeAbstract; +use PhpParser\Node\VariadicPlaceholder; trait AstNodeType { @@ -95,4 +96,9 @@ trait AstNodeType or $expr instanceof Node\Expr\MethodCall or $expr instanceof Node\Expr\StaticCall; } + + protected function isPlaceholderExpr(NodeAbstract $expr): bool + { + return $expr instanceof VariadicPlaceholder; + } } diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index aa87c1fd..3c013f32 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1565,6 +1565,10 @@ class CompilerBase extends \PhpAot\Core\Translator if (!$this->checkAccessible($classDef, $methodDef)) { $this->fatalError($expr, 'Method `' . $classDef->getNamespacedName() . '::' . $method . '()` is not accessible'); } + // 函数调用占位符,不是真实的函数调用 + if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) { + return false; + } if (count($expr->args) < $methodDef->functionDef->argCountRequired) { $this->fatalError($expr, 'Method `' . $classDef->getNamespacedName() . '::' . $method . '()` requires ' . $methodDef->functionDef->argCountRequired . ' arguments, ' . count($expr->args) . ' given'); } elseif (count($expr->args) > count($methodDef->functionDef->argInfoList)) { @@ -2199,7 +2203,7 @@ class CompilerBase extends \PhpAot\Core\Translator $hasNamedArg = false; // 对命名参数进行重排 foreach ($callArgs as $i => $arg) { - if ($arg instanceof Node\VariadicPlaceholder) { + if ($this->isPlaceholderExpr($arg)) { throw new PlaceHolder(); } if ($arg->name) { @@ -2242,7 +2246,7 @@ class CompilerBase extends \PhpAot\Core\Translator $list_args = []; $last = array_key_last($args); foreach ($args as $i => $arg) { - if ($arg instanceof Node\VariadicPlaceholder) { + if ($this->isPlaceholderExpr($arg)) { throw new PlaceHolder(); } if ($arg->name !== null) { diff --git a/src/Php/Generator/PlaceHolderGenerator.php b/src/Php/Generator/PlaceHolderGenerator.php index af609a13..6b2a409b 100644 --- a/src/Php/Generator/PlaceHolderGenerator.php +++ b/src/Php/Generator/PlaceHolderGenerator.php @@ -14,6 +14,11 @@ trait PlaceHolderGenerator { $ce = $this->getClassEntryPtr(\Closure::class); $fn = $ce . ', ' . $this->getFuncPtr('Closure::fromCallable', false); + $tmpVar = $this->genTmpVarName(); + if ($this->classDef) { + $this->beforeStmtLines[] = "auto $tmpVar = php_switch_scope(this_);"; + $this->afterStmtLines[] = "php_restore_scope($tmpVar);"; + } return 'php::call(' . $fn . ', {' . $callable . '})'; } } diff --git a/src/cpp/main.cc b/src/cpp/main.cc index 8d57cca9..0b81b33e 100644 --- a/src/cpp/main.cc +++ b/src/cpp/main.cc @@ -36,6 +36,25 @@ zend_class_entry *php_get_called_ce(php::Object &this_) { } } +static zend_execute_data *get_frame() { + zend_execute_data *frame = EG(current_execute_data); + while (frame && (!frame->func || !ZEND_USER_CODE(frame->func->type))) { + frame = frame->prev_execute_data; + } + return frame; +} + +zend_class_entry *php_switch_scope(php::Object &this_) { + auto frame = get_frame(); + auto ori_scope = frame->func->common.scope; + frame->func->common.scope = php_get_called_ce(this_); + return ori_scope; +} + +void php_restore_scope(zend_class_entry *ori_scope) { + get_frame()->func->common.scope = ori_scope; +} + void module_shutdown(zend_module_entry *module) { /** * There is a bug in PHP's handling of internal strings. All interned strings are released in the request shutdown diff --git a/src/cpp/php_aot_helper.h b/src/cpp/php_aot_helper.h index 287ada20..591378fb 100644 --- a/src/cpp/php_aot_helper.h +++ b/src/cpp/php_aot_helper.h @@ -9,6 +9,8 @@ extern zend_function *php_get_method(int func_id, const php::Str &method_name, i extern const char *php_get_called_class(php::Object &this_); extern zend_class_entry *php_get_called_ce(php::Object &this_); +extern zend_class_entry *php_switch_scope(php::Object &this_); +extern void php_restore_scope(zend_class_entry *ori_scope); static inline php::Variant CALL(int func_id, const php::Str &func_name) { return php::call(php_get_func(func_id, func_name)); diff --git a/tests/aot/private-prop-002.phpt b/tests/aot/private-prop-002.phpt new file mode 100644 index 00000000..bda9f6c4 --- /dev/null +++ b/tests/aot/private-prop-002.phpt @@ -0,0 +1,24 @@ +--TEST-- +Static Class Property Read/Write Test +--FILE-- + +--EXPECT-- +string(19) "Worker::checkErrors" \ No newline at end of file