refactor(compiler): update function naming and namespace handling logic

- Replace escapeFunction with escapeNativeFunctionKey in symbol operations
- Add NAMESPACE_END_MARKER constant for namespace separation
- Implement separate method name generation for functions vs class methods
- Create getNativeFunctionName and getNativeClassMethodName helper methods
- Update function call resolution to handle namespaced functions properly
- Modify native method name generation to use new namespace format
- Update test expectations for new function naming pattern
- Fix trait method name generation to use proper class method naming
pull/43/head
韩天峰 4 weeks ago
parent cf559bc9f4
commit f78d19fffd
  1. 5
      phpunit/code/function-method-symbol-collision.php
  2. 4
      phpunit/src/FunctionTest.php
  3. 68
      src/CompilerBase.php
  4. 26
      src/Context/CompilationStateTrait.php
  5. 2
      src/Parser/UniversalMethodCall.php
  6. 12
      src/Translator.php

@ -10,6 +10,11 @@ namespace Collision {
}
namespace Collision\Worker {
function validate(mixed $validater): mixed
{
return $validater;
}
function invoke_validate(mixed $validater): mixed
{
return validate($validater);

@ -13,8 +13,8 @@ class FunctionTest extends \BaseTest
$cppFile = $compiler->convertFile($testFile);
$cpp = file_get_contents($cppFile);
$this->assertStringContainsString('php::call(', $cpp);
$this->assertStringNotContainsString('php_collision__worker__validate(validater)', $cpp);
$this->assertStringContainsString('php_collision__worker__NSE__validate(validater)', $cpp);
$this->assertStringContainsString('php_collision__NSE__worker__validate(', $cpp);
}
public function testReturnRef(): void

@ -196,6 +196,7 @@ class CompilerBase implements PropertyAccessContext
public const string FUNC_MAP = 'func_map';
public const string PROP_MAP = 'property_map';
public const string NAMESPACE_SEPARATOR = '__';
public const string NAMESPACE_END_MARKER = 'NSE';
public const string PREFIX = 'php_';
protected const string MULTI_RETURN_NAMESPACE = 'typephp::detail';
@ -1018,7 +1019,14 @@ class CompilerBase implements PropertyAccessContext
protected function getFunctionName(FunctionLike $v): string
{
return $this->getNativeName($this->parseIdentifier($v->name), $this->namespace, $this->class);
if ($this->class !== '') {
return $this->getNativeClassMethodName(
$this->parseIdentifier($v->name),
$this->namespace,
$this->class,
);
}
return $this->getNativeFunctionName($this->parseIdentifier($v->name), $this->namespace);
}
protected function getFullClassName(): string
@ -1141,6 +1149,29 @@ class CompilerBase implements PropertyAccessContext
return implode(self::NAMESPACE_SEPARATOR, $names);
}
protected function getNativeFunctionName(string $function, string $namespace = ''): string
{
$names = [];
if ($namespace !== '') {
$names[] = $this->escapeNamespace($namespace);
$names[] = self::NAMESPACE_END_MARKER;
}
$names[] = $this->escapeName($function);
return implode(self::NAMESPACE_SEPARATOR, $names);
}
protected function getNativeClassMethodName(string $method, string $namespace, string $class): string
{
$names = [];
if ($namespace !== '') {
$names[] = $this->escapeNamespace($namespace);
}
$names[] = self::NAMESPACE_END_MARKER;
$names[] = $this->escapeClass($class);
$names[] = $this->escapeName($method);
return implode(self::NAMESPACE_SEPARATOR, $names);
}
protected function getClassId(string $className): int
{
if (isset($this->classMap[$className])) {
@ -2362,7 +2393,7 @@ class CompilerBase implements PropertyAccessContext
if ($checkArgs) {
$this->checkNativeCallArgs($expr, $methodDef->functionDef, $expr->args, $classDef->getNamespacedName() . '::' . $method);
}
return $this->getNativeName($method, $classDef->namespace, $classDef->name);
return $this->getNativeClassMethodName($method, $classDef->namespace, $classDef->name);
}
protected function findNativeClassConst(NodeAbstract $expr, string $class, string $const): string|false
@ -2814,17 +2845,33 @@ class CompilerBase implements PropertyAccessContext
// 绝对命名空间的函数
if ($funcName[0] == '\\') {
$funcName = ltrim($funcName, '\\');
$possibleFunctionNames = [$this->escapeName($funcName)];
$separator = strrpos($funcName, '\\');
if ($separator === false) {
$possibleFunctionNames = [$this->getNativeFunctionName($funcName)];
} else {
$possibleFunctionNames = [$this->getNativeFunctionName(
substr($funcName, $separator + 1),
substr($funcName, 0, $separator),
)];
}
} else {
$possibleFunctionNames = [$this->escapeName($funcName)];
$possibleFunctionNames = [$this->getNativeFunctionName($funcName)];
if (isset($this->useAliases[$funcName])) {
$possibleFunctionNames[] = $this->escapeName($this->escapeNamespace($this->useAliases[$funcName]));
$alias = $this->useAliases[$funcName];
$separator = strrpos($alias, '\\');
$possibleFunctionNames[] = $separator === false
? $this->getNativeFunctionName($alias)
: $this->getNativeFunctionName(substr($alias, $separator + 1), substr($alias, 0, $separator));
}
if ($this->namespace) {
$possibleFunctionNames[] = $this->escapeNamespace($this->namespace) . self::NAMESPACE_SEPARATOR . $this->escapeName($funcName);
$possibleFunctionNames[] = $this->getNativeFunctionName($funcName, $this->namespace);
}
if (isset($this->useFunctions[$funcName])) {
$possibleFunctionNames[] = $this->escapeNamespace($this->useFunctions[$funcName]);
$alias = $this->useFunctions[$funcName];
$separator = strrpos($alias, '\\');
$possibleFunctionNames[] = $separator === false
? $this->getNativeFunctionName($alias)
: $this->getNativeFunctionName(substr($alias, $separator + 1), substr($alias, 0, $separator));
}
// 复杂命名空间规则,组合命名空间
// 例子:use foo\bar; bar\fn();
@ -2834,7 +2881,12 @@ class CompilerBase implements PropertyAccessContext
if ($ns1[array_key_last($ns1)] === $ns2[array_key_first($ns2)]) {
$ns = array_merge($ns1, $ns2);
array_splice($ns, array_key_last($ns1) + 1);
$possibleFunctionNames[] = $this->escapeNamespace(implode('\\', $ns));
$fullName = implode('\\', $ns);
$separator = strrpos($fullName, '\\');
$possibleFunctionNames[] = $this->getNativeFunctionName(
substr($fullName, $separator + 1),
substr($fullName, 0, $separator),
);
break;
}
}

@ -106,7 +106,7 @@ trait CompilationStateTrait
protected function addFunction(string $name, FunctionDef $functionDef): void
{
$this->symbols->putFunction($this->escapeFunction($name), $functionDef);
$this->symbols->putFunction($this->escapeNativeFunctionKey($name), $functionDef);
}
/**
@ -114,12 +114,32 @@ trait CompilationStateTrait
*/
protected function hasFunction(string $name): bool
{
return $this->symbols->hasFunction($this->escapeFunction($name));
return $this->symbols->hasFunction($this->escapeNativeFunctionKey($name));
}
protected function getFunction(string $name): FunctionDef
{
return $this->symbols->function($this->escapeFunction($name));
return $this->symbols->function($this->escapeNativeFunctionKey($name));
}
/** Normalize PHP name segments without lowercasing the reserved ABI marker. */
private function escapeNativeFunctionKey(string $name): string
{
$placeholder = "\x00";
$leadingPlaceholder = "\x01";
$name = str_replace(
self::NAMESPACE_SEPARATOR . self::NAMESPACE_END_MARKER . self::NAMESPACE_SEPARATOR,
self::NAMESPACE_SEPARATOR . $placeholder . self::NAMESPACE_SEPARATOR,
$name,
);
if (str_starts_with($name, self::NAMESPACE_END_MARKER . self::NAMESPACE_SEPARATOR)) {
$name = $leadingPlaceholder . substr($name, strlen(self::NAMESPACE_END_MARKER));
}
return str_replace(
[$placeholder, $leadingPlaceholder],
[self::NAMESPACE_END_MARKER, self::NAMESPACE_END_MARKER],
$this->escapeFunction($name),
);
}
protected function addClass(string $name, ClassDef $classDef): void

@ -392,7 +392,7 @@ trait UniversalMethodCall
}
$registry[$targetKey][$methodKey] = [
'handler' => 'provider_extension',
'fn' => $this->getNativeName($method->name, $provider->namespace, $provider->name),
'fn' => $this->getNativeClassMethodName($method->name, $provider->namespace, $provider->name),
'class' => $provider->getNamespacedName(false),
'return_type' => $function->returnType,
'min_args' => max(0, $function->argCountRequired - 1),

@ -2471,7 +2471,7 @@ CODE;
protected function getNativeMethodName(ClassDef $classDef, MethodDef $methodDef): string
{
return $this->getNativeName($methodDef->name, $classDef->namespace, $classDef->name);
return $this->getNativeClassMethodName($methodDef->name, $classDef->namespace, $classDef->name);
}
protected function parseDeclare(mixed $v): void
@ -4543,8 +4543,8 @@ CODE;
$this->checkTraitMethodOverrideCompatibility($classDef, $methodDef, $classMethodName);
$classDef->addMethod($methodDef);
$traitMethodNativeName = $this->getNativeName($traitMethodName, $traitDef->namespace, $traitDef->name);
$classMethodNativeName = $this->getNativeName($classMethodName, $classDef->namespace, $classDef->name);
$traitMethodNativeName = $this->getNativeClassMethodName($traitMethodName, $traitDef->namespace, $traitDef->name);
$classMethodNativeName = $this->getNativeClassMethodName($classMethodName, $classDef->namespace, $classDef->name);
$argList = ['this_'];
if ($methodDef->parentMethodCalls) {
// Bind parent:: to the class that actually composes the trait. This
@ -4780,7 +4780,7 @@ CODE;
{
$name = $this->escapeZendFnName($functionDef->getNamespacedName());
$cppCode = 'ZEND_FUNCTION(' . $name . '){' . PHP_EOL;
$fn = self::PREFIX . $this->getNativeName($functionDef->name, $functionDef->namespace);
$fn = self::PREFIX . $this->getNativeFunctionName($functionDef->name, $functionDef->namespace);
$cppCode .= $this->genWrapperFunctionArgs($fn, $functionDef, $functionDef->getNamespacedName());
return $cppCode;
@ -4792,9 +4792,9 @@ CODE;
$fullName = ltrim($fullName, '\\');
$separator = strrpos($fullName, '\\');
if ($separator === false) {
return self::PREFIX . $this->getNativeName($fullName);
return self::PREFIX . $this->getNativeFunctionName($fullName);
}
return self::PREFIX . $this->getNativeName(
return self::PREFIX . $this->getNativeFunctionName(
substr($fullName, $separator + 1),
substr($fullName, 0, $separator),
);

Loading…
Cancel
Save