PHP SDK
Use durable-workflow/sdk when a PHP application or remote worker connects to
the standalone Durable Workflow Server or a Durable Workflow Cloud namespace
runtime URL. This first-party SDK is framework-neutral: it provides the
control-plane client, authentication, transport, public payload codec, replay
handler, and managed remote-worker lifecycle without requiring Laravel or the
embedded engine package.
Try the local Sample App playground
For the shortest no-Cloud authoring journey, open the current Sample App
main branch in GitHub Codespaces
and run:
scripts/playground php
The local playground generates caller-owned workflow and activity source, selects the current stable artifacts, and starts the published Server and Waterline. It waits for a worker registration whose identity, workflow type, activity type, and task queue match the generated contract before starting the workflow. Success requires the expected completed result and history; the terminal then prints the exact local Waterline run link and the path to structured JSON evidence.
The package-owned quickstart and API reference below remain the direct path for users who want to add the SDK to an existing project without Sample App.
For step-by-step onboarding, framework paths, testing, deployment, and troubleshooting, use the authored PHP developer portal. For exact constructor signatures, return types, and exception classes, use its distinct generated API reference. The portal's machine-readable contract identifies the package, runtime forms, role credentials, shipped source files, expected result, and published-artifact smoke as one tested path.
Cloud customers use the runtime URL and namespace returned during provisioning, with separate client and worker credentials. See Cloud Managed Runtime for that connection boundary; the examples below show the same SDK against local self-hosted values.
Use durable-workflow/workflow for the separate embedded Laravel path, where
the application owns workflow state in its existing database and executes work
through its Laravel queues. See Deployment Modes
for the complete ownership comparison.
Requirements
- PHP 8.1 or later
- A reachable self-hosted Server or provisioned Cloud namespace runtime
Install
Install the current published PHP SDK. The exact requirement below is generated
from the registry-refreshed published-artifact authority, and Composer records
the resolved package in composer.lock:
composer require durable-workflow/sdk:2.0.0
The SDK uses the official apache/avro Composer package for the public payload
envelope. Its production dependency graph excludes Laravel, Illuminate,
durable-workflow/workflow, and durable-workflow/server.
Start and inspect a workflow
The SDK-owned quickstart creates a clean Composer project, defines one
attributed workflow and activity, starts the worker, starts a unique workflow,
and waits for the result. The same shipped bootstrap.php, worker.php, and
client.php files are installed from the package and executed by the protected
published-artifact smoke, so this page does not maintain a second code listing.
Choose only the runtime connection value:
| Runtime | Value passed to Client | SDK request path behavior |
|---|---|---|
| Self-hosted Server | Bare origin such as http://localhost:8080 | Adds one /api segment; callers do not append /api. |
| Durable Workflow Cloud | Complete provisioned URI such as https://cloud.example/api/runtime/v1/namespaces/<runtime-id> | Preserves the namespace runtime path and appends endpoint /api after it. |
Open the tested PHP path for the exact
commands and visible source. Client operations read
DURABLE_WORKFLOW_CLIENT_TOKEN; worker polling reads
DURABLE_WORKFLOW_WORKER_TOKEN. The guide keeps those credentials in separate
processes without echoing or committing either value.
Worker::register() discovers #[Workflow] and #[Activity] handlers in the
same source file. The guide also documents the direct
registerWorkflow()/registerActivity() alternative for callable-first code.
The bootstrap removes autoloader-path selection from users when those shipped
files run in a standalone project, SDK checkout, installed package, or a
playground/container that places them beside its Composer vendor/ directory.
WorkflowHandle follows the current run after a continue-as-new transition.
Use its selected-run methods when an operation must remain guarded to one
specific run.
Lifecycle, updates, schedules, and visibility
The current public client is broader than selected-run result handling:
WorkflowHandleexposesdescribe,result,signal,query,cancel, andterminate, with selected-run variants for run-specific safety.ClientexposeslistWorkflowswith server filtering and pagination,workflowHistory,updateWorkflow,cancelWorkflow, andterminateWorkflow.- Schedule methods cover create, describe, list, update, pause, resume, trigger, backfill, and delete.
- Operational visibility includes
listNamespaces,listWorkers, andlistTaskQueues, with matching describe methods.
Remote workers register workflow, activity, query, and update handlers through
registerWorkflow, registerActivity, registerQuery, and registerUpdate.
Use the generated PHP SDK API reference
for complete parameters and return types.
Run a remote PHP worker
Workflow handlers are ordinary callables that run as straight-line code inside
a managed Fiber. Call operations such as WorkflowContext::activity()
directly; the SDK suspends the Fiber at durable decisions and returns recorded
results during replay without repeating external activity. Do not declare a
workflow as a Generator or yield WorkflowContext commands: Generator results
are rejected. The managed worker registers its workflow and activity type
names, polls the public worker protocol, heartbeats, completes or fails tasks,
and handles graceful shutdown when pcntl is available.
First-completion selection
Use WorkflowContext::select() to start independent deferred activities,
child workflows, timers, condition waits, or nested ordinary barriers and
resume from the first durably committed winner. The returned SelectionResult
contains stable member keys and identities plus one handle per member:
$selected = $ctx->select([
'resolver' => fn () => $ctx->activity('resolve-request', [$requestId]),
'input' => fn () => $ctx->waitCondition(
fn (): bool => $this->resolution !== null,
key: 'resolution-ready',
),
'deadline' => fn () => $ctx->sleep(2),
]);
if ($selected->key === 'deadline') {
$selected->handles['resolver']->cancel();
}
Selection does not cancel non-winners. Call await() on a handle to consume
its eventual result or cancel() to record explicit cancellation. A cold worker
or completed-history replay consumes the recorded winner even when duplicate or
later input and terminal events appear in another delivery order.
cancel() returns void and does not report its terminal outcome. Only
SelectionOperationCancelled history proves cancellation won; replay advances
past an unmarked cancel request, and if the operation completed first,
await() still returns that result.
Framework service mode and embedded Laravel
The same package ships first-party Laravel service-mode and Symfony service-mode bridges. They retain framework dependency injection, configuration, logging, console workers, and test fakes while connecting to Cloud or Server.
Those bridges are distinct from
embedded Laravel workflows, where
durable-workflow/workflow makes the Laravel application itself own durable
state and execute through Laravel queues. See
Laravel Adoption and Runtime Transition for the
same representative Laravel use case across v1, v2 embedded, and this shipped
service-mode bridge, including drain and rollback. Use
Deployment Modes for the wider runtime
boundary comparison.
Protocol and release boundary
The SDK declares its supported server range, worker protocol version,
control-plane version, and payload codecs in Composer metadata. The server also
publishes its accepted protocol and codec set from GET /api/cluster/info.
Check runtime discovery during deployment instead of inferring compatibility
from a server patch version.
The PHP SDK is versioned independently from the 2.0 Laravel package. Keep the exact published pin in runnable prerelease examples and evaluate release notes when moving between pre-1.0 SDK releases; no cross-release shim is implied.