Esc
Directory Structure
ZealPHP projects follow a predictable layout so that the runtime can discover routes, APIs, templates, and task handlers without additional configuration. This guide explains what each top-level directory does, when it is loaded, and how it participates in the server lifecycle.
zealphp/
├── app.php
├── api/
├── public/
├── route/
├── template/
├── task/
├── src/
├── examples/
├── vendor/
├── docs/
└── ...
Entrypoint
app.php– Boots ZealPHP by callingApp::init(), wiring middleware, and invokingApp::run(). It is the only script that should start the OpenSwoole HTTP server. Keep orchestration logic here; do not dispatch routes inline.
HTTP Surface
public/– ZealPHP's document root (the ApacheDocumentRootequivalent): the directory every implicit route and the built-in static handler resolve against. It defaults topublic/— override it withApp::documentRoot('…')beforeApp::init()(see routing.md). Contains PHP scripts and assets served via implicit routing: a request to/foo/barresolves topublic/foo/bar.php(without requiring.phpin the URL). Index files are handled automatically (public/index.php,public/foo/index.php). Use this directory for traditional PHP pages, SPA bootstraps, or static fallbacks.route/– Optional route injection point. All files in this directory are included before implicit routes are registered, allowing teams to register additional explicit routes without editingapp.php. Each file typically calls$app = App::instance();followed by$app->route(...),nsRoute(...), orpatternRoute(...).api/– Implicit API router. Files insideapi/become callable via/api/<path>. Subdirectories map to namespaces:api/device/list.phpis accessible as/api/device/list. Each file returns a closure stored in a variable whose name matches the file base name;ZealAPIbinds that closure into the API context at runtime.template/– Houses reusable view fragments loaded viaApp::render(). The default template root istemplate/home/with_master.php,_head.php, andcontent.php. Keep presentation-only PHP here to support dynamic HTML streaming.
Background Execution
task/– Contains task worker handlers triggered via$server->task(). Long-running, blocking work can also be offloaded to a child process viacoproc()when running in superglobals mode. Each file exposes a closure identified by file name (e.g.,task/backup.phpdefines$backup).examples/– Not loaded automatically, but offers reference scripts for coroutines, prefork processing, and stream wrappers. Use these as templates when experimenting with concurrency features.
Framework Core
-
src/– Framework source code. Important highlights:App.php– The main server class responsible for routing, middleware orchestration, template rendering, and OpenSwoole integration.G.php– Lightweight container that virtualizes PHP superglobals per request.HTTP/– Request and response wrappers that provide durable hooks for ZealPHP features while exposing the underlying OpenSwoole objects when needed.Session/– Session managers that bridge traditional PHP session semantics with OpenSwoole’s coroutine context.utils.php– Helper functions:coproc()(background-process spawner), logging utilities (elog(),zlog(),access_log()), and stack-trace helpers (jTraceEx()).
-
vendor/– Composer-managed dependencies and autoload metadata. Do not edit manually.
Documentation and Meta
docs/– The documentation set you are currently reading. Treat these Markdown files as publishable artifacts.README.md,CHANGELOG.md,TODO.md– Repository-level guidance, release history, and future work items.setup.sh– Bootstrap script that installs OpenSwoole, uopz, and Composer dependencies. Useful for setting up CI or fresh workstations.
What Gets Loaded at Runtime?
app.phpinitializesZealPHP\App.- All files under
route/are included so they can register explicit routes. - Implicit routes are registered for:
/and public directory traversal/api/*endpoints.phppattern guards (403 when direct PHP execution is disabled)
- Middleware and session managers are wired.
- OpenSwoole server starts listening and the request lifecycle begins.
Understanding this flow makes it easy to decide where a new feature belongs:
- Need a new API? Add
api/<module>/<action>.php. - Need to override routing or apply authentication? Drop a file in
route/. - Need a view fragment? Create it under
template/. - Need an async job or background worker? Add a closure in
task/and dispatch via$server->task()orcoproc().