Skip to content

Intendet workflow for developing a php extension #2147

@PKeidel

Description

@PKeidel

Describe your feature request

I would like to have some advise or discussion please, about the workflow when creating a php extension in go

Related docs page: https://frankenphp.dev/docs/extensions/

My problem
Go code gets re-written by the code generator and can not be modified again?

My test scenario

When I have a file "test1.go" with this code

// export_php:namespace PKeidel\Test1
package pkeidel

// #include <Zend/zend_types.h>
import "C"
import (
	"unsafe"

	"github.com/PKeidel/go-php-ext/repeat"
	"github.com/dunglas/frankenphp"
)

// export_php:class StringProcessor
type StringProcessorStruct struct {
	// internal fields
}

// export_php:method StringProcessor::repeat(string $str, int $count, bool $reverse): string
func (sp *StringProcessorStruct) Repeat(s *C.zend_string, count int64, reverse bool) unsafe.Pointer {
	str := frankenphp.GoString(unsafe.Pointer(s))

	result := repeat.Repeat(str, count, reverse)

	return frankenphp.PHPString(result, false)
}

and I then run GEN_STUB_SCRIPT=php-src/build/gen_stub.php frankenphp extension-init test1.go

it will rewrite my test1.go file and create a backup as test1.go.bak

This rewrite/generate removes comments like // export_php:method StringProcessor::repeat(string $str, int $count, bool $reverse): string.

But if i want to edit something, for example add a second function, I would have to run extension-init again. But it does not work, instead it just prints Error: no PHP functions, classes, or constants found in source file.

Although my newly added function looks like this:

// export_php:method StringProcessor::reverse(string $str): string
func (sp *StringProcessorStruct) Reverse(s *C.zend_string) unsafe.Pointer {
	str := frankenphp.GoString(unsafe.Pointer(s))

	result := repeat.Reverse(str)

	return frankenphp.PHPString(result, false)
}

So how is it intented to edit it? I now restore the code from the .bak file after every build, but that feels wrong and way to complicated.
Am I just missing some important part of the process?

Dockerfile

FROM php:8.5 AS phpsrc
RUN docker-php-source extract

FROM dunglas/frankenphp:1-builder-php8.5 AS builder

COPY --from=phpsrc /usr/src/php /usr/src/php
COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy

WORKDIR /ext
COPY entrypoint.sh .

ENTRYPOINT ["/ext/entrypoint.sh"]

entrypoint.sh

#!/usr/bin/env bash

export GEN_STUB_SCRIPT=/usr/src/php/build/gen_stub.php

function print_help {
    echo 'usage: ext [-h | bash | repl | new <stringext> | gen <stringext> | build | test | run <test.php> | make | serve]'
    echo
    echo 'docker build --network=host -t frankenphp-ext-build .'
    echo "alias ext='docker run --rm -v $(pwd):/ext -it --network=host frankenphp-ext-build'"
    echo
}

function gen {
    /usr/local/bin/frankenphp extension-init "$1.go" && \
    cp "$1.go" "$1.gen.go.txt"
}

function build {
    rm ./out/frankenphp
    CGO_ENABLED=1 \
    CGO_CFLAGS="-D_GNU_SOURCE $(php-config --includes)" \
    CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
    XCADDY_GO_BUILD_FLAGS='-ldflags="-w -s"' \
    xcaddy build \
        --output ./out/frankenphp \
        --with github.com/dunglas/frankenphp/caddy \
        --with github.com/dunglas/caddy-cbrotli \
        --with github.com/PKeidel/go-php-ext=.
    ls -lh ./out/frankenphp
}

function make {
    gen "$1"
    build
    mv "$1.go.bak" "$1.go"
    test
}

if [[ "${BASH_SOURCE}" != "${0}" ]]; then
    return
fi

case "$1" in
  ""|-h|--help)
    print_help
    exit 0
    ;;
  bash)
    exec bash
    exit 0
    ;;
  make)
    make
    exit 0
    ;;
  gen)
    gen "$2"
    exit 0
    ;;
  build)
    build
    exit 0
    ;;
esac

exec $@

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions