PHP Classes

File: CONTRIBUTING.md

Recommend this page to a friend!
  Packages of Gianfrancesco Aurecchia   OPC UA Client   CONTRIBUTING.md   Download  
File: CONTRIBUTING.md
Role: Auxiliary data
Content type: text/markdown
Description: Auxiliary data
Class: OPC UA Client
Control devices that support the OPC UA protocol
Author: By
Last change:
Date: 16 days ago
Size: 10,599 bytes
 

Contents

Class file image Download

Contributing to OPC UA PHP Client

Welcome!

Thank you for considering contributing to this project! Every contribution matters, whether it's a bug report, a feature suggestion, a documentation fix, or a code change. This project is open to everyone, you're welcome here.

If you have any questions or need help getting started, don't hesitate to open an issue. We're happy to help.

Development Setup

Requirements

  • PHP >= 8.2
  • `ext-openssl`
  • Composer
  • uanetstandard-test-suite (for integration tests)
  • Docker (optional ? required only to run the NodeManagement integration tests against the bundled open62541 server)

Installation

git clone https://github.com/php-opcua/opcua-client.git
cd opcua-client
composer install

Test Server

Integration tests require the OPC UA test server suite running locally:

git clone https://github.com/php-opcua/uanetstandard-test-suite.git
cd uanetstandard-test-suite
docker compose up -d

NodeManagement Test Server

The six tests/Integration/NodeManagementTest.php tests exercise the AddNodes / DeleteNodes / AddReferences / DeleteReferences service set. UA-.NETStandard (which powers uanetstandard-test-suite) does not implement that set, so a separate open62541 container is used, distributed via php-opcua/extra-test-suite:

git clone https://github.com/php-opcua/extra-test-suite.git
cd extra-test-suite
docker compose up -d

The container has restart: unless-stopped, so ? exactly like uanetstandard-test-suite ? you start it once and it survives reboots. The endpoint opc.tcp://localhost:24840 is hardcoded in TestHelper::ENDPOINT_NODE_MANAGEMENT; there is no env-var indirection. The CI workflow pulls the pre-built image from GHCR on the PHP 8.5 integration leg.

Running Tests

# All tests
./vendor/bin/pest

# Unit tests only
./vendor/bin/pest tests/Unit/

# Integration tests only (requires both uanetstandard-test-suite and extra-test-suite running)
./vendor/bin/pest tests/Integration/ --group=integration

# A specific test file
./vendor/bin/pest tests/Unit/ClientBatchingTest.php

# With coverage report
php -d pcov.enabled=1 ./vendor/bin/pest --coverage

All tests must pass before submitting a pull request.

Project Structure

src/
??? Client.php                  # Thin proxy ? typed one-liners delegating to modules
??? ClientBuilder.php           # Builder / entry point (addModule, replaceModule)
??? OpcUaClientInterface.php    # Public API interface
??? Kernel/                     # Shared infrastructure for all modules
?   ??? ClientKernel.php        # Infrastructure API (send, receive, retry, resolve, etc.)
?   ??? ClientKernelInterface.php
??? Module/                     # Self-contained service modules
?   ??? ServiceModule.php       # Abstract base (register, boot, reset, requires)
?   ??? ModuleRegistry.php      # Lifecycle, dependency sort, conflict detection
?   ??? ReadWrite/              # read, write, call + ReadService, WriteService, CallService, CallResult
?   ??? Browse/                 # browse, getEndpoints + BrowseService, BrowseResultSet
?   ??? Subscription/           # subscriptions, monitoring + protocol services + DTOs
?   ??? History/                # history read + HistoryReadService
?   ??? NodeManagement/         # add/delete nodes + NodeManagementService, AddNodesResult
?   ??? TranslateBrowsePath/    # path resolution + BrowsePathResult
?   ??? ServerInfo/             # server build info + BuildInfo
?   ??? TypeDiscovery/          # auto type discovery
??? Client/                     # Kernel traits (connection, handshake, secure channel, session)
??? Transport/                  # TCP socket communication
??? Protocol/                   # Shared protocol infrastructure (AbstractProtocolService, ServiceTypeId)
??? Encoding/                   # Binary serialization
??? Security/                   # Secure channel, crypto, certificates
??? Cache/                      # PSR-16 cache drivers (InMemoryCache, FileCache)
??? TrustStore/                 # Server certificate trust management
??? Event/                      # PSR-14 events (47 event classes + NullEventDispatcher)
??? Builder/                    # Fluent builders for multi-operations
??? Repository/                 # Per-client codec registry
??? Testing/                    # MockClient for consumer testing
??? Types/                      # Shared OPC UA data types and enums (module-specific DTOs live in Module/)
??? Exception/                  # Exception hierarchy

tests/
??? Unit/                       # Unit tests (no server required)
??? Integration/                # Integration tests (require test server)
    ??? Helpers/TestHelper.php  # Shared test utilities

