Skip to content

Commit 1474ba0

Browse files
committed
add ability to specify startup/shutdown functions
Signed-off-by: Robert Landers <landers.robert@gmail.com>
1 parent 365eae1 commit 1474ba0

6 files changed

Lines changed: 128 additions & 1 deletion

File tree

docs/extensions.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,31 @@ $user->updateInfo(null, 25, null); // Name and active are null
267267

268268
This design ensures that your Go code has complete control over how the object's state is accessed and modified, providing better encapsulation and type safety.
269269

270+
### Module Initialization and Shutdown
271+
272+
The generator supports defining module initialization and shutdown functions using the `//export_php:module` directive.
273+
This allows you to perform setup and cleanup operations when your extension is loaded and unloaded.
274+
275+
```go
276+
//export_php:module init=initializeModule, shutdown=cleanupModule
277+
```
278+
279+
The `init` parameter specifies a function that will be called when the module is initialized, and the `shutdown` parameter specifies a function that will be called when the module is shut down. Both parameters are optional; you can specify either one, both, or none.
280+
281+
The specified functions should be defined in your Go code:
282+
283+
```go
284+
func initializeModule() {
285+
// Perform initialization tasks
286+
// For example, set up global resources, initialize data structures, etc.
287+
}
288+
289+
func cleanupModule() {
290+
// Perform cleanup tasks
291+
// For example, free resources, close connections, etc.
292+
}
293+
```
294+
270295
### Declaring Constants
271296

272297
The generator supports exporting Go constants to PHP using two directives: `//export_php:const` for global constants and `//export_php:classconstant` for class constants. This allows you to share configuration values, status codes, and other constants between Go and PHP code.

internal/extgen/cfile.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type cTemplateData struct {
2323
Classes []phpClass
2424
Constants []phpConstant
2525
Namespace string
26+
Module *phpModule
2627
}
2728

2829
func (cg *cFileGenerator) generate() error {
@@ -68,6 +69,7 @@ func (cg *cFileGenerator) getTemplateContent() (string, error) {
6869
Classes: cg.generator.Classes,
6970
Constants: cg.generator.Constants,
7071
Namespace: cg.generator.Namespace,
72+
Module: cg.generator.Module,
7173
}); err != nil {
7274
return "", err
7375
}

internal/extgen/generator.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type Generator struct {
1515
Classes []phpClass
1616
Constants []phpConstant
1717
Namespace string
18+
Module *phpModule
1819
}
1920

2021
// EXPERIMENTAL
@@ -86,6 +87,12 @@ func (g *Generator) parseSource() error {
8687
}
8788
g.Namespace = ns
8889

90+
module, err := parser.ParseModule(g.SourceFile)
91+
if err != nil {
92+
return fmt.Errorf("parsing module: %w", err)
93+
}
94+
g.Module = module
95+
8996
return nil
9097
}
9198

internal/extgen/moduleParser.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package extgen
2+
3+
import (
4+
"bufio"
5+
"os"
6+
"regexp"
7+
"strings"
8+
)
9+
10+
var phpModuleParser = regexp.MustCompile(`//\s*export_php:module\s*(.*)`)
11+
12+
// phpModule represents a PHP module with optional init and shutdown functions
13+
type phpModule struct {
14+
InitFunc string // Name of the init function
15+
ShutdownFunc string // Name of the shutdown function
16+
}
17+
18+
// ModuleParser parses PHP module directives from Go source files
19+
type ModuleParser struct{}
20+
21+
// parse parses the source file for PHP module directives
22+
func (mp *ModuleParser) parse(filename string) (*phpModule, error) {
23+
file, err := os.Open(filename)
24+
if err != nil {
25+
return nil, err
26+
}
27+
defer file.Close()
28+
29+
scanner := bufio.NewScanner(file)
30+
for scanner.Scan() {
31+
line := strings.TrimSpace(scanner.Text())
32+
if matches := phpModuleParser.FindStringSubmatch(line); matches != nil {
33+
moduleInfo := strings.TrimSpace(matches[1])
34+
return mp.parseModuleInfo(moduleInfo)
35+
}
36+
}
37+
38+
// No module directive found
39+
return nil, nil
40+
}
41+
42+
// parseModuleInfo parses the module info string to extract init and shutdown function names
43+
func (mp *ModuleParser) parseModuleInfo(moduleInfo string) (*phpModule, error) {
44+
module := &phpModule{}
45+
46+
// Split the module info by commas
47+
parts := strings.Split(moduleInfo, ",")
48+
49+
for _, part := range parts {
50+
part = strings.TrimSpace(part)
51+
if part == "" {
52+
continue
53+
}
54+
55+
// Split each part by equals sign
56+
keyValue := strings.SplitN(part, "=", 2)
57+
if len(keyValue) != 2 {
58+
continue
59+
}
60+
61+
key := strings.TrimSpace(keyValue[0])
62+
value := strings.TrimSpace(keyValue[1])
63+
64+
switch key {
65+
case "init":
66+
module.InitFunc = value
67+
case "shutdown":
68+
module.ShutdownFunc = value
69+
}
70+
}
71+
72+
return module, nil
73+
}

internal/extgen/parser.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ func (p *SourceParser) ParseNamespace(filename string) (string, error) {
2525
namespaceParser := NamespaceParser{}
2626
return namespaceParser.parse(filename)
2727
}
28+
29+
// EXPERIMENTAL
30+
func (p *SourceParser) ParseModule(filename string) (*phpModule, error) {
31+
moduleParser := &ModuleParser{}
32+
return moduleParser.parse(filename)
33+
}

internal/extgen/templates/extension.c.tpl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,28 @@ PHP_MINIT_FUNCTION({{.BaseName}}) {
167167
{{- end}}
168168
{{- end}}
169169
{{- end}}
170+
171+
{{if and .Module .Module.InitFunc}}
172+
{{.Module.InitFunc}}_wrapper();
173+
{{end}}
174+
175+
return SUCCESS;
176+
}
177+
178+
{{if .Module}}
179+
{{if .Module.ShutdownFunc}}
180+
PHP_MSHUTDOWN_FUNCTION({{.BaseName}}) {
181+
{{.Module.ShutdownFunc}}_wrapper();
170182
return SUCCESS;
171183
}
184+
{{end}}
185+
{{end}}
172186

173187
zend_module_entry {{.BaseName}}_module_entry = {STANDARD_MODULE_HEADER,
174188
"{{.BaseName}}",
175189
ext_functions, /* Functions */
176190
PHP_MINIT({{.BaseName}}), /* MINIT */
177-
NULL, /* MSHUTDOWN */
191+
{{if and .Module .Module.ShutdownFunc}}PHP_MSHUTDOWN({{.BaseName}}),{{else}}NULL,{{end}} /* MSHUTDOWN */
178192
NULL, /* RINIT */
179193
NULL, /* RSHUTDOWN */
180194
NULL, /* MINFO */

0 commit comments

Comments
 (0)