Skip to content

Commit c96d884

Browse files
committed
Avoid namespaced class symbol clashes in gen_stub
Add the namespace prefix (using underscores) to both the arginfo name and the method declaration name.
1 parent 9c710b1 commit c96d884

File tree

6 files changed

+105
-37
lines changed

6 files changed

+105
-37
lines changed

build/gen_stub.php

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ interface FunctionOrMethodName {
357357
public function getDeclaration(): string;
358358
public function getArgInfoName(): string;
359359
public function __toString(): string;
360+
public function isMagicMethod(): bool;
360361
}
361362

362363
class FunctionName implements FunctionOrMethodName {
@@ -374,19 +375,19 @@ public function getNamespace(): ?string {
374375
return null;
375376
}
376377

377-
public function getShortName(): string {
378-
return $this->name->getLast();
379-
}
380-
381378
public function getNonNamespacedName(): string {
382379
if ($this->name->isQualified()) {
383380
throw new Exception("Namespaced name not supported here");
384381
}
385382
return $this->name->toString();
386383
}
387384

385+
public function getDeclarationName(): string {
386+
return $this->name->getLast();
387+
}
388+
388389
public function getDeclaration(): string {
389-
return "ZEND_FUNCTION({$this->name->getLast()});\n";
390+
return "ZEND_FUNCTION({$this->getDeclarationName()});\n";
390391
}
391392

392393
public function getArgInfoName(): string {
@@ -397,29 +398,41 @@ public function getArgInfoName(): string {
397398
public function __toString(): string {
398399
return $this->name->toString();
399400
}
401+
402+
public function isMagicMethod(): bool {
403+
return false;
404+
}
400405
}
401406

402407
class MethodName implements FunctionOrMethodName {
408+
/** @var Name */
409+
private $className;
403410
/** @var string */
404-
public $className;
405-
/** @var string */
406-
public $name;
411+
public $methodName;
407412

408-
public function __construct(string $className, string $name) {
413+
public function __construct(Name $className, string $methodName) {
409414
$this->className = $className;
410-
$this->name = $name;
415+
$this->methodName = $methodName;
416+
}
417+
418+
public function getDeclarationClassName(): string {
419+
return implode('_', $this->className->parts);
411420
}
412421

413422
public function getDeclaration(): string {
414-
return "ZEND_METHOD($this->className, $this->name);\n";
423+
return "ZEND_METHOD({$this->getDeclarationClassName()}, $this->methodName);\n";
415424
}
416425

417426
public function getArgInfoName(): string {
418-
return "arginfo_class_{$this->className}_{$this->name}";
427+
return "arginfo_class_{$this->getDeclarationClassName()}_{$this->methodName}";
419428
}
420429

421430
public function __toString(): string {
422-
return "$this->className::$this->name";
431+
return "$this->className::$this->methodName";
432+
}
433+
434+
public function isMagicMethod(): bool {
435+
return strpos($this->methodName, '__') === 0;
423436
}
424437
}
425438

@@ -526,58 +539,63 @@ public function getFunctionEntry(): string {
526539
if ($this->alias instanceof MethodName) {
527540
return sprintf(
528541
"\tZEND_MALIAS(%s, %s, %s, %s, %s)\n",
529-
$this->alias->className, $this->name->name, $this->alias->name, $this->getArgInfoName(), $this->getFlagsAsString()
542+
$this->alias->getDeclarationClassName(), $this->name->methodName,
543+
$this->alias->methodName, $this->getArgInfoName(), $this->getFlagsAsString()
530544
);
531545
} else if ($this->alias instanceof FunctionName) {
532546
return sprintf(
533547
"\tZEND_ME_MAPPING(%s, %s, %s, %s)\n",
534-
$this->name->name, $this->alias->getNonNamespacedName(),
548+
$this->name->methodName, $this->alias->getNonNamespacedName(),
535549
$this->getArgInfoName(), $this->getFlagsAsString()
536550
);
537551
} else {
538552
throw new Error("Cannot happen");
539553
}
540554
} else {
555+
$declarationClassName = $this->name->getDeclarationClassName();
541556
if ($this->flags & Class_::MODIFIER_ABSTRACT) {
542557
return sprintf(
543558
"\tZEND_ABSTRACT_ME_WITH_FLAGS(%s, %s, %s, %s)\n",
544-
$this->name->className, $this->name->name, $this->getArgInfoName(), $this->getFlagsAsString()
559+
$declarationClassName, $this->name->methodName, $this->getArgInfoName(),
560+
$this->getFlagsAsString()
545561
);
546562
}
547563

548564
return sprintf(
549565
"\tZEND_ME(%s, %s, %s, %s)\n",
550-
$this->name->className, $this->name->name, $this->getArgInfoName(), $this->getFlagsAsString()
566+
$declarationClassName, $this->name->methodName, $this->getArgInfoName(),
567+
$this->getFlagsAsString()
551568
);
552569
}
553570
} else if ($this->name instanceof FunctionName) {
554571
$namespace = $this->name->getNamespace();
555-
$shortName = $this->name->getShortName();
572+
$declarationName = $this->name->getDeclarationName();
556573

557574
if ($this->alias && $this->isDeprecated) {
558575
return sprintf(
559576
"\tZEND_DEP_FALIAS(%s, %s, %s)\n",
560-
$shortName, $this->alias->getNonNamespacedName(), $this->getArgInfoName()
577+
$declarationName, $this->alias->getNonNamespacedName(), $this->getArgInfoName()
561578
);
562579
}
563580

564581
if ($this->alias) {
565582
return sprintf(
566583
"\tZEND_FALIAS(%s, %s, %s)\n",
567-
$shortName, $this->alias->getNonNamespacedName(), $this->getArgInfoName()
584+
$declarationName, $this->alias->getNonNamespacedName(), $this->getArgInfoName()
568585
);
569586
}
570587

571588
if ($this->isDeprecated) {
572-
return sprintf("\tZEND_DEP_FE(%s, %s)\n", $shortName, $this->getArgInfoName());
589+
return sprintf(
590+
"\tZEND_DEP_FE(%s, %s)\n", $declarationName, $this->getArgInfoName());
573591
}
574592

575593
if ($namespace) {
576594
return sprintf(
577595
"\tZEND_NS_FE(\"%s\", %s, %s)\n",
578-
$namespace, $shortName, $this->getArgInfoName());
596+
$namespace, $declarationName, $this->getArgInfoName());
579597
} else {
580-
return sprintf("\tZEND_FE(%s, %s)\n", $shortName, $this->getArgInfoName());
598+
return sprintf("\tZEND_FE(%s, %s)\n", $declarationName, $this->getArgInfoName());
581599
}
582600
} else {
583601
throw new Error("Cannot happen");
@@ -622,12 +640,12 @@ public function discardInfoForOldPhpVersions(): void {
622640
}
623641

624642
class ClassInfo {
625-
/** @var string */
643+
/** @var Name */
626644
public $name;
627645
/** @var FuncInfo[] */
628646
public $funcInfos;
629647

630-
public function __construct(string $name, array $funcInfos) {
648+
public function __construct(Name $name, array $funcInfos) {
631649
$this->name = $name;
632650
$this->funcInfos = $funcInfos;
633651
}
@@ -741,7 +759,7 @@ function parseFunctionLike(
741759
if (count($aliasParts) === 1) {
742760
$alias = new FunctionName(new Name($aliasParts[0]));
743761
} else {
744-
$alias = new MethodName($aliasParts[0], $aliasParts[1]);
762+
$alias = new MethodName(new Name($aliasParts[0]), $aliasParts[1]);
745763
}
746764
} else if ($tag->name === 'deprecated') {
747765
$isDeprecated = true;
@@ -814,7 +832,7 @@ function parseFunctionLike(
814832
}
815833

816834
$returnType = $func->getReturnType();
817-
if ($returnType === null && !$haveDocReturnType && strpos($name->name, '__') !== 0) {
835+
if ($returnType === null && !$haveDocReturnType && !$name->isMagicMethod()) {
818836
throw new Exception("Missing return type for function $name()");
819837
}
820838

@@ -906,7 +924,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
906924
}
907925

908926
if ($stmt instanceof Stmt\ClassLike) {
909-
$className = $stmt->name->toString();
927+
$className = $stmt->namespacedName;
910928
$methodInfos = [];
911929
foreach ($stmt->stmts as $classStmt) {
912930
$cond = handlePreprocessorConditions($conds, $classStmt);
@@ -1160,10 +1178,14 @@ function (FuncInfo $funcInfo) use($fileInfo, &$generatedFunctionDeclarations) {
11601178
}
11611179

11621180
/** @param FuncInfo[] $funcInfos */
1163-
function generateFunctionEntries(?string $className, array $funcInfos): string {
1181+
function generateFunctionEntries(?Name $className, array $funcInfos): string {
11641182
$code = "";
11651183

1166-
$functionEntryName = $className ? "class_{$className}_methods" : "ext_functions";
1184+
$functionEntryName = "ext_functions";
1185+
if ($className) {
1186+
$underscoreName = implode("_", $className->parts);
1187+
$functionEntryName = "class_{$underscoreName}_methods";
1188+
}
11671189

11681190
$code .= "\n\nstatic const zend_function_entry {$functionEntryName}[] = {\n";
11691191
$code .= generateCodeWithConditions($funcInfos, "", function (FuncInfo $funcInfo) {

ext/ffi/ffi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4428,7 +4428,7 @@ ZEND_METHOD(FFI, isNull) /* {{{ */
44284428
/* }}} */
44294429

44304430

4431-
ZEND_METHOD(CType, getName) /* {{{ */
4431+
ZEND_METHOD(FFI_CType, getName) /* {{{ */
44324432
{
44334433
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
44344434
if (zend_parse_parameters_none() == FAILURE) {
@@ -5004,7 +5004,7 @@ ZEND_MINIT_FUNCTION(ffi)
50045004
zend_ffi_cdata_free_handlers.get_properties = zend_fake_get_properties;
50055005
zend_ffi_cdata_free_handlers.get_gc = zend_fake_get_gc;
50065006

5007-
INIT_NS_CLASS_ENTRY(ce, "FFI", "CType", class_CType_methods);
5007+
INIT_NS_CLASS_ENTRY(ce, "FFI", "CType", class_FFI_CType_methods);
50085008
zend_ffi_ctype_ce = zend_register_internal_class(&ce);
50095009
zend_ffi_ctype_ce->ce_flags |= ZEND_ACC_FINAL;
50105010
zend_ffi_ctype_ce->create_object = zend_ffi_ctype_new;

ext/ffi/ffi_arginfo.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_isNull, 0, 1, _IS_BOOL
7979
ZEND_ARG_OBJ_INFO(ZEND_SEND_PREFER_REF, ptr, FFI\\CData, 0)
8080
ZEND_END_ARG_INFO()
8181

82-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CType_getName, 0, 0, IS_STRING, 0)
82+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_CType_getName, 0, 0, IS_STRING, 0)
8383
ZEND_END_ARG_INFO()
8484

8585

@@ -100,7 +100,7 @@ ZEND_METHOD(FFI, memcmp);
100100
ZEND_METHOD(FFI, memset);
101101
ZEND_METHOD(FFI, string);
102102
ZEND_METHOD(FFI, isNull);
103-
ZEND_METHOD(CType, getName);
103+
ZEND_METHOD(FFI_CType, getName);
104104

105105

106106
static const zend_function_entry class_FFI_methods[] = {
@@ -125,7 +125,7 @@ static const zend_function_entry class_FFI_methods[] = {
125125
};
126126

127127

128-
static const zend_function_entry class_CType_methods[] = {
129-
ZEND_ME(CType, getName, arginfo_class_CType_getName, ZEND_ACC_PUBLIC)
128+
static const zend_function_entry class_FFI_CType_methods[] = {
129+
ZEND_ME(FFI_CType, getName, arginfo_class_FFI_CType_getName, ZEND_ACC_PUBLIC)
130130
ZEND_FE_END
131131
};

ext/zend_test/test.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,14 @@ static ZEND_METHOD(_ZendTestTrait, testMethod) {
313313
RETURN_TRUE;
314314
}
315315

316+
static ZEND_METHOD(ZendTestNS_Foo, method) {
317+
ZEND_PARSE_PARAMETERS_NONE();
318+
}
319+
320+
static ZEND_METHOD(ZendTestNS2_Foo, method) {
321+
ZEND_PARSE_PARAMETERS_NONE();
322+
}
323+
316324
PHP_INI_BEGIN()
317325
STD_PHP_INI_BOOLEAN("zend_test.observer.enabled", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_enabled, zend_zend_test_globals, zend_test_globals)
318326
STD_PHP_INI_BOOLEAN("zend_test.observer.show_output", "1", PHP_INI_SYSTEM, OnUpdateBool, observer_show_output, zend_zend_test_globals, zend_test_globals)

ext/zend_test/test.stub.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
/** @generate-function-entries static */
44

5+
namespace {
6+
57
class _ZendTestClass {
68
public static function is_object(): int {}
79

@@ -43,3 +45,21 @@ function zend_string_or_stdclass($param): stdClass|string {}
4345
function zend_string_or_stdclass_or_null($param): stdClass|string|null {}
4446

4547
function zend_iterable(iterable $arg1, ?iterable $arg2 = null): void {}
48+
49+
}
50+
51+
namespace ZendTestNS {
52+
53+
class Foo {
54+
public function method(): void {}
55+
}
56+
57+
}
58+
59+
namespace ZendTestNS2 {
60+
61+
class Foo {
62+
public function method(): void {}
63+
}
64+
65+
}

ext/zend_test/test_arginfo.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 2d871bb7fda01594bb46f53bca64323424db4709 */
2+
* Stub hash: 759463b1adece643974a9c51455789aef11ba935 */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
55
ZEND_END_ARG_INFO()
@@ -63,6 +63,10 @@ ZEND_END_ARG_INFO()
6363
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestTrait_testMethod, 0, 0, _IS_BOOL, 0)
6464
ZEND_END_ARG_INFO()
6565

66+
#define arginfo_class_ZendTestNS_Foo_method arginfo_zend_test_void_return
67+
68+
#define arginfo_class_ZendTestNS2_Foo_method arginfo_zend_test_void_return
69+
6670

6771
static ZEND_FUNCTION(zend_test_array_return);
6872
static ZEND_FUNCTION(zend_test_nullable_array_return);
@@ -81,6 +85,8 @@ static ZEND_METHOD(_ZendTestClass, is_object);
8185
static ZEND_METHOD(_ZendTestClass, __toString);
8286
static ZEND_METHOD(_ZendTestClass, returnsStatic);
8387
static ZEND_METHOD(_ZendTestTrait, testMethod);
88+
static ZEND_METHOD(ZendTestNS_Foo, method);
89+
static ZEND_METHOD(ZendTestNS2_Foo, method);
8490

8591

8692
static const zend_function_entry ext_functions[] = {
@@ -113,3 +119,15 @@ static const zend_function_entry class__ZendTestTrait_methods[] = {
113119
ZEND_ME(_ZendTestTrait, testMethod, arginfo_class__ZendTestTrait_testMethod, ZEND_ACC_PUBLIC)
114120
ZEND_FE_END
115121
};
122+
123+
124+
static const zend_function_entry class_ZendTestNS_Foo_methods[] = {
125+
ZEND_ME(ZendTestNS_Foo, method, arginfo_class_ZendTestNS_Foo_method, ZEND_ACC_PUBLIC)
126+
ZEND_FE_END
127+
};
128+
129+
130+
static const zend_function_entry class_ZendTestNS2_Foo_methods[] = {
131+
ZEND_ME(ZendTestNS2_Foo, method, arginfo_class_ZendTestNS2_Foo_method, ZEND_ACC_PUBLIC)
132+
ZEND_FE_END
133+
};

0 commit comments

Comments
 (0)