Under Laravel Octane on Swoole, how do you define and use a custom table through the tables config and Octane::table(), and what constraints does it impose?
answer
- 'name:rows' key in tables config
- string:size, int, float columns
- Octane::table('name')->set/get
- created at start, lost on restart
- string default size 1000 bytes
basics
~10 sDeclare the table in config/octane.php's tables array as 'name:rows' with string:size, int or float columns, then use Octane::table('name')->set($key, [...]) and get($key). It is shared by all workers, fixed-size and lost on restart.
solid answer
~40 sIn `config/octane.php`, each entry in `tables` is keyed `'name:rows'` and maps column names to `string:size`, `int` or `float`; the published example is `'example:1000' => ['name' => 'string:1000', 'votes' => 'int']`. When the Swoole server starts, Octane creates each table in shared memory with that row count (1000 if omitted) and string columns sized as given (1000 bytes if omitted), before workers fork, so every worker on that server reads and writes the same rows. `Octane::table('example')` returns the `Swoole\Table`: `set($key, [...])`, `get($key)`, `del($key)` and iteration work. Octane rejects oversized strings with `ValueTooLargeForColumnException`, asking for an undefined table throws, and outside a Swoole server `Octane::table()` throws. Capacity is fixed until restart, and data is per server and lost on restart.
code
php · 13 lines<?php
// config/octane.php (excerpt)
return [
'tables' => [
// 5000 rows; name up to 200 bytes
'presence:5000' => [
'name' => 'string:200',
'last_seen' => 'int',
'score' => 'float',
],
],
];go deeper
Recall that Octane lets you define shared in-memory tables on Swoole in config/octane.php and read them with Octane::table().
Explain the 'name:rows' and 'type:size' syntax, the three column types, default sizes, and the checks Octane adds on access and on write.
Show you size tables for peak, handle restarts and per-server data, and keep table access out of code that runs outside the Swoole server.
Decide which data is worth pinning in per-server shared memory versus a networked store, given capacity limits, volatility and lock-in.
## What a Swoole table gives you A **Swoole table** is a hash table in **shared memory**, allocated when the Swoole server starts and visible to every worker process on that server. **Laravel Octane** exposes it so an app can keep small, structured, hot data - online-user counts, per-server rate counters, a routing table - without a network round trip. Octane's own cache store and its max-execution-time timer are built on the same mechanism. ## Defining a table Tables are declared in the `tables` array of `config/octane.php`: ```php 'tables' => [ 'example:1000' => [ 'name' => 'string:1000', 'votes' => 'int', ], ], ``` - **Key**: `'<name>:<rows>'`. The number after the colon is the row capacity; without it, Octane uses 1000. - **Columns**: `'<column>' => '<type>[:<size>]'` with type `string`, `int` or `float` - the only three Swoole table types. For strings the size is the maximum length in bytes; without a size, Octane uses 1000. The tables are created by the Swoole server bootstrap from the configuration captured when the server started. Adding a table or changing a size therefore needs a **server restart**, not just a reload. ## Using a table ```php use Laravel\Octane\Facades\Octane; Octane::table('example')->set('uuid', [ 'name' => 'Nuno Maduro', 'votes' => 1000, ]); $row = Octane::table('example')->get('uuid'); ``` `Octane::table()` returns the `Swoole\Table` instance, so the usual table operations apply: `set()`, `get()`, `del()`, `exists()`, `count()`, iteration. Keys are strings; each row holds the declared columns. Octane adds two checks of its own: 1. **Server check** - if no Swoole server is bound, it throws an `Exception`: "Tables may only be accessed when using the Swoole server." That includes Artisan commands, queue workers and FrankenPHP or RoadRunner servers. 2. **Name check** - an undeclared name throws "Swoole table [name] has not been configured." And on write, Octane's table subclass validates string lengths: a value longer than its column throws `ValueTooLargeForColumnException`. ## Constraints to design around | Constraint | What it means | |---|---| | fixed row capacity | allocated at start; size it for peak with headroom | | fixed column sizes | long strings are rejected, not truncated | | three column types | no arrays or objects; serialize to a string column yourself if needed | | per server | each server in a fleet has its own table | | volatile | a restart or crash loses all rows | | memory reserved up front | rows x row size is allocated whether used or not | Concurrency is another consideration: individual row operations are handled by Swoole, but a read-modify-write sequence in PHP (`get`, change, `set`) from two workers can interleave, so design updates that tolerate it. ## A sizing example A chat server tracks presence for up to 3,000 concurrent users per server. The table is declared as `'presence:5000'` for headroom, with `name` as `string:200`, `last_seen` as `int` and `score` as `float`. Each row reserves space for all three columns plus the key, for every one of the 5,000 rows, from the moment the server starts. If a user's display name can exceed 200 bytes (multi-byte characters count by bytes), the write throws, so either truncate names before writing or raise the column size and restart. When presence peaks above capacity, new rows cannot be added until old ones are deleted, so a tick that prunes stale rows keeps the table healthy. ## When to use one, and when not Use a table for: - small, fixed-shape records read on nearly every request on that server; - approximate, per-server counters or state that can be rebuilt after a restart. Do not use it for: - data that must be consistent across servers or survive deploys; - large or variable-shaped values; - anything that must also work when the app runs outside Swoole, such as in tests or queue workers - `Octane::table()` throws there. Compared with `Cache::store('octane')`, a custom table gives typed columns and your own capacity, but no expiry and no `interval()` refresh.
- What happens if you call Octane::table() inside a queued job?A queue worker is not a Swoole server process, so `Octane::table()` finds no Swoole server bound and throws "Tables may only be accessed when using the Swoole server." Even on the same machine, the queue worker cannot reach the Octane server's shared memory; move that data to a shared store if jobs need it.
- Why must you restart, not reload, after changing the tables config?The tables are allocated in shared memory from the configuration captured when the Swoole server started, before workers fork. A worker reload re-boots the application but keeps the server's existing tables, so new tables, row counts or column sizes appear only after a full stop and start.
saying these in an interview costs you the question
- Swoole tables grow automatically when they run out of rows
- A string longer than its column is truncated silently
- Table columns can hold arrays or objects directly
- Octane::table() works in queue workers and Artisan commands
- Each worker has its own private copy of the table