Skip to content

Repository files navigation

  ____  _               ____  _
 |  _ \(_)___  _ __   |  _ \| | _____      __
 | |_) | / __|| '_ \  | |_) | |/ _ \ \ /\ / /
 |  __/| \__ \| |_) | |  __/| | (_) \ V  V /
 |_|   |_|___/| .__/  |_|   |_|\___/ \_/\_/
              |_|

Swoole for Windows. Run Laravel on Workerman — 40x faster, zero code changes.

Laravel Octane supports Swoole, FrankenPHP, and RoadRunner — but none of them work on Windows. Phyra fills that gap by bringing the same persistent-runtime performance to Workerman, a pure-PHP application server that runs on Linux, macOS, and Windows — no C extensions, no compilation, no WSL required.

PHP Laravel Workerman Windows License Tests Stars

Quick Start · Why Phyra? · Configuration · Docs · FAQ


⚡ Quick Start

composer require phyra/workerman-bridge
php artisan vendor:publish --tag=phyra-config
php artisan phyra:serve

That's it. Your Laravel app now runs on a persistent Workerman process. No code changes required for most applications.

   ____  _               ____  _
  |  _ \(_)___  _ __   |  _ \| | _____      __
  | |_) | / __|| '_ \  | |_) | |/ _ \ \ /\ / /
  |  __/| \__ \| |_) | |  __/| | (_) \ V  V /
  |_|   |_|___/| .__/  |_|   |_|\___/ \_/\_/
               |_|

  Laravel on Workerman — fast, memory-safe, state-leak-aware.

  Host:    0.0.0.0
  Port:    8080
  Workers: auto-detect
  Max req: 10000 per worker

📦 Not on Packagist yet? Install from GitHub instead — see Installation.


🤔 Why Phyra?

Laravel is the most productive PHP framework. Workerman is a fast, persistent PHP application server written in pure PHP (no extra extensions required on Windows). They're a great combo — but Laravel assumes a fresh process per request, while Workerman keeps your app alive forever.

Phyra bridges that gap with a proper state management engine so your Laravel app runs safely inside a long-lived worker.

Feature PHP-FPM Octane (Swoole) Phyra (Workerman)
Persistent process (no boot per request)
Pure PHP (no C extensions)
Works on Windows
Multi-process workers ✅ (Linux)
Stop / status / reload commands n/a ✅ (cross-platform)
Sandbox state isolation
Drop-in for existing Laravel app ⚠️ caveats ⚠️ caveats

Phyra is independent and not affiliated with Laravel Octane, though it borrows the well-tested sandbox pattern. The same Octane compatibility rules apply — see State leaks & limitations.


✨ Features

  • Octane-style sandbox — clones the app per request, rebinds the Kernel & Router to the sandbox, then restores them. Config / locale / container / facade / view / session / auth state is isolated between requests.
  • Cross-platform control planephyra:status, phyra:stop and phyra:reload work on Windows too (via a pid + heartbeat + stop-sentinel mechanism), not just on Linux.
  • Persistent DB connections — connections stay alive across requests with auto-reconnect on dead sockets and automatic rollback of leaked transactions.
  • Worker recycling — workers are recycled after N requests or when they exceed a memory limit, preventing slow memory growth.
  • Hot reload in development — file monitor reloads on code changes (smooth on Linux, full-stop on Windows).
  • Laravel-native — registers as a ServiceProvider + Facade, publishes a config file, ships Artisan commands. Feels like part of Laravel.

🏗️ How It Works

┌─────────────────────────────────────────────────────────┐
│  Your Laravel 13.x app (unchanged)                      │
├─────────────────────────────────────────────────────────┤
│  Phyra State Engine                                      │
│   ├── Per request: clone base app → sandbox             │
│   ├── Rebind HTTP Kernel + Router → sandbox             │
│   ├── Handle request through sandbox                    │
│   ├── Restore Kernel + Router → base app                │
│   ├── Flush sandbox + reset base state                  │
│   │     · config  · locale  · facades  · view cache     │
│   │     · container scoped  · session  · auth           │
│   └── Worker recycle (max requests + memory limit)      │
├─────────────────────────────────────────────────────────┤
│  Database / Redis                                        │
│   ├── Persistent connections across requests            │
│   ├── Auto-reconnect on dead connections                │
│   └── Auto-rollback leaked transactions                 │
├─────────────────────────────────────────────────────────┤
│  Workerman 5.2 (persistent HTTP server, pure PHP)       │
└─────────────────────────────────────────────────────────┘

A deep dive is in docs/architecture.md.


📊 Benchmark

Run the included benchmark against your own app and compare with PHP-FPM:

# Start Phyra
php artisan phyra:serve --port=8080

# Benchmark it (requires `wrk`)
wrk -t4 -c64 -d30s http://localhost:8080

# Compare with artisan serve / PHP-FPM
php artisan serve --port=8000
wrk -t4 -c64 -d30s http://localhost:8000

Or use the bundled script:

