laravel-opcua · v4.3.x
Docs · Using the client

Named connections

Switch between configured connections by name with Opcua::connection(). The pattern is identical to Laravel's DB facade — and the same caching rules apply.

The package mirrors Laravel's database facade. You configure multiple connections in config/opcua.php, then switch between them by name at the call site.

The shape

php config/opcua.php
'default' => env('OPCUA_CONNECTION', 'plc-line-a'),

'connections' => [
    'plc-line-a' => [
        'endpoint' => 'opc.tcp://plc-a.factory.local:4840',
        // ...
    ],
    'plc-line-b' => [
        'endpoint' => 'opc.tcp://plc-b.factory.local:4840',
        // ...
    ],
    'historian' => [
        'endpoint' => 'opc.tcp://historian.factory.local:4841',
        // ...
    ],
],

Switching at the call site

php usage
use PhpOpcua\LaravelOpcua\Facades\Opcua;

// Default connection
$dv = Opcua::read('ns=2;s=Speed');

// Named connection
$dv = Opcua::connection('plc-line-b')->read('ns=2;s=Speed');

// Chained reads on a non-default connection
$client = Opcua::connection('historian');
$tags = $client->browseRecursive('ns=4;s=Tags');

Opcua::connection($name) returns the underlying OpcUaClientInterface for that connection — exactly the type direct callers (controllers, jobs) need.

Method resolution

When you call Opcua::read('...') without connection(...), the facade dispatches the method to the default connection. The default is the value of 'default' in config/opcua.php.

These two are equivalent:

php equivalent calls
Opcua::read('ns=2;s=Speed');
Opcua::connection('plc-line-a')->read('ns=2;s=Speed');  // assuming default = 'plc-line-a'

Caching

Each connection resolves to one client instance per request. The first Opcua::connection('plc-line-b') opens the connection and caches it on the OpcuaManager; subsequent calls in the same request return the same client.

Under Octane / FrankenPHP, "per request" becomes "per worker boot" by default. See Connection lifecycle and Octane integration for the details.

Closing one specific connection

php disconnect
Opcua::disconnect('plc-line-b');

Closes the cached client for plc-line-b. The next Opcua::connection('plc-line-b') will open a fresh connection.

Closing all connections

php disconnect all
Opcua::disconnectAll();

Useful in long-running workers to enforce a recycle. Typically not needed in request-per-process FPM.

When the name is dynamic

If the connection name depends on request input (multi-tenant routing), keep the lookup in middleware or a service:

php multi-tenant routing
class OpcuaConnectionResolver
{
    public function forTenant(int $tenantId): string
    {
        return "plc-tenant-{$tenantId}";
    }
}

class TagsController
{
    public function show(Request $request, OpcuaConnectionResolver $r): JsonResponse
    {
        $name = $r->forTenant($request->user()->tenant_id);

        $dv = Opcua::connection($name)->read($request->input('node'));

        return response()->json(['value' => $dv->getValue()]);
    }
}

This is the right shape — keep the routing logic in one place. Don't sprinkle connection("plc-tenant-{$tenantId}") calls throughout the codebase.

When the connection doesn't exist

Opcua::connection('typo') throws InvalidArgumentException immediately — the package validates names against the connections map at resolution time.

This is a boot-time error, not a runtime one — you find typos on the first call, not on the millionth.

Listing configured connections

php list connections
$names = array_keys(config('opcua.connections'));
// ['default', 'plc-line-a', 'plc-line-b', 'historian']

Useful for healthcheck endpoints that probe each connection:

php health endpoint
Route::get('/health/opcua', function () {
    $results = [];
    foreach (array_keys(config('opcua.connections')) as $name) {
        try {
            Opcua::connection($name)->read('i=2256');  // Server_ServerStatus
            $results[$name] = 'ok';
        } catch (\Throwable $e) {
            $results[$name] = 'unhealthy: ' . class_basename($e);
        }
    }
    return response()->json($results);
});

Naming conventions

Recap from Connections:

  • Lowercase, kebab-case.
  • Role-based (plc-line-a) preferred over instance-based (plc-192-168-1-10).
  • Include tenancy in the name (plc-tenant-acme) if relevant.
Documentation