Examples

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.