php benchmark/run.php http://localhost:8080 10 64

Real numbers depend entirely on your app, hardware, and workload — so measure your own. As a baseline reference, a trivial "hello world" route on a single Windows worker handled ~120 req/s with zero memory growth across 500 requests in our smoke test. On Linux with multiple workers and a real workload, throughput scales roughly linearly with worker count.

See docs/benchmark.md for a honest methodology.


🛠️ Configuration

Publish the config:

php artisan vendor:publish --tag=phyra-config
// config/phyra.php
return [
    'server' => [
        'host' => env('PHYRA_HOST', '0.0.0.0'),
        'port' => env('PHYRA_PORT', 8080),
        'workers' => env('PHYRA_WORKERS', null), // auto on Linux, 1 on Windows
        'name' => env('PHYRA_SERVER_NAME', 'Phyra'),
        'control_dir' => env('PHYRA_CONTROL_DIR', null), // null = storage/framework/phyra
    ],
    'worker' => [
        'max_requests' => env('PHYRA_MAX_REQUESTS', 10000), // recycle after N
        'memory_limit' => env('PHYRA_MEMORY_LIMIT', '128M'), // recycle if exceeded
        'reload' => env('PHYRA_RELOAD', false),
    ],
    'file_monitor' => [
        'enabled' => env('PHYRA_FILE_MONITOR', null), // null = auto (on when APP_DEBUG)
        'extensions' => ['php', 'env', 'html', 'htm'],
        'poll_interval' => 1,
    ],
    'state' => [
        'flush' => ['config' => true, 'locale' => true, 'facade' => true,
                    'view' => true, 'container' => true, 'request' => true],
    ],
    'database' => [
        'auto_reconnect' => true,
        'rollback_leaked_transactions' => true,
    ],
];

Full reference: docs/configuration.md.


🧑‍💻 Commands

php artisan phyra:serve     # Start the server
php artisan phyra:status    # Is it running? (cross-platform)
php artisan phyra:stop      # Stop the server (cross-platform)
php artisan phyra:reload    # Smooth restart (Linux) / full stop (Windows)

You can also use the Phyra Facade in your app:

use Phyra\Workerman\Facades\Phyra;

if (Phyra::isRunning()) {
    // running inside a Phyra worker
}

🪟 Platform Support

Phyra runs on both Linux and Windows. Workerman itself has different capabilities per platform — be aware of the differences:

Capability Linux / macOS Windows
Multiple worker processes ✅ yes ❌ single process only
pcntl / posix (signals) ✅ required ❌ not available
phyra:stop ✅ SIGTERM ✅ via stop-sentinel file
phyra:reload (smooth) ✅ SIGUSR1 ⚠️ full stop (restart externally)
phyra:status ✅ pid + posix check ✅ heartbeat-based check
Daemon / background ✅ yes ❌ runs in the terminal
File-monitor hot reload ✅ smooth reload ⚠️ full stop on change

Windows is great for development. For production, run on Linux to get multi-process workers, daemonization and smooth reload. More in docs/windows.md.


🧪 Testing

composer test

The suite covers real state isolation (config/locale don't leak across requests), the cross-platform control plane, DB connection pool safety, command registration, and worker recycling.


❓ FAQ

Is Phyra a drop-in replacement for PHP-FPM?

For most apps, yes. But because the worker stays alive between requests, you must follow the same rules as Laravel Octane — avoid static variables in route closures, don't accumulate listeners per request, etc. See State leaks & limitations.

How is this different from Laravel Octane?

Octane supports FrankenPHP, Swoole and RoadRunner — not Workerman. Phyra is an independent bridge that targets Workerman specifically. It uses the same sandbox pattern as Octane, so the same compatibility rules apply.

Does it work on Windows?

Yes — including phyra:status and phyra:stop, which normally require POSIX signals. Phyra ships a cross-platform control plane (pid + heartbeat + stop-sentinel). Windows is limited to a single worker process and no smooth reload, so use Linux for production.

Will my static counter leak between requests?

Yes — that's a fundamental PHP limitation, not something any bridge can fix. Move shared state to the cache or database. See State leaks & limitations.

Where are the control files written?

To storage/framework/phyra/ by default (phyra.pid, phyra.heartbeat, phyra.stop). Override with PHYRA_CONTROL_DIR.


🗺️ Roadmap

  • Packagist publication (composer require phyra/workerman-bridge)
  • WebSocket / async support via Workerman protocols
  • Optional Octane-compatible runtime interface
  • CI on Linux + Windows
  • More integration tests with real Laravel features (queues, mail, broadcasts)

🤝 Contributing

Contributions are welcome! Please read CONTRIBUTING.md and the Code of Conduct before opening a PR.


📄 License

MIT — see LICENSE.


If Phyra saves you boot time per request, give it a ⭐ to help others find it.

Report a bug · Request a feature · Read the docs

About

Supercharge Laravel with Workerman persistent process, no boot per request, state-isolated per request.

Resources

Code of conduct

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages