Using builders
Fluent builders for read, write, browse, and monitored items. You get them by calling readMulti() / writeMulti() / createMonitoredItems() / translateBrowsePaths() with no arguments. Same surface as opcua-client — through the Laravel facade.
opcua-client exposes fluent builders for the batched operations.
The convention is the same on every batch method: call it with
no arguments to get the builder, call it with an array to run
immediately.
| Builder | Got from | Finaliser | Returns |
|---|---|---|---|
ReadMultiBuilder |
Opcua::readMulti() |
execute() |
DataValue[] |
WriteMultiBuilder |
Opcua::writeMulti() |
execute() |
int[] |
MonitoredItemsBuilder |
Opcua::createMonitoredItems($subId) |
execute() |
MonitoredItemResult[] |
BrowsePathsBuilder |
Opcua::translateBrowsePaths() |
execute() |
BrowsePathResult[] |
There is no readBuilder() / writeBuilder() / browseBuilder()
/ callBuilder() / historyBuilder() on the facade. The one-shot
methods (read, write, browse, call, historyRead*) take
their own positional arguments and don't return a builder.
Read — one-shot vs builder
$dv = Opcua::read('ns=2;s=Speed'); // Value
$dv = Opcua::read('ns=2;s=Speed', AttributeId::DisplayName); // any attribute
Batched read via readMulti():
$values = Opcua::readMulti()
->node('ns=2;s=Speed')
->node('ns=2;s=Temperature')
->node('ns=2;s=Pressure')
->execute();
// $values is array<int, DataValue>, indexed in the order added
execute() always returns an array, even for one entry.
Write — one-shot vs builder
$status = Opcua::write('ns=2;s=Setpoint', 75.0);
// Or with an explicit BuiltinType:
$status = Opcua::write('ns=2;s=Setpoint', 75.0, BuiltinType::Float);
Batched write via writeMulti(). Each item is a node() followed
by either value() (auto-detect) or typed() (explicit
BuiltinType):
use PhpOpcua\Client\Types\BuiltinType;
$statuses = Opcua::writeMulti()
->node('ns=2;s=Setpoint')->value(75.0)
->node('ns=2;s=Mode')->value('Auto')
->node('ns=2;s=EnableAlarm')->typed(true, BuiltinType::Boolean)
->execute();
See Operations · Writing for the type detection rules.
Browse
browse() and browseRecursive() are positional — no fluent
builder. Use the positional BrowseDirection, referenceTypeId,
includeSubtypes, and nodeClasses arguments to filter:
use PhpOpcua\Client\Types\BrowseDirection;
use PhpOpcua\Client\Types\NodeClass;
use PhpOpcua\Client\Types\NodeId;
$results = Opcua::browse(
nodeId: 'ns=2;s=Folder',
direction: BrowseDirection::Forward,
referenceTypeId: NodeId::numeric(0, 35), // Organizes
includeSubtypes: true,
nodeClasses: [NodeClass::Variable],
);
Recursive browse — useful for tag discovery ($maxDepth is the
third positional argument, so use the named form):
$tree = Opcua::browseRecursive('ns=4;s=Tags', maxDepth: 5);
Translate browse paths
$results = Opcua::translateBrowsePaths()
->add(startingNodeId: 'ns=2;s=Folder', browsePath: '/Speed')
->add(startingNodeId: 'ns=2;s=Folder', browsePath: '/Temperature')
->execute();
Subscriptions / monitored items
Subscriptions are created with createSubscription(); monitored
items are attached with createMonitoredItems() (which returns the
MonitoredItemsBuilder when called with no $items array):
$sub = Opcua::createSubscription(publishingInterval: 500.0);
Opcua::createMonitoredItems($sub->subscriptionId)
->add('ns=2;s=Speed', clientHandle: 1)
->add('ns=2;s=Temperature', clientHandle: 2)
->execute();
Listen via Event::listen(DataChangeReceived::class, …) for
notifications. See Operations · Subscriptions
and Events · Data events.
Method calls
call() takes its arguments positionally — no callBuilder():
$result = Opcua::call(
objectId: 'ns=2;s=Recipe',
methodId: 'ns=2;s=Recipe.Load',
inputArguments: ['NewRecipe', 42],
);
// $result->statusCode + $result->outputArguments
See Operations · Method calls.
Chainable with connection()
Builders are rooted in a connection — call them on the result of
Opcua::connection('name'):
$values = Opcua::connection('historian')
->readMulti()
->node('ns=4;s=Tag1')
->node('ns=4;s=Tag2')
->execute();
The chain reads left-to-right: choose connection, open the builder, add items, execute.
Async / queued builders
There's no async builder. PHP OPC UA is synchronous. To run a read off the request thread, dispatch a job:
class SampleBatch implements ShouldQueue
{
public function __construct(public array $nodeIds) {}
public function handle(OpcuaManager $opcua): void
{
$b = $opcua->readMulti();
foreach ($this->nodeIds as $node) {
$b->node($node);
}
$values = $b->execute();
// ... persist
}
}
See Horizon and queues.
When to skip the builder
If the call is one node, one value, one attribute — use the shortcut form. The builder is for batching.
| Operation | Shortcut | Use builder when… |
|---|---|---|
| Read one Value | Opcua::read() |
Batching multiple nodes |
| Write one Value | Opcua::write() |
Batching multiple writes |
| Browse one folder | Opcua::browse() |
No builder — use positional filters |
| Method call | Opcua::call() |
No builder |
| History read | Opcua::historyReadRaw() / etc. |
No builder — three flat methods |
Reference
The builder classes are documented in
opcua-client's reference docs.
The Laravel package adds nothing on top — the chain you call
through Opcua::readMulti() (etc.) is the same one documented
upstream.
Where to read next
You've finished Using the client. Move on to Operations for the per-operation deep dives.