Examples
Getting Started
Introduction Overview InstallationUsage
Daemon Managed-client Ipc-protocol Type-serializationReference
Testing ExamplesExamples
Reading a Value
use PhpOpcua\SessionManager\Client\ManagedClient;
$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');
$dv = $client->read('i=2259');
echo "Server state: " . $dv->getValue() . "\n";
echo "Status: " . $dv->statusCode . "\n";
$client->disconnect();Browsing the Address Space
$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');
$refs = $client->browse('i=85');
foreach ($refs as $ref) {
echo "{$ref->displayName} — {$ref->nodeId} (class: {$ref->nodeClass->name})\n";
}
$client->disconnect();Recursive Browse
$tree = $client->browseRecursive('i=85', maxDepth: 3);
foreach ($tree as $node) {
echo "{$node->reference->displayName}\n";
foreach ($node->getChildren() as $child) {
echo " └─ {$child->reference->displayName}\n";
}
}Path Resolution
$nodeId = $client->resolveNodeId('/Objects/Server/ServerStatus/State');
$value = $client->read($nodeId);
echo "State: " . $value->getValue() . "\n";Reading Multiple Values
// Fluent builder
$results = $client->readMulti()
->node('i=2259')->value()
->node('ns=2;i=1001')->displayName()
->node('ns=2;s=Temperature')->value()
->execute();
foreach ($results as $dv) {
echo $dv->getValue() . "\n";
}
// Array style
$results = $client->readMulti([
['nodeId' => 'i=2259'],
['nodeId' => 'ns=2;i=1001', 'attributeId' => 4],
]);Writing Values
use PhpOpcua\Client\Types\BuiltinType;
// Auto-detection (v4) — type inferred automatically
$status = $client->write('ns=2;i=1001', 42);
// Explicit type (still supported)
$status = $client->write('ns=2;i=1001', 42, BuiltinType::Int32);
// Multiple writes (auto-detection and explicit can be mixed)
$statuses = $client->writeMulti([
['nodeId' => 'ns=2;i=1001', 'value' => 42],
['nodeId' => 'ns=2;i=1002', 'value' => 3.14, 'type' => BuiltinType::Double],
['nodeId' => 'ns=2;i=1003', 'value' => 'hello'],
]);Calling a Method
use PhpOpcua\Client\Types\Variant;
$result = $client->call(
'ns=2;i=100', // object
'ns=2;i=200', // method
[
new Variant(BuiltinType::Double, 3.0),
new Variant(BuiltinType::Double, 4.0),
],
);
echo "Status: " . $result->statusCode . "\n";
echo "Result: " . $result->outputArguments[0]->value . "\n";Subscriptions
$sub = $client->createSubscription(publishingInterval: 500.0);
$items = $client->createMonitoredItems($sub->subscriptionId, [
['nodeId' => 'ns=2;i=1001', 'samplingInterval' => 250.0],
['nodeId' => 'ns=2;i=1002'],
]);
for ($i = 0; $i < 10; $i++) {
$response = $client->publish([
['subscriptionId' => $sub->subscriptionId, 'sequenceNumber' => $i],
]);
foreach ($response->notifications as $notif) {
if ($notif['type'] === 'DataChange') {
echo $notif['dataValue']->getValue() . "\n";
}
}
}
$client->deleteSubscription($sub->subscriptionId);Secure Connection
use PhpOpcua\Client\Security\SecurityPolicy;
use PhpOpcua\Client\Security\SecurityMode;
use PhpOpcua\SessionManager\Client\ManagedClient;
$client = new ManagedClient(
socketPath: '/var/run/opcua-session-manager.sock',
authToken: trim(file_get_contents('/etc/opcua/daemon.token')),
);
// RSA security
$client->setSecurityPolicy(SecurityPolicy::Basic256Sha256);
$client->setSecurityMode(SecurityMode::SignAndEncrypt);
$client->setClientCertificate('/certs/client.pem', '/certs/client.key', '/certs/ca.pem');
$client->setUserCredentials('operator', 'secret');
$client->connect('opc.tcp://192.168.1.100:4840');
$value = $client->read('ns=2;i=1001');
echo $value->getValue();ECC Security
use PhpOpcua\Client\Security\SecurityPolicy;
use PhpOpcua\Client\Security\SecurityMode;
use PhpOpcua\SessionManager\Client\ManagedClient;
$client = new ManagedClient(
socketPath: '/var/run/opcua-session-manager.sock',
authToken: trim(file_get_contents('/etc/opcua/daemon.token')),
);
// ECC security — no setClientCertificate needed, auto-generated
$client->setSecurityPolicy(SecurityPolicy::EccNistP256);
$client->setSecurityMode(SecurityMode::SignAndEncrypt);
$client->setUserCredentials('operator', 'secret');
$client->connect('opc.tcp://192.168.1.100:4840');
$value = $client->read('ns=2;i=1001');
echo $value->getValue();Session Persistence Across Requests
// Request 1: open session
$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');
$sessionId = $client->getSessionId();
$_SESSION['opcua_session'] = $sessionId;
// Do NOT disconnect — session stays alive in daemon
// Request 2: reuse session (no handshake, ~5ms)
$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');
$value = $client->read('i=2259');
echo $value->getValue();Daemon Health Monitoring
use PhpOpcua\SessionManager\Client\SocketConnection;
$response = SocketConnection::send('/tmp/opcua-session-manager.sock', [
'command' => 'ping',
]);
echo "Status: " . $response['data']['status'] . "\n";
echo "Active sessions: " . $response['data']['sessions'] . "\n";
$response = SocketConnection::send('/tmp/opcua-session-manager.sock', [
'command' => 'list',
]);
foreach ($response['data']['sessions'] as $session) {
echo "Session {$session['id']}: {$session['endpointUrl']}\n";
}Error Handling
use PhpOpcua\Client\Exception\ConnectionException;
use PhpOpcua\Client\Exception\ServiceException;
use PhpOpcua\SessionManager\Exception\DaemonException;
$client = new ManagedClient();
try {
$client->connect('opc.tcp://localhost:4840');
$value = $client->read('i=2259');
echo $value->getValue();
} catch (DaemonException $e) {
echo "Daemon error: " . $e->getMessage() . "\n";
} catch (ConnectionException $e) {
echo "Connection lost: " . $e->getMessage() . "\n";
} catch (ServiceException $e) {
echo "OPC UA error: " . $e->getMessage() . "\n";
} finally {
try { $client->disconnect(); } catch (\Throwable) {}
}Auto-Publish with PSR-14 Events
Start the daemon with auto-publish enabled. The client's existing PSR-14 events are dispatched automatically for every subscription notification — no manual publish() loop needed.
use PhpOpcua\Client\Event\DataChangeReceived;
use PhpOpcua\Client\Event\EventNotificationReceived;
use PhpOpcua\Client\Event\AlarmActivated;
use PhpOpcua\SessionManager\Daemon\SessionManagerDaemon;
use Psr\EventDispatcher\EventDispatcherInterface;
$dispatcher = /* your PSR-14 event dispatcher */;
$daemon = new SessionManagerDaemon(
socketPath: '/tmp/opcua.sock',
clientEventDispatcher: $dispatcher,
autoPublish: true,
);
$daemon->autoConnect([
'plc-1' => [
'endpoint' => 'opc.tcp://192.168.1.10:4840',
'config' => ['username' => 'operator', 'password' => 'secret'],
'subscriptions' => [
[
'publishing_interval' => 500.0,
'max_keep_alive_count' => 5,
'monitored_items' => [
['node_id' => 'ns=2;s=Temperature', 'client_handle' => 1],
['node_id' => 'ns=2;s=Pressure', 'client_handle' => 2],
['node_id' => 'ns=2;s=MachineState', 'client_handle' => 3],
],
'event_monitored_items' => [
[
'node_id' => 'i=2253',
'client_handle' => 10,
'select_fields' => [
'EventId', 'EventType', 'SourceName', 'Time',
'Message', 'Severity', 'ActiveState',
],
],
],
],
],
],
]);
$daemon->run();Register listeners on your PSR-14 dispatcher to handle notifications:
$dispatcher->listen(DataChangeReceived::class, function (DataChangeReceived $e) {
echo "Subscription {$e->subscriptionId}, handle {$e->clientHandle}: {$e->dataValue->getValue()}\n";
});
$dispatcher->listen(AlarmActivated::class, function (AlarmActivated $e) {
echo "ALARM from {$e->sourceName}: {$e->message} (severity: {$e->severity})\n";
});Auto-Publish with Runtime Subscriptions
Auto-publish also works for subscriptions created at runtime via ManagedClient. Any session that creates a subscription gets auto-published automatically:
use PhpOpcua\SessionManager\Client\ManagedClient;
$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');
$sub = $client->createSubscription(publishingInterval: 500.0);
$client->createMonitoredItems($sub->subscriptionId, [
['nodeId' => 'ns=2;s=Temperature', 'clientHandle' => 1],
]);
// No need to call publish() — the daemon handles it automatically.
// DataChangeReceived events are dispatched to the PSR-14 dispatcher.