fix: improve generated C extension code (#1698)

This commit is contained in:
Alexandre Daubois
2025-06-30 09:23:21 +02:00
committed by GitHub
parent 291dd4eed9
commit 58fde42654
3 changed files with 19 additions and 45 deletions

View File

@@ -44,11 +44,6 @@ func TestHeaderGenerator_BuildContent(t *testing.T) {
"#define _SIMPLE_H",
"#include <php.h>",
"extern zend_module_entry ext_module_entry;",
"typedef struct go_value go_value;",
"typedef struct go_string {",
"size_t len;",
"char *data;",
"} go_string;",
"#endif",
},
},
@@ -134,11 +129,6 @@ func TestHeaderGenerator_BasicStructure(t *testing.T) {
expectedElements := []string{
"#include <php.h>",
"extern zend_module_entry ext_module_entry;",
"typedef struct go_value go_value;",
"typedef struct go_string {",
"size_t len;",
"char *data;",
"} go_string;",
}
for _, element := range expectedElements {
@@ -209,9 +199,6 @@ func TestHeaderGenerator_ContentValidation(t *testing.T) {
assert.Equal(t, 1, strings.Count(content, "#define"), "Header should have exactly one #define")
assert.Equal(t, 1, strings.Count(content, "#endif"), "Header should have exactly one #endif")
assert.False(t, strings.Contains(content, "{{") || strings.Contains(content, "}}"), "Generated header contains unresolved template syntax")
assert.Contains(t, content, "typedef struct go_string {", "Header should contain go_string typedef")
assert.Contains(t, content, "size_t len;", "Header should contain len field in go_string")
assert.Contains(t, content, "char *data;", "Header should contain data field in go_string")
}
func TestHeaderGenerator_SpecialCharacterHandling(t *testing.T) {
@@ -278,7 +265,6 @@ func TestHeaderGenerator_MinimalContent(t *testing.T) {
"#define _MINIMAL_H",
"#include <php.h>",
"extern zend_module_entry ext_module_entry;",
"typedef struct go_value go_value;",
"#endif",
}
@@ -302,11 +288,6 @@ func testHeaderBasicStructure(t *testing.T, content, baseName string) {
"#define _" + headerGuard,
"#include <php.h>",
"extern zend_module_entry ext_module_entry;",
"typedef struct go_value go_value;",
"typedef struct go_string {",
"size_t len;",
"char *data;",
"} go_string;",
"#endif",
}

View File

@@ -8,12 +8,19 @@
{{- if .Classes}}
#define VALIDATE_GO_HANDLE(intern) \
do { \
if ((intern)->go_handle == 0) { \
zend_throw_error(NULL, "Go object not found in registry"); \
RETURN_THROWS(); \
} \
} while (0)
static zend_object_handlers object_handlers_{{.BaseName}};
typedef struct {
uintptr_t go_handle;
char* class_name;
zend_object std; /* This MUST be the last struct field to memory alignement problems */
zend_object std; /* This must be the last field in the structure: the property store starts at this offset */
} {{.BaseName}}_object;
static inline {{.BaseName}}_object *{{.BaseName}}_object_from_obj(zend_object *obj) {
@@ -28,18 +35,13 @@ static zend_object *{{.BaseName}}_create_object(zend_class_entry *ce) {
intern->std.handlers = &object_handlers_{{.BaseName}};
intern->go_handle = 0; /* will be set in __construct */
intern->class_name = estrdup(ZSTR_VAL(ce->name));
return &intern->std;
}
static void {{.BaseName}}_free_object(zend_object *object) {
{{.BaseName}}_object *intern = {{.BaseName}}_object_from_obj(object);
if (intern->class_name) {
efree(intern->class_name);
}
if (intern->go_handle != 0) {
removeGoObject(intern->go_handle);
}
@@ -47,14 +49,10 @@ static void {{.BaseName}}_free_object(zend_object *object) {
zend_object_std_dtor(&intern->std);
}
static zend_function *{{.BaseName}}_get_method(zend_object **object, zend_string *method, const zval *key) {
return zend_std_get_method(object, method, key);
}
void init_object_handlers() {
memcpy(&object_handlers_{{.BaseName}}, &std_object_handlers, sizeof(zend_object_handlers));
object_handlers_{{.BaseName}}.get_method = {{.BaseName}}_get_method;
object_handlers_{{.BaseName}}.free_obj = {{.BaseName}}_free_object;
object_handlers_{{.BaseName}}.clone_obj = NULL;
object_handlers_{{.BaseName}}.offset = offsetof({{.BaseName}}_object, std);
}
{{- end}}
@@ -67,7 +65,12 @@ PHP_METHOD({{.Name}}, __construct) {
}
{{$.BaseName}}_object *intern = {{$.BaseName}}_object_from_obj(Z_OBJ_P(ZEND_THIS));
/* Constructor is called more than once, make it no-op */
if (intern->go_handle != 0) {
return;
}
intern->go_handle = create_{{.GoStruct}}_object();
}
@@ -75,10 +78,7 @@ PHP_METHOD({{.Name}}, __construct) {
PHP_METHOD({{.ClassName}}, {{.PhpName}}) {
{{$.BaseName}}_object *intern = {{$.BaseName}}_object_from_obj(Z_OBJ_P(ZEND_THIS));
if (intern->go_handle == 0) {
zend_throw_error(NULL, "Go object not found in registry");
RETURN_THROWS();
}
VALIDATE_GO_HANDLE(intern);
{{- if .Params -}}
{{range $i, $param := .Params -}}

View File

@@ -6,13 +6,6 @@
extern zend_module_entry ext_module_entry;
typedef struct go_value go_value;
typedef struct go_string {
size_t len;
char *data;
} go_string;
{{if .Constants}}
/* User defined constants */{{end}}
{{range .Constants}}#define {{.Name}} {{.CValue}}