Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Webman Laravel Package

workerman/webman

Webman is a high-performance PHP framework built on Workerman. It runs as a persistent process, delivering fast HTTP, WebSocket, TCP, and UDP services with low overhead. It offers Laravel-style components and an active ecosystem for building reliable, scalable applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Webman is not a Laravel package — it's a standalone, high-performance PHP framework built on Workerman that borrows heavily from Laravel's idioms. For a Laravel developer the mental model shifts from "boot the framework on every request" to "boot once, serve thousands of requests from resident workers." Most of your Laravel knowledge (routing, controllers, middleware signatures, illuminate/database, Blade) transfers directly; the execution model does not.

Minimal setup:

composer create-project workerman/webman my-api
cd my-api
php start.php start          # foreground, shows logs/echo — use this while developing
# visit http://127.0.0.1:8787

In production you run php start.php start -d (daemonized) behind supervisor/systemd, usually with nginx in front for TLS and static assets.

Where to look first, in this order:

Path Why
config/server.php Listen address, worker count, request limits
route/route.php Explicit route definitions (Laravel routes/web.php equivalent)
config/middleware.php Global and route-group middleware
app/controller/IndexController.php Controller shape and return conventions
config/process.php Custom long-running processes (queues, timers, consumers)
config/exception.php Your Handler::render() — the app/Exceptions/Handler.php analogue

First use case to port: take one JSON API endpoint from a Laravel app — route, controller, Eloquent query, validation — and rebuild it here. It's about 20 minutes of work and it will surface every conceptual difference you need to know.

// route/route.php
Route::get('/users/{id}', [UserController::class, 'show']);
Route::post('/users', [UserController::class, 'store'])->middleware([AuthMiddleware::class]);

// app/controller/UserController.php
public function show(Request $request, int $id)
{
    $user = User::find($id);
    return $user ? json(['code' => 0, 'data' => $user]) : json(['code' => 404], 404);
}

Implementation Patterns

Controllers and the request/response contract. No facades, no superglobals. You receive support\Request and must return a support\Response (or a string, which gets wrapped). request(), json(), view(), redirect(), abort() helpers exist but only make sense inside a request context.

public function store(Request $request)
{
    $data = $request->post();                 // not $_POST
    $page = $request->get('page', 1);         // not $_GET
    $token = $request->header('authorization');
    return json(['ok' => true], 201);
}

Middleware is signature-compatible with Laravel's pipeline, which makes porting trivial:

class AuthMiddleware
{
    public function process(Request $request, callable $handler)
    {
        if (! $request->header('authorization')) {
            return json(['code' => 401], 401);
        }
        return $handler($request);
    }
}

Database: bring your Eloquent habits. webman/database wraps illuminate/database, so Db::table(...), query scopes, relationships, and models extending Illuminate\Database\Eloquent\Model all work. Install webman/console and you get familiar generators:

composer require webman/console
php webman make:model User
php webman make:controller UserController
php webman make:middleware AuthMiddleware

Validation and views via plugins — this is how Webman stays lean. Pull only what you need:

composer require webman/validation     # illuminate/validation rules
composer require webman/blade          # your existing Blade templates
composer require webman/redis          # Redis facade-ish client
composer require webman/jwt-auth       # API auth
composer require webman/rate-limiter   # per-IP throttling
composer require webman/redis-queue    # queued jobs
composer require webman/crontab        # scheduled tasks

Custom processes replace queue workers and schedulers. Anything long-running goes in config/process.php and runs once per worker, independent of HTTP traffic:

return [
    'consumer' => [
        'handler' => app\process\Consumer::class,
        'count'   => 2,
    ],
];

Consumer::onWorkerStart() is where you wire redis-queue consumers, Timer::add() ticks, or Kafka listeners. This is the Webman equivalent of php artisan queue:work + schedule:run, but supervised by the framework itself.

