opcua-client · v4.3.x
Docs · Operations

Managing nodes

Add, delete, and re-reference nodes at runtime. The service set is in the client by default — but most servers do not implement it. Catch ServiceUnsupportedException first, succeed second.

The OPC UA NodeManagement service set lets a client create and destroy nodes and references at runtime. The library exposes four methods on the client surface:

Method What it does
addNodes() Create one or more nodes under a parent
deleteNodes() Remove existing nodes
addReferences() Wire arbitrary references between nodes
deleteReferences() Remove references

These are the only OPC UA mutation primitives. There is no MoveNode, no RenameNode — composing add + delete is the path.

Server support

NodeManagement is optional in the OPC UA spec. Many production servers (especially PLC-embedded ones) do not implement it. When that is the case, the very first call to any of the four methods raises:

php capability detection
use PhpOpcua\Client\Exception\ServiceUnsupportedException;

try {
    $client->addNodes([/* … */]);
} catch (ServiceUnsupportedException $e) {
    // Server does not implement NodeManagement (BadServiceUnsupported 0x800B0000).
    // Fall back to whatever pattern your application uses for static address spaces.
}

ServiceUnsupportedException extends ServiceException, so callers that catch the parent class still match. The exception fires on the first unsupported call; subsequent calls behave identically — there is no in-client capability cache. Wrap the first attempt in a guard and remember the answer yourself if you call these methods often. See Recipes · Handling unsupported services.

Info

The library is tested against open62541 v1.4.8 (ci_server) for the NodeManagement integration suite — open62541 enables this service set by default. UA-.NETStandard, which powers most of the uanetstandard-test-suite servers, does not implement it. Plan your reference server accordingly.

addNodes

Creates one or more nodes. Each entry in $nodesToAdd describes a node by its class and parent reference:

php examples/add-variable.php
use PhpOpcua\Client\Types\BuiltinType;
use PhpOpcua\Client\Types\NodeClass;

$results = $client->addNodes([
    [
        'parentNodeId'     => 'i=85',                    // Objects folder
        'referenceTypeId'  => 'i=35',                    // Organizes
        'requestedNewNodeId' => 'ns=1;s=Counter',        // optional — server may assign
        'browseName'       => '1:Counter',
        'nodeClass'        => NodeClass::Variable,
        'attributes' => [
            'displayName' => 'Counter',
            'description' => 'Boot-counter incremented by AddNodes',
            'dataType'    => 'i=6',                      // Int32
            'value'       => 0,
            'valueRank'   => -1,                         // scalar
            'accessLevel' => 3,                          // CurrentRead | CurrentWrite
        ],
        'typeDefinition' => 'i=63',                      // BaseDataVariableType
    ],
]);

foreach ($results as $r) {
    if ($r->statusCode === 0) {
        echo "Created: " . $r->addedNodeId . "\n";
    } else {
        echo "Failed: " . dechex($r->statusCode) . "\n";
    }
}

AddNodesResult:

Field Meaning
statusCode Per-node result. 0 = Good.
addedNodeId The NodeId the server assigned (matches requestedNewNodeId when accepted, otherwise server-chosen).

Supported node classes

All eight OPC UA node classes are supported. Class-specific attributes are encoded automatically as the appropriate ExtensionObject (ObjectAttributes, VariableAttributes, etc.):

NodeClass Class-specific attributes (key fields)
Object eventNotifier
Variable dataType, value, valueRank, arrayDimensions, accessLevel, userAccessLevel, minimumSamplingInterval, historizing
Method executable, userExecutable
ObjectType isAbstract
VariableType dataType, valueRank, value, isAbstract
ReferenceType isAbstract, symmetric, inverseName
DataType isAbstract
View containsNoLoops, eventNotifier

Common attributes (displayName, description, writeMask, userWriteMask) apply to every class. Omitting an attribute lets the server pick its default.

deleteNodes

php delete with reference cleanup
$statuses = $client->deleteNodes([
    ['nodeId' => 'ns=1;s=Counter', 'deleteTargetReferences' => true],
]);
  • deleteTargetReferences: true removes references that point at the deleted node from elsewhere — keeps the address space consistent. false leaves dangling references and is rarely what you want.
  • The return is a parallel int[] of per-node status codes.

addReferences

php link two existing nodes
$client->addReferences([
    [
        'sourceNodeId'     => 'ns=1;s=Counter',
        'referenceTypeId'  => 'i=46',                      // HasProperty
        'targetNodeId'     => 'ns=1;s=Counter.Description',
        'isForward'        => true,
        'targetNodeClass'  => NodeClass::Variable,
    ],
]);

deleteReferences

php remove a reference
$client->deleteReferences([
    [
        'sourceNodeId'      => 'ns=1;s=Counter',
        'referenceTypeId'   => 'i=46',
        'targetNodeId'      => 'ns=1;s=Counter.Description',
        'isForward'         => true,
        'deleteBidirectional' => true,
    ],
]);

deleteBidirectional: true also removes the inverse reference on the target node — usually what you want.

Authorisation and audit

Every call runs in the session's authorisation context. A session authenticated as anonymous on a hardened server will see BadUserAccessDenied per item. The four operations are also commonly audited server-side — expect a paper trail.

Failure modes per item

StatusCode Meaning
BadParentNodeIdInvalid Parent does not exist
BadReferenceTypeIdInvalid Reference type is unknown
BadNodeIdExists requestedNewNodeId is taken
BadBrowseNameInvalid BrowseName is not unique among siblings
BadTypeDefinitionInvalid TypeDefinition is missing or wrong
BadNodeAttributesInvalid Class-specific attributes are malformed
BadUserAccessDenied Session is not authorised