mirror of
https://github.com/dunglas/frankenphp.git
synced 2025-12-24 13:38:11 +08:00
Compare commits
3 Commits
v1.11.0
...
perf/types
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f80034ee4f | ||
|
|
4092ecb5b5 | ||
|
|
75ccccf1b2 |
@@ -1472,3 +1472,31 @@ func TestDd(t *testing.T) {
|
||||
"dump123",
|
||||
)
|
||||
}
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
tester := caddytest.NewTester(t)
|
||||
tester.InitServer(`
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
}
|
||||
|
||||
http://localhost:`+testPort+` {
|
||||
log {
|
||||
output stdout
|
||||
format json
|
||||
}
|
||||
|
||||
root ../testdata
|
||||
php_server {
|
||||
worker ../testdata/log-frankenphp_log.php
|
||||
}
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
tester.AssertGetResponse(
|
||||
"http://localhost:"+testPort+"/log-frankenphp_log.php?i=0",
|
||||
http.StatusOK,
|
||||
"",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -55,11 +55,8 @@ func (f *FrankenPHPModule) configureHotReload(app *FrankenPHPApp) error {
|
||||
}
|
||||
|
||||
func (f *FrankenPHPModule) unmarshalHotReload(d *caddyfile.Dispenser) error {
|
||||
patterns := d.RemainingArgs()
|
||||
if len(patterns) > 0 {
|
||||
f.HotReload = &hotReloadConfig{
|
||||
Watch: patterns,
|
||||
}
|
||||
f.HotReload = &hotReloadConfig{
|
||||
Watch: d.RemainingArgs(),
|
||||
}
|
||||
|
||||
for d.NextBlock(1) {
|
||||
@@ -81,10 +78,6 @@ func (f *FrankenPHPModule) unmarshalHotReload(d *caddyfile.Dispenser) error {
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
if f.HotReload == nil {
|
||||
f.HotReload = &hotReloadConfig{}
|
||||
}
|
||||
|
||||
f.HotReload.Watch = append(f.HotReload.Watch, patterns...)
|
||||
|
||||
default:
|
||||
|
||||
@@ -554,10 +554,10 @@ PHP_FUNCTION(frankenphp_log) {
|
||||
zend_long level = 0;
|
||||
zval *context = NULL;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(2, 3)
|
||||
ZEND_PARSE_PARAMETERS_START(1, 3)
|
||||
Z_PARAM_STR(message)
|
||||
Z_PARAM_LONG(level)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_LONG(level)
|
||||
Z_PARAM_ARRAY(context)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
|
||||
@@ -447,6 +447,7 @@ func testLog_frankenphp_log(t *testing.T, opts *testOptions) {
|
||||
|
||||
logs := buf.String()
|
||||
for _, message := range []string{
|
||||
`level=INFO msg="default level message"`,
|
||||
fmt.Sprintf(`level=DEBUG msg="some debug message %d" "key int"=1`, i),
|
||||
fmt.Sprintf(`level=INFO msg="some info message %d" "key string"=string`, i),
|
||||
fmt.Sprintf(`level=WARN msg="some warn message %d"`, i),
|
||||
|
||||
2
testdata/log-frankenphp_log.php
vendored
2
testdata/log-frankenphp_log.php
vendored
@@ -2,6 +2,8 @@
|
||||
|
||||
require_once __DIR__.'/_executor.php';
|
||||
|
||||
frankenphp_log("default level message");
|
||||
|
||||
return function () {
|
||||
frankenphp_log("some debug message {$_GET['i']}", FRANKENPHP_LOG_LEVEL_DEBUG, [
|
||||
"key int" => 1,
|
||||
|
||||
13
types.go
13
types.go
@@ -462,8 +462,12 @@ func extractZvalValue(zval *C.zval, expectedType C.uint8_t) (unsafe.Pointer, err
|
||||
}
|
||||
|
||||
func zendStringRelease(p unsafe.Pointer) {
|
||||
zs := (*C.zend_string)(p)
|
||||
C.zend_string_release(zs)
|
||||
C.zend_string_release((*C.zend_string)(p))
|
||||
}
|
||||
|
||||
// used in tests for cleanup
|
||||
func zendArrayRelease(p unsafe.Pointer) {
|
||||
C.zend_array_release((*C.zend_array)(p))
|
||||
}
|
||||
|
||||
func zendHashDestroy(p unsafe.Pointer) {
|
||||
@@ -471,6 +475,11 @@ func zendHashDestroy(p unsafe.Pointer) {
|
||||
C.zend_hash_destroy(ht)
|
||||
}
|
||||
|
||||
// used in tests for cleanup
|
||||
func efree(p unsafe.Pointer) {
|
||||
C.__efree__(p)
|
||||
}
|
||||
|
||||
// EXPERIMENTAL: CallPHPCallable executes a PHP callable with the given parameters.
|
||||
// Returns the result of the callable as a Go interface{}, or nil if the call failed.
|
||||
func CallPHPCallable(cb unsafe.Pointer, params []interface{}) interface{} {
|
||||
|
||||
128
types_test.go
128
types_test.go
@@ -1,6 +1,8 @@
|
||||
package frankenphp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
@@ -145,3 +147,129 @@ func TestNestedMixedArray(t *testing.T) {
|
||||
assert.Equal(t, originalArray, convertedArray, "nested mixed array should be equal after conversion")
|
||||
})
|
||||
}
|
||||
|
||||
func benchOnPHPThread(b *testing.B, count int, cb func()) {
|
||||
globalLogger = slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
_, err := initPHPThreads(1, 1, nil) // boot 1 thread
|
||||
assert.NoError(b, err)
|
||||
handler := convertToTaskThread(phpThreads[0])
|
||||
|
||||
task := newTask(func() {
|
||||
for i := 0; i < count; i++ {
|
||||
cb()
|
||||
}
|
||||
})
|
||||
handler.execute(task)
|
||||
task.waitForCompletion()
|
||||
|
||||
drainPHPThreads()
|
||||
}
|
||||
|
||||
func BenchmarkBool(b *testing.B) {
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpBool := PHPValue(true)
|
||||
_, _ = GoValue[bool](phpBool)
|
||||
efree(phpBool)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkInt(b *testing.B) {
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpInt := PHPValue(int64(42))
|
||||
_, _ = GoValue[int64](phpInt)
|
||||
efree(phpInt)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkFloat(b *testing.B) {
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpFloat := PHPValue(3.14)
|
||||
_, _ = GoValue[float64](phpFloat)
|
||||
efree(phpFloat)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkString(b *testing.B) {
|
||||
message := "Hello, World!"
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpString := PHPString(message, false)
|
||||
_ = GoString(phpString)
|
||||
zendStringRelease(phpString)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkInternedString(b *testing.B) {
|
||||
message := "Error"
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpString := PHPString(message, false)
|
||||
_ = GoString(phpString)
|
||||
zendStringRelease(phpString)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkEmptyMap(b *testing.B) {
|
||||
originalMap := map[string]any{}
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpArray := PHPMap(originalMap)
|
||||
_, _ = GoMap[any](phpArray)
|
||||
zendArrayRelease(phpArray)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkMap5Entries(b *testing.B) {
|
||||
originalMap := map[string]any{
|
||||
"foo1": "bar1",
|
||||
"foo2": int64(2),
|
||||
"foo3": true,
|
||||
"foo4": 3.14,
|
||||
"foo5": nil,
|
||||
}
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpArray := PHPMap(originalMap)
|
||||
_, _ = GoMap[any](phpArray)
|
||||
zendArrayRelease(phpArray)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkAssociativeArray5Entries(b *testing.B) {
|
||||
originalArray := AssociativeArray[any]{
|
||||
Map: map[string]any{
|
||||
"foo1": "bar1",
|
||||
"foo2": int64(2),
|
||||
"foo3": true,
|
||||
"foo4": 3.14,
|
||||
"foo5": nil,
|
||||
},
|
||||
Order: []string{"foo3", "foo1", "foo4", "foo2", "foo5"},
|
||||
}
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpArray := PHPAssociativeArray(originalArray)
|
||||
_, _ = GoAssociativeArray[any](phpArray)
|
||||
zendArrayRelease(phpArray)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkSlice5Entries(b *testing.B) {
|
||||
originalSlice := []any{"bar1", int64(2), true, 3.14, nil}
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpArray := PHPPackedArray(originalSlice)
|
||||
_, _ = GoPackedArray[any](phpArray)
|
||||
zendArrayRelease(phpArray)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkMap50Entries(b *testing.B) {
|
||||
originalMap := map[string]any{}
|
||||
for i := 0; i < 10; i++ {
|
||||
originalMap[fmt.Sprintf("foo%d", i*5)] = fmt.Sprintf("val%d", i)
|
||||
originalMap[fmt.Sprintf("foo%d", i*5+1)] = "Error" // interned string
|
||||
originalMap[fmt.Sprintf("foo%d", i*5+2)] = true
|
||||
originalMap[fmt.Sprintf("foo%d", i*5+3)] = 3.12
|
||||
originalMap[fmt.Sprintf("foo%d", i*5+4)] = nil
|
||||
}
|
||||
benchOnPHPThread(b, b.N, func() {
|
||||
phpArray := PHPMap(originalMap)
|
||||
_, _ = GoMap[any](phpArray)
|
||||
zendArrayRelease(phpArray)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user