Regeneration overview
generate.php is the regeneration script. It clones UA-Nodeset, runs opcua-cli on every NodeSet2.xml, validates dependencies, and formats. Run it after upstream spec updates; not part of normal application use.
generate.php at the repository root is the regeneration script.
End users of the package do not run it — the generated src/
ships in the Composer install. Run it when:
- The OPC Foundation publishes a new revision of UA-Nodeset
- A bug in the generator is fixed and you need fresh output
- You are forking the package to ship custom companion specs
Prerequisites
The script depends on a sibling clone of
php-opcua/opcua-cli at
../opcua-cli/ (relative to this package). If opcua-cli is
installed somewhere else, edit the $cli path at the top of
generate.php.
workspace/
├── opcua-cli/ # sibling clone
└── opcua-client-nodeset/ # this package
└── generate.php
php-cs-fixer must be installed as a dev dependency of this
package (composer install brings it in). The script invokes it
at the end to format the generated output.
Running
cd opcua-client-nodeset
php generate.php
The script:
-
01
Clones UA-Nodeset if missing.
Default location:
./UA-Nodeset/. Pass a path argument to point at an existing clone:php generate.php /path/to/my/UA-Nodeset -
02
Copies the OPC Foundation LICENSE
from the clone into
LICENSE.OPC-Foundation.Required by the OPC Foundation's license terms — the generated output incorporates content from their files, so the license must travel with it.
-
03
Wipes `src/` and recreates it empty.
Generation is from-scratch every time. No incremental updates.
-
04
Walks every subdirectory of `UA-Nodeset/`.
Skips
\.github,AnsiC,DotNet,OpenApi,XML,Schema— these are not companion specs. Everything else is a candidate. -
05
**Looks for `*NodeSet2.xml` or `*NodeSet.xml`** in each
candidate directory.
Directories without one are skipped silently. Directories with one (or more) trigger generation.
-
06
Invokes `opcua-cli generate:nodeset`
per XML found.
The CLI command writes the PHP output into
src/<DirNameSanitised>/with namespacePhpOpcua\Nodeset\<DirNameSanitised>. The sanitised name strips-and.from the directory name (soIOLink-IODDbecomesIOLinkIODD). -
07
Validates dependency references.
Some specs declare dependencies on other specs whose generation fails or whose directory is skipped. The post-processing pass scans every
<Spec>Registrar.php'sdependencyRegistrars()method and removes references to non-existent registrars. -
08
Runs `php-cs-fixer`
over the generated output.
Applies the package's coding standards. Mostly cosmetic, but needed for the repo to pass its own format check.
Output
A successful run prints a summary:
=== Done ===
Generated: 51 NodeSet(s)
Errors: 0
Skipped: N (no NodeSet2.xml found)
Generated is the count of XML files turned into PHP. Skipped
is candidate directories that had no NodeSet2.xml. Errors is the
count of opcua-cli failures.
A few errors are expected — some specs in UA-Nodeset are
genuinely malformed, drafts, or have generator bugs upstream. Read
the per-spec error output and decide whether to escalate to
opcua-cli or accept the gap.
Verification
After a successful regeneration, verify that nothing visible changed semantically by comparing against the previous version's output:
git diff --stat src/
# Big diff is normal after a real spec update.
# Small diff with no spec update may indicate generator drift —
# investigate before committing.
Then run the package's CI hooks:
composer format:check # php-cs-fixer dry-run
# The package ships only `format`, `format:check`, and `generate`
# scripts — there is no `composer test`. Runtime tests live in
# the runtime packages (opcua-client, opcua-session-manager).
A smoke test against the runtime: load one of the larger registrars and run it through a real OPC UA test server:
use PhpOpcua\Client\ClientBuilder;
use PhpOpcua\Nodeset\Robotics\RoboticsRegistrar;
$client = ClientBuilder::create()
->loadGeneratedTypes(new RoboticsRegistrar())
->connect('opc.tcp://test-server.local:4840');
$dv = $client->read('i=2261');
echo $dv->getValue(); // server product name
$client->disconnect();
If this succeeds, the regenerated package is functional. The
deeper validation (every codec round-trips correctly against a
spec-conformant server) is the responsibility of opcua-cli's
test suite — see
opcua-cli — code generation guide.
Committing the regenerated output
The output is part of the package distribution. Every regeneration is a commit:
git add src/ LICENSE.OPC-Foundation
git commit -m "Regenerate from UA-Nodeset <sha>"
Reference the upstream commit hash from the UA-Nodeset clone so future maintainers can reproduce. The CHANGELOG note should call out the upstream source SHA and any noticeable downstream impact (new specs, dropped specs, renamed registrars).
What the script does not do
- Tag a release. Versioning is manual. After regeneration, bump the package version per Reference · Versioning.
- Update
composer.jsonconstraints. Ifopcua-clioropcua-clientversions need bumping, do so by hand. - Sanity-check spec coverage. A spec dropped upstream
silently disappears from
src/. Detecting this is a diff-review job. - Detect missing PHP imports. The generator's output is
trusted. If a generated DTO references a class with no
usestatement, the package format-check catches it, but the diagnostic comes from PHP's class loader, not fromgenerate.php.
Custom output
generate.php is a script — fork it for custom needs:
- Subset of specs. Replace the
glob(...)loop with an explicit allowlist. - Custom namespace. Change the
$namespace = "PhpOpcua\\Nodeset\\$nsName"line. - Different
opcua-cliflags. Add--namespace-uri-list=,--include-deprecated, etc., per the opcua-cli generate:nodeset reference.
For most users, the shipped generate.php is the right balance —
it regenerates the package as-distributed.
Failure modes
See Troubleshooting for the common failure modes (CLI not found, dependency cleanup leaving orphans, format failures).