Skip to content

Commit 11213fd

Browse files
fix: returns a zend_array directly in types.go (#1894)
1 parent 41da660 commit 11213fd

8 files changed

Lines changed: 109 additions & 70 deletions

File tree

docs/extensions.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ import (
132132
)
133133

134134
// export_php:function process_data_ordered(array $input): array
135-
func process_data_ordered_map(arr *C.zval) unsafe.Pointer {
135+
func process_data_ordered_map(arr *C.zend_array) unsafe.Pointer {
136136
// Convert PHP associative array to Go while keeping the order
137137
associativeArray, err := frankenphp.GoAssociativeArray[any](unsafe.Pointer(arr))
138138
if err != nil {
@@ -157,7 +157,7 @@ func process_data_ordered_map(arr *C.zval) unsafe.Pointer {
157157
}
158158

159159
// export_php:function process_data_unordered(array $input): array
160-
func process_data_unordered_map(arr *C.zval) unsafe.Pointer {
160+
func process_data_unordered_map(arr *C.zend_array) unsafe.Pointer {
161161
// Convert PHP associative array to a Go map without keeping the order
162162
// ignoring the order will be more performant
163163
goMap, err := frankenphp.GoMap[any](unsafe.Pointer(arr))
@@ -178,7 +178,7 @@ func process_data_unordered_map(arr *C.zval) unsafe.Pointer {
178178
}
179179

180180
// export_php:function process_data_packed(array $input): array
181-
func process_data_packed(arr *C.zval) unsafe.Pointer {
181+
func process_data_packed(arr *C.zend_array) unsafe.Pointer {
182182
// Convert PHP packed array to Go
183183
goSlice, err := frankenphp.GoPackedArray(unsafe.Pointer(arr))
184184
if err != nil {

internal/extgen/templates/extension.c.tpl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,16 @@ PHP_METHOD({{namespacedClassName $.Namespace .ClassName}}, {{.PhpName}}) {
119119
}
120120
RETURN_EMPTY_STRING();
121121
{{- else if eq .ReturnType "int"}}
122-
zend_long result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else}}(long){{.Name}}{{end}}{{end}}{{end}}{{end}});
122+
zend_long result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else}}(long){{.Name}}{{end}}{{end}}{{end}}{{end}});
123123
RETURN_LONG(result);
124124
{{- else if eq .ReturnType "float"}}
125-
double result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else}}(double){{.Name}}{{end}}{{end}}{{end}}{{end}});
125+
double result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else}}(double){{.Name}}{{end}}{{end}}{{end}}{{end}});
126126
RETURN_DOUBLE(result);
127127
{{- else if eq .ReturnType "bool"}}
128-
int result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else}}(int){{.Name}}{{end}}{{end}}{{end}}{{end}});
128+
int result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else}}(int){{.Name}}{{end}}{{end}}{{end}}{{end}});
129129
RETURN_BOOL(result);
130130
{{- else if eq .ReturnType "array"}}
131-
void* result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{end}}{{else}}{{.Name}}{{end}}{{end}}{{end}});
131+
void* result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else}}{{.Name}}{{end}}{{end}}{{end}}{{end}});
132132
if (result != NULL) {
133133
HashTable *ht = (HashTable*)result;
134134
RETURN_ARR(ht);
@@ -137,7 +137,7 @@ PHP_METHOD({{namespacedClassName $.Namespace .ClassName}}, {{.PhpName}}) {
137137
}
138138
{{- end}}
139139
{{- else}}
140-
{{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{end}}{{else}}{{if eq .PhpType "string"}}{{.Name}}{{else if eq .PhpType "int"}}(long){{.Name}}{{else if eq .PhpType "float"}}(double){{.Name}}{{else if eq .PhpType "bool"}}(int){{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{end}}{{end}}{{end}}{{end}});
140+
{{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{end}}{{else}}{{if eq .PhpType "string"}}{{.Name}}{{else if eq .PhpType "int"}}(long){{.Name}}{{else if eq .PhpType "float"}}(double){{.Name}}{{else if eq .PhpType "bool"}}(int){{.Name}}{{else if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{end}}{{end}}{{end}}{{end}});
141141
{{- end}}
142142
}
143143
{{end}}{{end}}

internal/extgen/validator.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,9 @@ func (v *Validator) phpTypeToGoType(t phpType, isNullable bool) string {
203203
baseType = "float64"
204204
case phpBool:
205205
baseType = "bool"
206-
case phpArray, phpMixed:
206+
case phpArray:
207+
baseType = "*C.zend_array"
208+
case phpMixed:
207209
baseType = "*C.zval"
208210
default:
209211
baseType = "any"

internal/extgen/validator_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ func TestValidateGoFunctionSignature(t *testing.T) {
669669
Params: []phpParameter{
670670
{Name: "items", PhpType: phpArray},
671671
},
672-
GoFunction: `func arrayFunc(items *C.zval) unsafe.Pointer {
672+
GoFunction: `func arrayFunc(items *C.zend_array) unsafe.Pointer {
673673
return nil
674674
}`,
675675
},
@@ -684,7 +684,7 @@ func TestValidateGoFunctionSignature(t *testing.T) {
684684
{Name: "items", PhpType: phpArray, IsNullable: true},
685685
{Name: "name", PhpType: phpString},
686686
},
687-
GoFunction: `func nullableArrayFunc(items *C.zval, name *C.zend_string) unsafe.Pointer {
687+
GoFunction: `func nullableArrayFunc(items *C.zend_array, name *C.zend_string) unsafe.Pointer {
688688
return nil
689689
}`,
690690
},
@@ -700,7 +700,7 @@ func TestValidateGoFunctionSignature(t *testing.T) {
700700
{Name: "filter", PhpType: phpString},
701701
{Name: "limit", PhpType: phpInt},
702702
},
703-
GoFunction: `func mixedFunc(data *C.zval, filter *C.zend_string, limit int64) unsafe.Pointer {
703+
GoFunction: `func mixedFunc(data *C.zend_array, filter *C.zend_string, limit int64) unsafe.Pointer {
704704
return nil
705705
}`,
706706
},
@@ -737,8 +737,8 @@ func TestPhpTypeToGoType(t *testing.T) {
737737
{"float", true, "*float64"},
738738
{"bool", false, "bool"},
739739
{"bool", true, "*bool"},
740-
{"array", false, "*C.zval"},
741-
{"array", true, "*C.zval"},
740+
{"array", false, "*C.zend_array"},
741+
{"array", true, "*C.zend_array"},
742742
{"unknown", false, "any"},
743743
}
744744

types.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ void __zval_double__(zval *zv, double val) { ZVAL_DOUBLE(zv, val); }
3131

3232
void __zval_string__(zval *zv, zend_string *str) { ZVAL_STR(zv, str); }
3333

34+
void __zval_empty_string__(zval *zv) { ZVAL_EMPTY_STRING(zv); }
35+
3436
void __zval_arr__(zval *zv, zend_array *arr) { ZVAL_ARR(zv, arr); }
3537

3638
zend_array *__zend_new_array__(uint32_t size) { return zend_new_array(size); }

types.go

Lines changed: 69 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
package frankenphp
22

33
/*
4+
#cgo nocallback __zend_new_array__
5+
#cgo nocallback __zval_null__
6+
#cgo nocallback __zval_bool__
7+
#cgo nocallback __zval_long__
8+
#cgo nocallback __zval_double__
9+
#cgo nocallback __zval_string__
10+
#cgo nocallback __zval_arr__
11+
#cgo noescape __zend_new_array__
12+
#cgo noescape __zval_null__
13+
#cgo noescape __zval_bool__
14+
#cgo noescape __zval_long__
15+
#cgo noescape __zval_double__
16+
#cgo noescape __zval_string__
17+
#cgo noescape __zval_arr__
418
#include "types.h"
519
*/
620
import "C"
@@ -13,7 +27,7 @@ import (
1327
)
1428

1529
type toZval interface {
16-
toZval() *C.zval
30+
toZval(*C.zval)
1731
}
1832

1933
// EXPERIMENTAL: GoString copies a zend_string to a Go string.
@@ -50,8 +64,8 @@ type AssociativeArray[T any] struct {
5064
Order []string
5165
}
5266

53-
func (a AssociativeArray[T]) toZval() *C.zval {
54-
return (*C.zval)(PHPAssociativeArray[T](a))
67+
func (a AssociativeArray[T]) toZval(zval *C.zval) {
68+
C.__zval_arr__(zval, (*C.zend_array)(PHPAssociativeArray[T](a)))
5569
}
5670

5771
// EXPERIMENTAL: GoAssociativeArray converts a zend_array to a Go AssociativeArray
@@ -61,7 +75,7 @@ func GoAssociativeArray[T any](arr unsafe.Pointer) (AssociativeArray[T], error)
6175
return AssociativeArray[T]{entries, order}, err
6276
}
6377

64-
// EXPERIMENTAL: GoMap converts a zval having a zend_array value to an unordered Go map
78+
// EXPERIMENTAL: GoMap converts a zend_array to an unordered Go map
6579
func GoMap[T any](arr unsafe.Pointer) (map[string]T, error) {
6680
entries, _, err := goArray[T](arr, false)
6781

@@ -73,27 +87,25 @@ func goArray[T any](arr unsafe.Pointer, ordered bool) (map[string]T, []string, e
7387
return nil, nil, errors.New("received a nil pointer on array conversion")
7488
}
7589

76-
zval := (*C.zval)(arr)
77-
v, err := extractZvalValue(zval, C.IS_ARRAY)
78-
if err != nil {
79-
return nil, nil, fmt.Errorf("received a *zval that wasn't a HashTable on array conversion: %w", err)
80-
}
90+
array := (*C.zend_array)(arr)
8191

82-
hashTable := (*C.HashTable)(v)
92+
if array == nil {
93+
return nil, nil, fmt.Errorf("received a *zval that wasn't a HashTable on array conversion")
94+
}
8395

84-
nNumUsed := hashTable.nNumUsed
96+
nNumUsed := array.nNumUsed
8597
entries := make(map[string]T, nNumUsed)
8698
var order []string
8799
if ordered {
88100
order = make([]string, 0, nNumUsed)
89101
}
90102

91-
if htIsPacked(hashTable) {
92-
// if the HashTable is packed, convert all integer keys to strings
103+
if htIsPacked(array) {
104+
// if the array is packed, convert all integer keys to strings
93105
// this is probably a bug by the dev using this function
94106
// still, we'll (inefficiently) convert to an associative array
95107
for i := C.uint32_t(0); i < nNumUsed; i++ {
96-
v := C.get_ht_packed_data(hashTable, i)
108+
v := C.get_ht_packed_data(array, i)
97109
if v != nil && C.zval_get_type(v) != C.IS_UNDEF {
98110
strIndex := strconv.Itoa(int(i))
99111
e, err := goValue[T](v)
@@ -114,7 +126,7 @@ func goArray[T any](arr unsafe.Pointer, ordered bool) (map[string]T, []string, e
114126
var zeroVal T
115127

116128
for i := C.uint32_t(0); i < nNumUsed; i++ {
117-
bucket := C.get_ht_bucket_data(hashTable, i)
129+
bucket := C.get_ht_bucket_data(array, i)
118130
if bucket == nil || C.zval_get_type(&bucket.val) == C.IS_UNDEF {
119131
continue
120132
}
@@ -150,26 +162,24 @@ func goArray[T any](arr unsafe.Pointer, ordered bool) (map[string]T, []string, e
150162
return entries, order, nil
151163
}
152164

153-
// EXPERIMENTAL: GoPackedArray converts a zval with a zend_array value to a Go slice
165+
// EXPERIMENTAL: GoPackedArray converts a zend_array to a Go slice
154166
func GoPackedArray[T any](arr unsafe.Pointer) ([]T, error) {
155167
if arr == nil {
156168
return nil, errors.New("GoPackedArray received a nil value")
157169
}
158170

159-
zval := (*C.zval)(arr)
160-
v, err := extractZvalValue(zval, C.IS_ARRAY)
161-
if err != nil {
162-
return nil, fmt.Errorf("GoPackedArray received *zval that wasn't a HashTable: %w", err)
163-
}
171+
array := (*C.zend_array)(arr)
164172

165-
hashTable := (*C.HashTable)(v)
173+
if array == nil {
174+
return nil, fmt.Errorf("GoPackedArray received *zval that wasn't a HashTable")
175+
}
166176

167-
nNumUsed := hashTable.nNumUsed
177+
nNumUsed := array.nNumUsed
168178
result := make([]T, 0, nNumUsed)
169179

170-
if htIsPacked(hashTable) {
180+
if htIsPacked(array) {
171181
for i := C.uint32_t(0); i < nNumUsed; i++ {
172-
v := C.get_ht_packed_data(hashTable, i)
182+
v := C.get_ht_packed_data(array, i)
173183
if v != nil && C.zval_get_type(v) != C.IS_UNDEF {
174184
v, err := goValue[T](v)
175185
if err != nil {
@@ -185,7 +195,7 @@ func GoPackedArray[T any](arr unsafe.Pointer) ([]T, error) {
185195

186196
// fallback if ht isn't packed - equivalent to array_values()
187197
for i := C.uint32_t(0); i < nNumUsed; i++ {
188-
bucket := C.get_ht_bucket_data(hashTable, i)
198+
bucket := C.get_ht_bucket_data(array, i)
189199
if bucket != nil && C.zval_get_type(&bucket.val) != C.IS_UNDEF {
190200
v, err := goValue[T](&bucket.val)
191201
if err != nil {
@@ -199,18 +209,18 @@ func GoPackedArray[T any](arr unsafe.Pointer) ([]T, error) {
199209
return result, nil
200210
}
201211

202-
// EXPERIMENTAL: PHPMap converts an unordered Go map to a PHP zend_array
212+
// EXPERIMENTAL: PHPMap converts an unordered Go map to a zend_array
203213
func PHPMap[T any](arr map[string]T) unsafe.Pointer {
204214
return phpArray[T](arr, nil)
205215
}
206216

207-
// EXPERIMENTAL: PHPAssociativeArray converts a Go AssociativeArray to a PHP zval with a zend_array value
217+
// EXPERIMENTAL: PHPAssociativeArray converts a Go AssociativeArray to a zend_array
208218
func PHPAssociativeArray[T any](arr AssociativeArray[T]) unsafe.Pointer {
209219
return phpArray[T](arr.Map, arr.Order)
210220
}
211221

212222
func phpArray[T any](entries map[string]T, order []string) unsafe.Pointer {
213-
var zendArray *C.HashTable
223+
var zendArray *C.zend_array
214224

215225
if len(order) != 0 {
216226
zendArray = createNewArray((uint32)(len(order)))
@@ -227,10 +237,7 @@ func phpArray[T any](entries map[string]T, order []string) unsafe.Pointer {
227237
}
228238
}
229239

230-
var zval C.zval
231-
C.__zval_arr__(&zval, zendArray)
232-
233-
return unsafe.Pointer(&zval)
240+
return unsafe.Pointer(zendArray)
234241
}
235242

236243
// EXPERIMENTAL: PHPPackedArray converts a Go slice to a PHP zval with a zend_array value.
@@ -241,10 +248,7 @@ func PHPPackedArray[T any](slice []T) unsafe.Pointer {
241248
C.zend_hash_next_index_insert(zendArray, zval)
242249
}
243250

244-
var zval C.zval
245-
C.__zval_arr__(&zval, zendArray)
246-
247-
return unsafe.Pointer(&zval)
251+
return unsafe.Pointer(zendArray)
248252
}
249253

250254
// EXPERIMENTAL: GoValue converts a PHP zval to a Go value
@@ -316,11 +320,11 @@ func goValue[T any](zval *C.zval) (res T, err error) {
316320
return resZero, err
317321
}
318322

319-
hashTable := (*C.HashTable)(v)
320-
if hashTable != nil && htIsPacked(hashTable) {
323+
array := (*C.zend_array)(v)
324+
if array != nil && htIsPacked(array) {
321325
typ := reflect.TypeOf(res)
322326
if typ == nil || typ.Kind() == reflect.Interface && typ.NumMethod() == 0 {
323-
r, e := GoPackedArray[any](unsafe.Pointer(zval))
327+
r, e := GoPackedArray[any](unsafe.Pointer(array))
324328
if e != nil {
325329
return resZero, e
326330
}
@@ -333,7 +337,7 @@ func goValue[T any](zval *C.zval) (res T, err error) {
333337
return resZero, fmt.Errorf("cannot convert packed array to non-any Go type %s", typ.String())
334338
}
335339

336-
a, err := GoAssociativeArray[T](unsafe.Pointer(zval))
340+
a, err := GoAssociativeArray[T](unsafe.Pointer(array))
337341
if err != nil {
338342
return resZero, err
339343
}
@@ -367,7 +371,8 @@ func phpValue(value any) *C.zval {
367371
var zval C.zval
368372

369373
if toZvalObj, ok := value.(toZval); ok {
370-
return toZvalObj.toZval()
374+
toZvalObj.toZval(&zval)
375+
return &zval
371376
}
372377

373378
switch v := value.(type) {
@@ -382,12 +387,18 @@ func phpValue(value any) *C.zval {
382387
case float64:
383388
C.__zval_double__(&zval, C.double(v))
384389
case string:
390+
if v == "" {
391+
C.__zval_empty_string__(&zval)
392+
break
393+
}
385394
str := (*C.zend_string)(PHPString(v, false))
386395
C.__zval_string__(&zval, str)
396+
case AssociativeArray[any]:
397+
C.__zval_arr__(&zval, (*C.zend_array)(PHPAssociativeArray[any](v)))
387398
case map[string]any:
388-
return (*C.zval)(PHPAssociativeArray[any](AssociativeArray[any]{Map: v}))
399+
C.__zval_arr__(&zval, (*C.zend_array)(PHPMap[any](v)))
389400
case []any:
390-
return (*C.zval)(PHPPackedArray(v))
401+
C.__zval_arr__(&zval, (*C.zend_array)(PHPPackedArray[any](v)))
391402
default:
392403
panic(fmt.Sprintf("unsupported Go type %T", v))
393404
}
@@ -396,13 +407,13 @@ func phpValue(value any) *C.zval {
396407
}
397408

398409
// createNewArray creates a new zend_array with the specified size.
399-
func createNewArray(size uint32) *C.HashTable {
410+
func createNewArray(size uint32) *C.zend_array {
400411
arr := C.__zend_new_array__(C.uint32_t(size))
401-
return (*C.HashTable)(unsafe.Pointer(arr))
412+
return (*C.zend_array)(unsafe.Pointer(arr))
402413
}
403414

404-
// htIsPacked checks if a HashTable is a list (packed) or hashmap (not packed).
405-
func htIsPacked(ht *C.HashTable) bool {
415+
// htIsPacked checks if a zend_array is a list (packed) or hashmap (not packed).
416+
func htIsPacked(ht *C.zend_array) bool {
406417
flags := *(*C.uint32_t)(unsafe.Pointer(&ht.u[0]))
407418

408419
return (flags & C.HASH_FLAG_PACKED) != 0
@@ -435,3 +446,13 @@ func extractZvalValue(zval *C.zval, expectedType C.uint8_t) (unsafe.Pointer, err
435446

436447
return nil, fmt.Errorf("unsupported zval type %d", expectedType)
437448
}
449+
450+
func zendStringRelease(p unsafe.Pointer) {
451+
zs := (*C.zend_string)(p)
452+
C.zend_string_release(zs)
453+
}
454+
455+
func zendHashDestroy(p unsafe.Pointer) {
456+
ht := (*C.zend_array)(p)
457+
C.zend_hash_destroy(ht)
458+
}

types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ void __zval_bool__(zval *zv, bool val);
1919
void __zval_long__(zval *zv, zend_long val);
2020
void __zval_double__(zval *zv, double val);
2121
void __zval_string__(zval *zv, zend_string *str);
22+
void __zval_empty_string__(zval *zv);
2223
void __zval_arr__(zval *zv, zend_array *arr);
2324
zend_array *__zend_new_array__(uint32_t size);
2425

0 commit comments

Comments
 (0)