Design Principles

Zero Runtime Dependencies

This library depends only on ext-openssl and PSR interface packages (psr/log, psr/simple-cache, psr/event-dispatcher). PSR packages contain interfaces only ? no runtime code, no transitive dependencies.

Do not add Composer dependencies that ship runtime code. If a feature requires an external library (Redis driver, HTTP client, etc.), it belongs in a separate package or should accept a PSR interface that the consumer provides. This is a deliberate architectural choice ? see the Won't Do section in the roadmap for examples.

Cross-Platform Compatibility

The library must work on Linux, macOS, and Windows. Do not use platform-specific APIs (Unix sockets, pcntl_* in production code, /proc, etc.). The only allowed extension is ext-openssl, which is available on all platforms.

Public Readonly DTOs

All service response types and value objects use public readonly properties. Do not add getter methods ? access is $result->subscriptionId, not $result->getSubscriptionId(). Old getters are deprecated but kept for backward compatibility.

Instance-Level State

The Client does not use static state. Each client instance has its own codec registry (ExtensionObjectRepository), cache, logger, and configuration. Two clients in the same process must not interfere with each other.

Guidelines

Code Style

The project enforces a Laravel-style coding standard (PSR-12 + opinionated rules) via php-cs-fixer. Configuration lives in .php-cs-fixer.php.

# Format all files
composer format

# Check without modifying (CI mode)
composer format:check

You must run composer format before committing. Pull requests with unformatted code will fail the CI check. Make it a habit: write code, run composer format, then commit.

Key rules:

  • `declare(strict_types=1)` required
  • Single quotes for strings
  • Trailing commas in multiline arrays, arguments, and parameters
  • `not_operator_with_successor_space` (space after `!`)
  • Ordered imports (alphabetical)
  • No unused imports
  • No blank lines after class opening brace
  • Type declarations for parameters, return types, and properties
  • `public readonly` properties for DTOs ? no getters

IDE integration:

  • PhpStorm: Settings > PHP > Quality Tools > PHP CS Fixer ? point to `vendor/bin/php-cs-fixer` and `.php-cs-fixer.php`. Enable "On Save" for automatic formatting.
  • VSCode: Install the `junstyle.php-cs-fixer` extension. It reads `.php-cs-fixer.php` automatically.

Documentation & Comments

  • Every class, trait, interface, and enum must have a PHPDoc description
  • Every public method must have a PHPDoc block with `@param`, `@return`, `@throws`, and `@see` where applicable
  • `@return` and `@param` must be on their own line, not inline with the description
  • Do not add comments inside function bodies. No `//`, no `//`, no section headers. If the code needs a comment to be understood, the method is too complex ? split it into smaller, well-named methods instead. The method name and its PHPDoc should be enough to understand what it does.
  • Update relevant files in `doc/` for new features
  • Update `CHANGELOG.md` with your changes
  • Update `README.md` features list if adding a major feature
  • Update `llms.txt` and `llms-full.txt` if the change affects the public API or architecture

Public API Changes

  • Any new built-in public method must be added to `OpcUaClientInterface` and implemented as a typed one-liner in `Client.php` that delegates to `$this->methodHandlers['name']`
  • New service sets should be implemented as a `ServiceModule` in `src/Module/YourModule/` ? include the module class, protocol service(s), and any module-specific DTOs in the same directory
  • Configuration methods should return `self` for fluent chaining
  • All methods accepting a `NodeId` should also accept `string` (OPC UA format: `'i=2259'`, `'ns=2;s=MyNode'`)
  • Use `AttributeId` constants instead of magic numbers for attribute IDs

Testing

  • Write unit tests for all new functionality
  • Write integration tests for features that interact with an OPC UA server
  • Use Pest PHP syntax (not PHPUnit)
  • Group integration tests with `->group('integration')`
  • Use `TestHelper::safeDisconnect()` in `finally` blocks
  • Use `MockClient` for builder and consumer-facing tests ? do not create anonymous classes implementing `OpcUaClientInterface`
  • Code coverage must remain at or above 99.5%. Pull requests that drop coverage below this threshold will not be merged. Run `php -d pcov.enabled=1 ./vendor/bin/pest --coverage` to check locally before submitting.

Commits

  • Use descriptive commit messages
  • Prefix with `[ADD]`, `[UPD]`, `[PATCH]`, `[REF]`, `[DOC]`, `[TEST]` as appropriate

Pull Request Process

  1. Fork the repository and create a feature branch
  2. Write your code and tests
  3. Run `composer format` to format your code
  4. Ensure all tests pass and coverage is >= 99.5%
  5. Update documentation, changelog, and llms files
  6. Submit a pull request using the provided template
  7. Wait for review ? a maintainer will review your PR, may request changes or ask questions
  8. Once approved, your PR will be merged

Reporting Issues

Use the issue templates to report bugs, request features, or ask questions.