{"id":49072629,"url":"https://github.com/johanjanssens/frankenstate","last_synced_at":"2026-04-20T08:08:00.067Z","repository":{"id":348141486,"uuid":"1196682592","full_name":"johanjanssens/frankenstate","owner":"johanjanssens","description":"Shared state between Go and PHP with Redis protocol support","archived":false,"fork":false,"pushed_at":"2026-03-31T00:02:12.000Z","size":174,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-31T01:41:25.214Z","etag":null,"topics":["arrayaccess","frankenphp","go","in-process","key-value-store","php","redis","resp","shared-memory","state-management"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johanjanssens.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-31T00:01:30.000Z","updated_at":"2026-03-31T00:02:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/johanjanssens/frankenstate","commit_stats":null,"previous_names":["johanjanssens/frankenstate"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/johanjanssens/frankenstate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanjanssens%2Ffrankenstate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanjanssens%2Ffrankenstate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanjanssens%2Ffrankenstate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanjanssens%2Ffrankenstate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johanjanssens","download_url":"https://codeload.github.com/johanjanssens/frankenstate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanjanssens%2Ffrankenstate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32038501,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T00:18:06.643Z","status":"online","status_checked_at":"2026-04-20T02:00:06.527Z","response_time":94,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arrayaccess","frankenphp","go","in-process","key-value-store","php","redis","resp","shared-memory","state-management"],"created_at":"2026-04-20T08:07:59.345Z","updated_at":"2026-04-20T08:08:00.059Z","avatar_url":"https://github.com/johanjanssens.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FrankenState\n\nShared state between Go and PHP — an in-process key-value store with Redis wire protocol support, powered by [FrankenPHP](https://frankenphp.dev).\n\nGo extensions write directly to a shared `map[string]any`. PHP reads and writes via `ArrayAccess`. Both sides see the same data, same process, zero network overhead. Reads that hit the version-gated cache cost zero CGo crossings.\n\n\u003e **Note**: This is a companion repo for my FrankenPHP conference talks. It's meant as inspiration and a reference implementation, not a production framework. Feel free to explore, fork, and adapt the patterns for your own projects. Links to talks and slides will be added here.\n\n### Talks\n\nNo talks yet — but here's the abstract if you want to present this:\n\n\u003e **Shared State Between Go and PHP**\n\u003e\n\u003e What if PHP and Go could share memory — no Redis, no serialization, no network hop? With FrankenState and FrankenPHP, a Go extension writes to a shared map and PHP reads it via `$state['key']`. Same process, same memory. Cached reads cost zero CGo crossings. Scalar writes skip JSON entirely.\n\u003e\n\u003e This talk shows how to build a bidirectional Go ↔ PHP communication channel inside FrankenPHP, why in-process state changes the architecture of PHP applications, and how shared memory eliminates an entire class of infrastructure.\n\nSee [talk.md](talk.md) for the full narrative, demo walkthrough, and architecture breakdown.\n\n![FrankenState Demo](demo.png)\n\n## How It Works\n\n```\nGo Extension                    Shared Store                    PHP Thread\n┌──────────────────┐           ┌──────────────────┐           ┌──────────────────┐\n│ state.Set(k, v)  ├──────────►│ RWMutex + map    │◄──────────┤ $s['key'] = val  │\n│ v = state.Get(k) │◄──────────┤ version tracking │──────────►│ $v = $s['key']   │\n└──────────────────┘  direct   └──────────────────┘  CGo/JSON └──────────────────┘\n     (zero overhead)                                     (cached, version-gated)\n```\n\nFrankenPHP embeds PHP in a Go process — they share the same address space. A Go `map[string]any` protected by `sync.RWMutex` is all you need. The C extension caches the full snapshot on each PHP object and gates refreshes on an atomic version counter.\n\n## Quick Start\n\n### Docker (recommended)\n\n```bash\ndocker build -t frankenstate .\ndocker run -p 8083:8083 frankenstate\n```\n\nOpen `http://localhost:8083` to see the demos.\n\nThe PHP build stage uses [static-php-cli](https://github.com/crazywhalecc/static-php-cli) which can download pre-built libraries from GitHub. Pass a GitHub token to speed up the build:\n\n```bash\nGITHUB_TOKEN=$(gh auth token) docker build \\\n    --secret id=github_token,env=GITHUB_TOKEN \\\n    -t frankenstate .\n```\n\n### Build \u0026 Run\n\n```bash\nmake php        # Build PHP 8.3 (ZTS, embed) via static-php-cli (one-time)\nmake env        # Generate env.yaml with CGO flags from the PHP build\nmake run        # Build the binary + start the server on :8083\n```\n\nThe PHP build is cached in `build/.php/` — subsequent runs skip the build if `libphp.a` exists. To rebuild PHP from scratch:\n\n```bash\nmake php-clean  # Remove cached downloads and build artifacts\nmake php        # Rebuild\nmake env        # Regenerate env.yaml\n```\n\n### GoLand\n\nInstall the [EnvFile](https://plugins.jetbrains.com/plugin/7861-envfile) plugin, then in your Run Configuration enable EnvFile and add `env.yaml` to load the CGO flags automatically.\n\n### Environment Variables\n\n| Variable | Default | Description |\n|---|---|---|\n| `FRANKENSTATE_PORT` | `8083` | HTTP server port |\n| `FRANKENSTATE_REDIS_PORT` | `6380` | RESP server port (Redis wire protocol) |\n| `FRANKENSTATE_DOC_ROOT` | `examples` | PHP document root directory |\n| `FRANKENSTATE_THREADS` | `2` | Number of PHP threads |\n\n## Demos\n\n| Demo | Description |\n|------|-------------|\n| **Dashboard** | Live server metrics pushed from Go — request count, uptime, PID, threads |\n| **Explorer** | CRUD key-value browser with cross-request persistence |\n| **Redis** | Same store accessed over RESP — raw TCP, no phpredis needed |\n\n## Go API\n\nAny Go extension can import the state package:\n\n```go\nimport \"github.com/johanjanssens/frankenstate/state\"\n\nstate.Set(\"model.status\", \"loaded\")\nstate.Set(\"config\", map[string]any{\"debug\": true})\n\nval, ok := state.Get(\"model.status\")\nstate.Merge(map[string]any{\"a\": 1, \"b\": 2})\nstate.Replace(map[string]any{\"fresh\": \"data\"})\nsnap := state.Snapshot()\nver := state.Version()\n```\n\n## PHP API\n\n```php\nuse FrankenPHP\\SharedArray;\n\n$state = new SharedArray();\n\n// ArrayAccess\n$state['key'] = 'value';\n$val = $state['key'];\nisset($state['key']);\nunset($state['key']);\n\n// Countable + IteratorAggregate\ncount($state);\nforeach ($state as $key =\u003e $value) { ... }\n\n// Bulk operations\n$state-\u003emerge(['key1' =\u003e 'val1', 'key2' =\u003e 'val2']);\n$old = $state-\u003ereplace(['fresh' =\u003e 'data']);\n$state-\u003ekeys();\n$state-\u003esnapshot();\n$state-\u003eversion();\n```\n\n## Project Structure\n\n```\nfrankenstate/\n├── main.go              # HTTP server + FrankenPHP init + request metrics\n├── state/\n│   └── state.go         # Go backend — RWMutex + map + version tracking\n├── resp/\n│   └── server.go        # Redis wire protocol (RESP) server\n├── phpext/\n│   ├── phpext.c         # Zend extension — module lifecycle\n│   ├── phpext.h         # Module declarations\n│   ├── phpext.go        # CGo exports (registered via init())\n│   ├── phpext_cgo.h     # CGo header binding\n│   ├── state.c          # FrankenPHP\\SharedArray class\n│   └── state.h          # Class declarations + arginfo\n├── examples/            # PHP demo pages\n│   ├── index.php        # Landing page with card grid\n│   ├── dashboard/       # Live Go metrics\n│   ├── explorer/        # CRUD key-value browser\n│   └── redis/           # RESP round-trip demo\n├── build/php/           # PHP build system (static-php-cli)\n├── Dockerfile\n├── Makefile\n└── go.mod\n```\n\n## Requirements\n\n- Go 1.26+\n- [FrankenPHP](https://frankenphp.dev) (built automatically via `make php`)\n- macOS, Linux, or Windows\n\n## Family\n\nPart of the franken\\* family — FrankenPHP extensions written in Go:\n\n- [frankenasync](https://github.com/johanjanssens/frankenasync) — parallel PHP subrequests\n- [frankenwasm](https://github.com/johanjanssens/frankenwasm) — WASM plugins via Extism\n- [frankenonnx](https://github.com/johanjanssens/frankenonnx) — ONNX inference\n- [frankenwails](https://github.com/johanjanssens/frankenwails) — native desktop apps with PHP\n\n## License\n\nCode is MIT — see [LICENSE.md](LICENSE.md). The [talk material](talk.md) is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — free to share and adapt with attribution.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohanjanssens%2Ffrankenstate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohanjanssens%2Ffrankenstate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohanjanssens%2Ffrankenstate/lists"}