Configuration and environment. All config lives in config/*.php and returns arrays; read it with config('database.default'). Secrets come from .env (via env() / Env::get()). There is no config cache and no .env parsing per request cost — it's loaded once at boot.

Deployment pattern that actually works: nginx → 127.0.0.1:8787, static files served by nginx (config/static.php should be an empty array so Webman doesn't serve them in prod), supervisor running php start.php start, and php start.php reload on deploy. reload is graceful — it finishes in-flight requests before recycling workers, giving you zero-downtime deploys that Laravel's php-fpm reload also gives you but with far less overhead.

Gotchas and Tips

Memory is not reset between requests. This is the single biggest trap. Static properties, singletons, and module-level state persist across every request a worker handles. Never store per-request data on a class property of a singleton; never cache a User object in a static. Treat all objects resolved from the container as process-scoped, not request-scoped.

// WRONG — bleeds the first user into every subsequent request
class UserService { public static $current; }

No exit, die, echo, header(), setcookie(), or ob_*. Any of these will kill or corrupt the worker process. Always return a response object. Output buffering is handled for you.

No $_GET, $_POST, $_SESSION, $_FILES, $_SERVER. They're empty or stale. Use $request->get(), $request->post(), $request->file(), $request->header(), $request->session() (with webman/session installed).

Timers and Timer::add() fire once per worker. If count is 4 and you add a "run every minute" timer in onWorkerStart, your job runs four times a minute. Scheduled/periodic work belongs in a dedicated process with count => 1.

"MySQL server has gone away" will happen on idle resident workers. Connections live for hours. Either set a wait_timeout above your idle period, handle reconnection in your query wrapper, or add a heartbeat query in onWorkerStart + a periodic Db::reconnect().

DB connection math changes. Each worker process opens its own pool. count => 8 workers × 5 connections each = 40 connections to MySQL, not 5. Tune count deliberately: start at CPU cores and measure.

You must reload after code changes. In dev use php start.php start (foreground) plus an auto-reload plugin, or get in the habit of php start.php reload. In daemon mode, code changes are invisible until you reload — a classic "my fix isn't working" false alarm. Adding new classes also needs composer dump-autoload and a reload.

Debugging in daemon mode is blind. var_dump goes to the foreground console, not the browser. Always develop with php start.php start (no -d), and use Log::info() / Log::debug() written to runtime/logs/ for anything you need later. The exception handler should log with stack traces:

public function report(Throwable $e): void { Log::error((string) $e); }

No built-in CSRF protection and no session by default. Laravel's VerifyCsrfToken and encrypted cookies are opt-in via plugins. For stateful browser apps, install webman/session, set config/session.php, and write a CSRF middleware. For APIs, prefer stateless JWT (webman/jwt-auth) and skip sessions entirely.

Migrations aren't first-class. There's no php artisan migrate. Use Phinx, plain SQL, or wire illuminate/database's Schema builder into a custom php webman console command. Teams migrating from Laravel consistently underestimate this — plan for it.

Static analysis of memory leaks: php start.php status shows per-worker memory and request counts. Watch for a steadily climbing memory column — that's a leak. php start.php connections gives you a live connection dump. Restarting workers nightly (reload) is a legitimate band-aid while you hunt the cause.

Extension points worth knowing:

  • config/exception.php → custom error rendering and JSON error envelopes
  • config/bootstrap.php → code that runs once at process start (register observers, bind container entries)
  • support\Container → PSR-11-ish container; constructor injection works in controllers and middleware
  • webman/gateway-worker → WebSockets with a separate gateway/worker split, if you outgrow plain HTTP
  • config/plugin/*/ → plugin configs are auto-merged; override them rather than editing vendor files

Performance tuning checklist: opcache.enable_cli=1 and opcache.validate_timestamps=0 in production (reload after deploy), preload your hot classes in config/bootstrap.php, keep count at ~CPU cores for CPU-bound work and higher for I/O-bound, and avoid composer dump-autoload -o only if you rely on dynamic class names — otherwise it's free speed.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource