<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gianfrancesco</title>
    <description>The latest articles on DEV Community by Gianfrancesco (@gianfriaur).</description>
    <link>https://dev.to/gianfriaur</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F130513%2Fae0c8e0a-18a0-4e96-aa22-84c12b7cecd5.png</url>
      <title>DEV Community: Gianfrancesco</title>
      <link>https://dev.to/gianfriaur</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gianfriaur"/>
    <language>en</language>
    <item>
      <title>OPC UA in PHP without learning OPC UA - the 4.4.0 ecosystem ships AI Skills</title>
      <dc:creator>Gianfrancesco</dc:creator>
      <pubDate>Thu, 04 Jun 2026 13:21:24 +0000</pubDate>
      <link>https://dev.to/gianfriaur/opc-ua-in-php-without-learning-opc-ua-the-440-ecosystem-ships-ai-skills-35pn</link>
      <guid>https://dev.to/gianfriaur/opc-ua-in-php-without-learning-opc-ua-the-440-ecosystem-ships-ai-skills-35pn</guid>
      <description>&lt;h2&gt;
  
  
  OPC UA in PHP - without learning OPC UA
&lt;/h2&gt;

&lt;p&gt;A while back I shared a &lt;a href="https://github.com/php-opcua" rel="noopener noreferrer"&gt;pure-PHP OPC UA ecosystem&lt;/a&gt; that lets a web app talk to factory-floor PLCs, CNC machines, SCADA systems and IoT sensors &lt;strong&gt;without&lt;/strong&gt; C++ SDKs, gateways, or sidecar proxies. Just Composer and &lt;code&gt;ext-openssl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It just reached &lt;strong&gt;v4.4.0&lt;/strong&gt; - the biggest release so far. There's a lot of new protocol surface (aggregates, history writes, file transfer, three new transports - I'll cover them). But here's the thing I actually want to tell you about:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You no longer need to learn any of it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every package now ships an &lt;strong&gt;AI Skill&lt;/strong&gt;. Point your coding assistant at one repo, describe what you want in plain English, and it writes correct OPC UA code - the right APIs, the right security model, the right patterns - &lt;em&gt;without you knowing how OPC UA works or how the ecosystem is laid out.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let me start there, then show what's under the hood for when you're curious.&lt;/p&gt;




&lt;h2&gt;
  
  
  The point: you don't have to be an OPC UA expert
&lt;/h2&gt;

&lt;p&gt;OPC UA is &lt;em&gt;deep&lt;/em&gt;. The spec runs to a dozen multi-hundred-page Parts. There are NodeIds, secure channels, sessions, subscriptions, monitored items, companion specifications, three transport mappings, a publish/subscribe model with pre-shared group keys... Learning enough to write correct code used to be a real investment.&lt;/p&gt;

&lt;p&gt;And LLMs don't help much on their own here: ask a generic assistant to "read a tag from my PLC over OPC UA in PHP" and it will happily &lt;strong&gt;hallucinate&lt;/strong&gt; method names, miss the security model, and reinvent patterns that don't exist. It has never seen &lt;em&gt;these&lt;/em&gt; libraries.&lt;/p&gt;

&lt;p&gt;That's exactly what an &lt;a href="https://docs.claude.com/en/docs/agents-and-tools/agent-skills" rel="noopener noreferrer"&gt;&lt;strong&gt;Agent Skill&lt;/strong&gt;&lt;/a&gt; fixes. A skill is a &lt;code&gt;SKILL.md&lt;/code&gt; file - frontmatter that tells the model &lt;em&gt;when&lt;/em&gt; it's relevant, plus a body and &lt;code&gt;references/&lt;/code&gt; that tell it &lt;em&gt;how&lt;/em&gt; to use the package correctly: the API surface, the idioms, the security model, the testing approach, the common pitfalls.&lt;/p&gt;

&lt;p&gt;Every package in the ecosystem now ships one under &lt;code&gt;.ai/skills/&amp;lt;package&amp;gt;/&lt;/code&gt;, and they're all mirrored into a single auto-synced repo: &lt;strong&gt;&lt;a href="https://github.com/php-opcua/ai-skills" rel="noopener noreferrer"&gt;php-opcua/ai-skills&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So your assistant can learn the &lt;em&gt;whole&lt;/em&gt; ecosystem from one place - and &lt;strong&gt;you&lt;/strong&gt; can stay at the level of "what do I want to happen."&lt;/p&gt;

&lt;h3&gt;
  
  
  From plain English to correct code
&lt;/h3&gt;

&lt;p&gt;With the skills installed, this is the actual workflow. You write:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Connect to &lt;code&gt;opc.https://plant.local:443/UA/&lt;/code&gt; through our corporate proxy and read the boiler temperature tag."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...and your assistant produces working code that uses the right transport, knows TLS is the secure channel (so OPC UA security stays &lt;code&gt;None&lt;/code&gt;), and routes the proxy through the HTTP client - none of which you had to know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpsTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CurlHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;verifyTls&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;extraCurlOptions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;CURLOPT_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'http://proxy.corp:3128'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BinaryHttpsEncoding&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;endpointUrl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'opc.https://plant.local:443/UA/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setSecurityPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityPolicy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// TLS is the secure channel&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setSecurityMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityMode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.https://plant.local:443/UA/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;s=Boiler/Temperature'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or &lt;em&gt;"subscribe to the PubSub multicast group 239.0.0.1 and print every field"&lt;/em&gt;, or &lt;em&gt;"accept a reverse connection from our edge gateway and browse it"&lt;/em&gt; - same deal. You describe the outcome; the skill supplies the how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install it in one command
&lt;/h3&gt;

&lt;p&gt;If you're on Laravel, &lt;a href="https://github.com/laravel/boost" rel="noopener noreferrer"&gt;Boost&lt;/a&gt; v2 pulls skills straight from a GitHub repo and syncs them across every AI agent it manages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan boost:add-skill php-opcua/ai-skills &lt;span class="nt"&gt;--list&lt;/span&gt;             &lt;span class="c"&gt;# see what's available&lt;/span&gt;
php artisan boost:add-skill php-opcua/ai-skills &lt;span class="nt"&gt;--skill&lt;/span&gt; opcua-client
php artisan boost:add-skill php-opcua/ai-skills &lt;span class="nt"&gt;--all&lt;/span&gt;              &lt;span class="c"&gt;# or grab everything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;strong&gt;Claude Code&lt;/strong&gt;? These &lt;em&gt;are&lt;/em&gt; Anthropic Agent Skills - nothing to convert:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/php-opcua/ai-skills.git
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ai-skills/skills/opcua-client ~/.claude/skills/     &lt;span class="c"&gt;# personal, every project&lt;/span&gt;
&lt;span class="c"&gt;# or .claude/skills/ to commit it with your repo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code auto-activates a skill when your task matches its description. &lt;strong&gt;Cursor, Windsurf, Copilot&lt;/strong&gt; work too - drop the &lt;code&gt;SKILL.md&lt;/code&gt; into their rules/instructions folder.&lt;/p&gt;

&lt;p&gt;Take only the skills for the packages you use - each is self-contained. That's the whole onboarding.&lt;/p&gt;




&lt;h2&gt;
  
  
  ...and if you &lt;em&gt;are&lt;/em&gt; curious, here's what's new in 4.4.0
&lt;/h2&gt;

&lt;p&gt;You don't need this section to be productive. But if you like knowing what your AI is driving, here's the release.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ecosystem, briefly
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-client&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The core - pure-PHP client: read, write, browse, call, subscribe, history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-cli&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Terminal companion - browse/read/write/watch, all with &lt;code&gt;--json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-client-nodeset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pre-generated PHP types for OPC Foundation companion specs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-session-manager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep sessions alive across requests via a ReactPHP daemon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;laravel-opcua&lt;/code&gt; / &lt;code&gt;symfony-opcua&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Framework integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Core: aggregates, history writes, file transfer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AggregateModule&lt;/code&gt;&lt;/strong&gt; computes &lt;code&gt;Interpolate&lt;/code&gt; / &lt;code&gt;Minimum&lt;/code&gt; / &lt;code&gt;Maximum&lt;/code&gt; / &lt;code&gt;Average&lt;/code&gt; / &lt;code&gt;Count&lt;/code&gt; from a raw &lt;code&gt;DataValue&lt;/code&gt; buffer - pair it with &lt;code&gt;historyAggregate()&lt;/code&gt; to fetch + bucket in one call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HistoryUpdate&lt;/strong&gt; - nine new methods for Insert / Replace / Update / Remove of historical data and events. History is no longer read-only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;FileTransferModule&lt;/code&gt;&lt;/strong&gt; wraps the OPC UA File Transfer service set (Part 5) into typed &lt;code&gt;openFile&lt;/code&gt; / &lt;code&gt;readFile&lt;/code&gt; / &lt;code&gt;writeFile&lt;/code&gt; / &lt;code&gt;closeFile&lt;/code&gt; calls, with chunked reads for large files.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;pluggable transport layer&lt;/strong&gt; (&lt;code&gt;ClientTransportInterface&lt;/code&gt; + &lt;code&gt;ClientBuilder::setTransport()&lt;/code&gt;) - the quiet headline that made the three extensions below possible. Plus a small &lt;code&gt;DataValue::getType()&lt;/code&gt; accessor so you can read a value's type without the deprecated &lt;code&gt;getVariant()&lt;/code&gt; hop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Three new transports
&lt;/h3&gt;

&lt;p&gt;OPC UA isn't only &lt;code&gt;opc.tcp://&lt;/code&gt;. v4.4.0 brings three more mappings as &lt;strong&gt;opt-in extensions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;opcua-client-ext-reverse-connect&lt;/code&gt;&lt;/strong&gt; (Part 6 7.1.2.3) - &lt;em&gt;the server dials you&lt;/em&gt;. For edge gateways and PLCs behind NAT/firewall that can't accept inbound connections but can dial out. Your app listens, validates the announced &lt;code&gt;ServerUri&lt;/code&gt; against a fail-secure whitelist, then proceeds with the normal handshake.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;opcua-client-ext-transport-https&lt;/code&gt;&lt;/strong&gt; (Part 6 7.4) - &lt;strong&gt;&lt;code&gt;opc.https://&lt;/code&gt;&lt;/strong&gt;: one HTTPS POST per UA message, TLS as the secure channel. For getting through proxies and firewalls that block &lt;code&gt;opc.tcp://&lt;/code&gt;. Binary encoding is production-ready; JSON ships as a reference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;opcua-client-ext-transport-pubsub&lt;/code&gt;&lt;/strong&gt; (Part 14) - a &lt;strong&gt;PubSub&lt;/strong&gt; subscriber: UADP and JSON over UDP (unicast or multicast), pre-shared group-key security, optional Security Key Service. A different runtime model, ideal for high-rate telemetry.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-client
&lt;span class="c"&gt;# add only the transports you need:&lt;/span&gt;
composer require php-opcua/opcua-client-ext-reverse-connect
composer require php-opcua/opcua-client-ext-transport-https
composer require php-opcua/opcua-client-ext-transport-pubsub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code &amp;amp; docs:&lt;/strong&gt; &lt;a href="https://github.com/php-opcua" rel="noopener noreferrer"&gt;https://github.com/php-opcua&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Skills (start here):&lt;/strong&gt; &lt;a href="https://github.com/php-opcua/ai-skills" rel="noopener noreferrer"&gt;https://github.com/php-opcua/ai-skills&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs site:&lt;/strong&gt; &lt;a href="https://www.php-opcua.com" rel="noopener noreferrer"&gt;https://www.php-opcua.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is pure PHP, MIT-licensed, and tested against the OPC Foundation's UA-.NETStandard reference server.&lt;/p&gt;

&lt;p&gt;The best part? You can install the skills, describe what you need, and ship a working industrial integration this afternoon - without reading a single page of the OPC UA spec. If you build something with it (or your AI does), I'd love to hear about it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Industry 4.0, meet &lt;code&gt;composer require&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>opcua</category>
      <category>ai</category>
      <category>iot</category>
    </item>
    <item>
      <title>OPC UA in PHP without learning OPC UA - the 4.4.0 ecosystem ships AI Skills</title>
      <dc:creator>Gianfrancesco</dc:creator>
      <pubDate>Thu, 04 Jun 2026 13:21:24 +0000</pubDate>
      <link>https://dev.to/gianfriaur/opc-ua-in-php-without-learning-opc-ua-the-440-ecosystem-ships-ai-skills-10k</link>
      <guid>https://dev.to/gianfriaur/opc-ua-in-php-without-learning-opc-ua-the-440-ecosystem-ships-ai-skills-10k</guid>
      <description>&lt;h2&gt;
  
  
  OPC UA in PHP - without learning OPC UA
&lt;/h2&gt;

&lt;p&gt;A while back I shared a &lt;a href="https://github.com/php-opcua" rel="noopener noreferrer"&gt;pure-PHP OPC UA ecosystem&lt;/a&gt; that lets a web app talk to factory-floor PLCs, CNC machines, SCADA systems and IoT sensors &lt;strong&gt;without&lt;/strong&gt; C++ SDKs, gateways, or sidecar proxies. Just Composer and &lt;code&gt;ext-openssl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It just reached &lt;strong&gt;v4.4.0&lt;/strong&gt; - the biggest release so far. There's a lot of new protocol surface (aggregates, history writes, file transfer, three new transports - I'll cover them). But here's the thing I actually want to tell you about:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You no longer need to learn any of it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every package now ships an &lt;strong&gt;AI Skill&lt;/strong&gt;. Point your coding assistant at one repo, describe what you want in plain English, and it writes correct OPC UA code - the right APIs, the right security model, the right patterns - &lt;em&gt;without you knowing how OPC UA works or how the ecosystem is laid out.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let me start there, then show what's under the hood for when you're curious.&lt;/p&gt;




&lt;h2&gt;
  
  
  The point: you don't have to be an OPC UA expert
&lt;/h2&gt;

&lt;p&gt;OPC UA is &lt;em&gt;deep&lt;/em&gt;. The spec runs to a dozen multi-hundred-page Parts. There are NodeIds, secure channels, sessions, subscriptions, monitored items, companion specifications, three transport mappings, a publish/subscribe model with pre-shared group keys... Learning enough to write correct code used to be a real investment.&lt;/p&gt;

&lt;p&gt;And LLMs don't help much on their own here: ask a generic assistant to "read a tag from my PLC over OPC UA in PHP" and it will happily &lt;strong&gt;hallucinate&lt;/strong&gt; method names, miss the security model, and reinvent patterns that don't exist. It has never seen &lt;em&gt;these&lt;/em&gt; libraries.&lt;/p&gt;

&lt;p&gt;That's exactly what an &lt;a href="https://docs.claude.com/en/docs/agents-and-tools/agent-skills" rel="noopener noreferrer"&gt;&lt;strong&gt;Agent Skill&lt;/strong&gt;&lt;/a&gt; fixes. A skill is a &lt;code&gt;SKILL.md&lt;/code&gt; file - frontmatter that tells the model &lt;em&gt;when&lt;/em&gt; it's relevant, plus a body and &lt;code&gt;references/&lt;/code&gt; that tell it &lt;em&gt;how&lt;/em&gt; to use the package correctly: the API surface, the idioms, the security model, the testing approach, the common pitfalls.&lt;/p&gt;

&lt;p&gt;Every package in the ecosystem now ships one under &lt;code&gt;.ai/skills/&amp;lt;package&amp;gt;/&lt;/code&gt;, and they're all mirrored into a single auto-synced repo: &lt;strong&gt;&lt;a href="https://github.com/php-opcua/ai-skills" rel="noopener noreferrer"&gt;php-opcua/ai-skills&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So your assistant can learn the &lt;em&gt;whole&lt;/em&gt; ecosystem from one place - and &lt;strong&gt;you&lt;/strong&gt; can stay at the level of "what do I want to happen."&lt;/p&gt;

&lt;h3&gt;
  
  
  From plain English to correct code
&lt;/h3&gt;

&lt;p&gt;With the skills installed, this is the actual workflow. You write:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Connect to &lt;code&gt;opc.https://plant.local:443/UA/&lt;/code&gt; through our corporate proxy and read the boiler temperature tag."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...and your assistant produces working code that uses the right transport, knows TLS is the secure channel (so OPC UA security stays &lt;code&gt;None&lt;/code&gt;), and routes the proxy through the HTTP client - none of which you had to know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpsTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CurlHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;verifyTls&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;extraCurlOptions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;CURLOPT_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'http://proxy.corp:3128'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BinaryHttpsEncoding&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;endpointUrl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'opc.https://plant.local:443/UA/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setSecurityPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityPolicy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// TLS is the secure channel&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setSecurityMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityMode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.https://plant.local:443/UA/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;s=Boiler/Temperature'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or &lt;em&gt;"subscribe to the PubSub multicast group 239.0.0.1 and print every field"&lt;/em&gt;, or &lt;em&gt;"accept a reverse connection from our edge gateway and browse it"&lt;/em&gt; - same deal. You describe the outcome; the skill supplies the how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install it in one command
&lt;/h3&gt;

&lt;p&gt;If you're on Laravel, &lt;a href="https://github.com/laravel/boost" rel="noopener noreferrer"&gt;Boost&lt;/a&gt; v2 pulls skills straight from a GitHub repo and syncs them across every AI agent it manages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan boost:add-skill php-opcua/ai-skills &lt;span class="nt"&gt;--list&lt;/span&gt;             &lt;span class="c"&gt;# see what's available&lt;/span&gt;
php artisan boost:add-skill php-opcua/ai-skills &lt;span class="nt"&gt;--skill&lt;/span&gt; opcua-client
php artisan boost:add-skill php-opcua/ai-skills &lt;span class="nt"&gt;--all&lt;/span&gt;              &lt;span class="c"&gt;# or grab everything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;strong&gt;Claude Code&lt;/strong&gt;? These &lt;em&gt;are&lt;/em&gt; Anthropic Agent Skills - nothing to convert:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/php-opcua/ai-skills.git
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ai-skills/skills/opcua-client ~/.claude/skills/     &lt;span class="c"&gt;# personal, every project&lt;/span&gt;
&lt;span class="c"&gt;# or .claude/skills/ to commit it with your repo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code auto-activates a skill when your task matches its description. &lt;strong&gt;Cursor, Windsurf, Copilot&lt;/strong&gt; work too - drop the &lt;code&gt;SKILL.md&lt;/code&gt; into their rules/instructions folder.&lt;/p&gt;

&lt;p&gt;Take only the skills for the packages you use - each is self-contained. That's the whole onboarding.&lt;/p&gt;




&lt;h2&gt;
  
  
  ...and if you &lt;em&gt;are&lt;/em&gt; curious, here's what's new in 4.4.0
&lt;/h2&gt;

&lt;p&gt;You don't need this section to be productive. But if you like knowing what your AI is driving, here's the release.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ecosystem, briefly
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-client&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The core - pure-PHP client: read, write, browse, call, subscribe, history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-cli&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Terminal companion - browse/read/write/watch, all with &lt;code&gt;--json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-client-nodeset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pre-generated PHP types for OPC Foundation companion specs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcua-session-manager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep sessions alive across requests via a ReactPHP daemon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;laravel-opcua&lt;/code&gt; / &lt;code&gt;symfony-opcua&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Framework integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Core: aggregates, history writes, file transfer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AggregateModule&lt;/code&gt;&lt;/strong&gt; computes &lt;code&gt;Interpolate&lt;/code&gt; / &lt;code&gt;Minimum&lt;/code&gt; / &lt;code&gt;Maximum&lt;/code&gt; / &lt;code&gt;Average&lt;/code&gt; / &lt;code&gt;Count&lt;/code&gt; from a raw &lt;code&gt;DataValue&lt;/code&gt; buffer - pair it with &lt;code&gt;historyAggregate()&lt;/code&gt; to fetch + bucket in one call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HistoryUpdate&lt;/strong&gt; - nine new methods for Insert / Replace / Update / Remove of historical data and events. History is no longer read-only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;FileTransferModule&lt;/code&gt;&lt;/strong&gt; wraps the OPC UA File Transfer service set (Part 5) into typed &lt;code&gt;openFile&lt;/code&gt; / &lt;code&gt;readFile&lt;/code&gt; / &lt;code&gt;writeFile&lt;/code&gt; / &lt;code&gt;closeFile&lt;/code&gt; calls, with chunked reads for large files.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;pluggable transport layer&lt;/strong&gt; (&lt;code&gt;ClientTransportInterface&lt;/code&gt; + &lt;code&gt;ClientBuilder::setTransport()&lt;/code&gt;) - the quiet headline that made the three extensions below possible. Plus a small &lt;code&gt;DataValue::getType()&lt;/code&gt; accessor so you can read a value's type without the deprecated &lt;code&gt;getVariant()&lt;/code&gt; hop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Three new transports
&lt;/h3&gt;

&lt;p&gt;OPC UA isn't only &lt;code&gt;opc.tcp://&lt;/code&gt;. v4.4.0 brings three more mappings as &lt;strong&gt;opt-in extensions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;opcua-client-ext-reverse-connect&lt;/code&gt;&lt;/strong&gt; (Part 6 7.1.2.3) - &lt;em&gt;the server dials you&lt;/em&gt;. For edge gateways and PLCs behind NAT/firewall that can't accept inbound connections but can dial out. Your app listens, validates the announced &lt;code&gt;ServerUri&lt;/code&gt; against a fail-secure whitelist, then proceeds with the normal handshake.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;opcua-client-ext-transport-https&lt;/code&gt;&lt;/strong&gt; (Part 6 7.4) - &lt;strong&gt;&lt;code&gt;opc.https://&lt;/code&gt;&lt;/strong&gt;: one HTTPS POST per UA message, TLS as the secure channel. For getting through proxies and firewalls that block &lt;code&gt;opc.tcp://&lt;/code&gt;. Binary encoding is production-ready; JSON ships as a reference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;opcua-client-ext-transport-pubsub&lt;/code&gt;&lt;/strong&gt; (Part 14) - a &lt;strong&gt;PubSub&lt;/strong&gt; subscriber: UADP and JSON over UDP (unicast or multicast), pre-shared group-key security, optional Security Key Service. A different runtime model, ideal for high-rate telemetry.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-client
&lt;span class="c"&gt;# add only the transports you need:&lt;/span&gt;
composer require php-opcua/opcua-client-ext-reverse-connect
composer require php-opcua/opcua-client-ext-transport-https
composer require php-opcua/opcua-client-ext-transport-pubsub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code &amp;amp; docs:&lt;/strong&gt; &lt;a href="https://github.com/php-opcua" rel="noopener noreferrer"&gt;https://github.com/php-opcua&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Skills (start here):&lt;/strong&gt; &lt;a href="https://github.com/php-opcua/ai-skills" rel="noopener noreferrer"&gt;https://github.com/php-opcua/ai-skills&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs site:&lt;/strong&gt; &lt;a href="https://www.php-opcua.com" rel="noopener noreferrer"&gt;https://www.php-opcua.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is pure PHP, MIT-licensed, and tested against the OPC Foundation's UA-.NETStandard reference server.&lt;/p&gt;

&lt;p&gt;The best part? You can install the skills, describe what you need, and ship a working industrial integration this afternoon - without reading a single page of the OPC UA spec. If you build something with it (or your AI does), I'd love to hear about it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Industry 4.0, meet &lt;code&gt;composer require&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>opcua</category>
      <category>ai</category>
      <category>iot</category>
    </item>
    <item>
      <title>Who Says PHP Isn't Good Enough for OPC UA?</title>
      <dc:creator>Gianfrancesco</dc:creator>
      <pubDate>Tue, 28 Apr 2026 09:42:40 +0000</pubDate>
      <link>https://dev.to/gianfriaur/who-says-php-isnt-good-enough-for-opc-ua-5ma</link>
      <guid>https://dev.to/gianfriaur/who-says-php-isnt-good-enough-for-opc-ua-5ma</guid>
      <description>&lt;p&gt;&lt;em&gt;"PHP? For OPC UA? Come on."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've ever tried to connect a PHP application to a PLC, a SCADA system, or any industrial device, you've probably heard that line. Maybe you said it yourself, opening a browser and searching for a library that didn't exist.&lt;/p&gt;

&lt;p&gt;That time is over.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Historical Gap
&lt;/h2&gt;

&lt;p&gt;OPC UA is the standard protocol for industrial automation. Motors, sensors, historians, SCADA systems, PLCs — the entire Industry 4.0 world speaks OPC UA. It's the OPC Foundation standard: battle-tested, secure, feature-rich. It is, essentially, the TCP/IP of the manufacturing industry.&lt;/p&gt;

&lt;p&gt;And yet, for years, PHP was left out.&lt;/p&gt;

&lt;p&gt;These were your options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. An HTTP-to-OPC-UA gateway&lt;/strong&gt;&lt;br&gt;
Spin up a separate process (Python, Node.js, a C++ binary), expose a REST API, and have PHP act as the HTTP client. Result: a more complex infrastructure, added latency, one more point of failure, and a second language to maintain in parallel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Compiled C/C++ extensions&lt;/strong&gt;&lt;br&gt;
Some PHP libraries wrap C implementations via FFI or native extensions. But compiling &lt;code&gt;.so&lt;/code&gt; files for every PHP version, on every server, in every CI pipeline is an operational nightmare. And if your shared host doesn't support that extension? Dead stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Shell out to other languages&lt;/strong&gt;&lt;br&gt;
Calling a Python or Node.js process from PHP. Fragile. Slow. Hard to debug. And again: two stacks, two teams, two deployments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Commercial Windows-only libraries&lt;/strong&gt;&lt;br&gt;
COM bridges, proprietary solutions, Windows-dependent. Let's not even go there.&lt;/p&gt;

&lt;p&gt;The practical result? Anyone running an ERP in Laravel, a dashboard in Symfony, or even just a PHP API that needed to read a temperature from a Siemens S7 — had to face this reality: &lt;strong&gt;PHP wasn't "industrial enough."&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Where php-opcua Comes From
&lt;/h2&gt;

&lt;p&gt;The project was born out of a real need. Gianfrancesco Aurecchia, its creator and maintainer, had a PHP application for monitoring a production line. He needed to connect it to Siemens PLCs via OPC UA. Every available option was ugly, expensive, or both.&lt;/p&gt;

&lt;p&gt;Instead of working around the problem, he built the solution.&lt;/p&gt;

&lt;p&gt;The result — today — is an ecosystem of &lt;strong&gt;7 packages&lt;/strong&gt;, &lt;strong&gt;147,000 lines of PHP&lt;/strong&gt;, &lt;strong&gt;2,649 tests&lt;/strong&gt;, &lt;strong&gt;5,204 assertions&lt;/strong&gt;, and zero runtime dependencies beyond &lt;code&gt;ext-openssl&lt;/code&gt;. An open-source project that implements the full OPC UA binary protocol natively in PHP.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Ecosystem: Package by Package
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. &lt;code&gt;opcua-client&lt;/code&gt; — The Core
&lt;/h3&gt;

&lt;p&gt;This is the core package. It implements the entire OPC UA binary protocol stack in pure PHP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TCP transport and binary encoding/decoding&lt;/li&gt;
&lt;li&gt;Secure channel with asymmetric and symmetric encryption&lt;/li&gt;
&lt;li&gt;Session management&lt;/li&gt;
&lt;li&gt;All major OPC UA services: browse, read, write, method call, subscriptions, history
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\ClientBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.tcp://192.168.1.100:4840'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;s=Temperature'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$temp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 23.5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Three lines. No config files, no XML, no gateway.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;10 security policies&lt;/strong&gt;, from &lt;code&gt;None&lt;/code&gt; up to &lt;code&gt;Aes256_Sha256_RsaPss&lt;/code&gt; and the new ECC policies (&lt;code&gt;nistP256&lt;/code&gt;, &lt;code&gt;nistP384&lt;/code&gt;, &lt;code&gt;brainpoolP256r1&lt;/code&gt;, &lt;code&gt;brainpoolP384r1&lt;/code&gt;). Anonymous, username/password, and X.509 authentication. Persistent trust store with TOFU support.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  2. &lt;code&gt;opcua-session-manager&lt;/code&gt; — The Answer to PHP's Stateless Model
&lt;/h3&gt;

&lt;p&gt;This was the biggest objection. OPC UA requires a persistent session: the initial handshake costs 50–200ms and must be repeated on every connection. PHP's request/response model destroys all state at the end of each request.&lt;/p&gt;

&lt;p&gt;The answer is the &lt;strong&gt;Session Manager&lt;/strong&gt;: a long-lived ReactPHP daemon that keeps OPC UA sessions alive in memory, communicating with PHP processes over a Unix socket. The handshake happens once. Every subsequent request reuses the existing session — reducing per-request overhead from ~150ms to ~5ms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-session-manager

&lt;span class="c"&gt;# Start the daemon&lt;/span&gt;
php bin/opcua-session-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\SessionManager\Client\ManagedClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Same interface as the direct client&lt;/span&gt;
&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ManagedClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.tcp://localhost:4840'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'i=2259'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ManagedClient&lt;/code&gt; implements the same &lt;code&gt;OpcUaClientInterface&lt;/code&gt; as the direct client. Change one line, keep all your code. In production, the daemon runs under &lt;code&gt;systemd&lt;/code&gt; or &lt;code&gt;supervisord&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. &lt;code&gt;laravel-opcua&lt;/code&gt; — Laravel-Native
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/laravel-opcua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Service Provider, Facade, Artisan commands, configuration via &lt;code&gt;config/opcua.php&lt;/code&gt;. Named connections like database config. Subscriptions that become Laravel Events. Logging with Laravel's logger. Caching with Redis. Testing with MockClient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\LaravelOpcua\Facades\Opcua&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Read from the default connection&lt;/span&gt;
&lt;span class="nv"&gt;$temperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Opcua&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;s=Temperature'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Switch to a different PLC on the fly&lt;/span&gt;
&lt;span class="nv"&gt;$level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Opcua&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tank-plc'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;s=FillLevel'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;OpcuaManager&lt;/code&gt; automatically checks whether the Session Manager daemon is running: if the Unix socket exists, traffic routes through the daemon for session persistence; otherwise it builds a direct client. Zero code changes to switch between development and production.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. &lt;code&gt;symfony-opcua&lt;/code&gt; — The Symfony Bundle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/symfony-opcua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependency injection, semantic YAML configuration, autowiring of &lt;code&gt;OpcUaClientInterface&lt;/code&gt;, a console command for the daemon, automatic Monolog integration, automatic PSR-16 cache pool injection, and 47 PSR-14 events dispatched through Symfony's event system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/packages/php_opcua_symfony_opcua.yaml&lt;/span&gt;
&lt;span class="na"&gt;php_opcua_symfony_opcua&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%env(OPCUA_ENDPOINT)%'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\SymfonyOpcua\OpcuaManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlcController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;OpcuaManager&lt;/span&gt; &lt;span class="nv"&gt;$opcua&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$opcua&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$value&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'i=2259'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. &lt;code&gt;opcua-client-nodeset&lt;/code&gt; — 51 Companion Specs, Zero Manual Codecs
&lt;/h3&gt;

&lt;p&gt;The OPC Foundation publishes dozens of "companion specifications": standardized data models for Robotics, Machinery, MachineTool, ISA-95, CNC, MTConnect, and many more. Decoding these structures normally requires writing custom codecs by hand.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;opcua-client-nodeset&lt;/code&gt; ships &lt;strong&gt;807 pre-generated PHP files&lt;/strong&gt; from 51 companion specs. Enumerations as PHP &lt;code&gt;BackedEnum&lt;/code&gt;, structures as typed DTOs with full IDE autocomplete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-client-nodeset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Nodeset\Robotics\RoboticsRegistrar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Nodeset\Robotics\Enums\OperationalModeEnumeration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;loadGeneratedTypes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RoboticsRegistrar&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.tcp://192.168.1.100:4840'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoboticsNodeIds&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;OperationalMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// OperationalModeEnumeration::MANUAL_REDUCED_SPEED — not a raw integer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. &lt;code&gt;opcua-cli&lt;/code&gt; — Explore Without Writing Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-cli

opcua-cli browse    opc.tcp://192.168.1.10:4840 /Objects
opcua-cli &lt;span class="nb"&gt;read      &lt;/span&gt;opc.tcp://192.168.1.10:4840 &lt;span class="s2"&gt;"ns=2;i=1001"&lt;/span&gt;
opcua-cli watch     opc.tcp://192.168.1.10:4840 &lt;span class="s2"&gt;"ns=2;s=Temperature"&lt;/span&gt;
opcua-cli endpoints opc.tcp://192.168.1.10:4840
opcua-cli trust     opc.tcp://server:4840
opcua-cli generate:nodeset MySpec.NodeSet2.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Address space browsing, node read/write, real-time monitoring, endpoint discovery, trust store management, and PHP class generation from custom NodeSet2.xml files. Full security support, JSON output, debug logging.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. &lt;code&gt;uanetstandard-test-suite&lt;/code&gt; — CI Without Compromise
&lt;/h3&gt;

&lt;p&gt;A Docker environment with &lt;strong&gt;10 pre-configured OPC UA servers&lt;/strong&gt; based on UA-.NETStandard (the OPC Foundation's reference implementation), covering all security policies, all data types, events, and historical data. The &lt;code&gt;opcua-client&lt;/code&gt; test suite runs against real servers, not mocks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/pest                                          &lt;span class="c"&gt;# everything&lt;/span&gt;
./vendor/bin/pest tests/Unit/                              &lt;span class="c"&gt;# unit only&lt;/span&gt;
./vendor/bin/pest tests/Integration/ &lt;span class="nt"&gt;--group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;integration   &lt;span class="c"&gt;# integration only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CI runs on PHP 8.2, 8.3, 8.4, and 8.5 via GitHub Actions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ecosystem by the Numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lines of PHP&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;147,000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2,649&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assertions&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5,204&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Packages&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security policies&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;10&lt;/strong&gt; (RSA + ECC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Companion specs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;51&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-generated types&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;807&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C runtime dependencies&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supported PHP versions&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.2 / 8.3 / 8.4 / 8.5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Architecture at a Glance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Application
  │
  ├── laravel-opcua  or  symfony-opcua    Framework integration
  │     │
  │     ├── opcua-session-manager         Persistent sessions (optional)
  │     │
  │     └── opcua-client                  Binary protocol, crypto, I/O
  │           │
  │           └── opcua-client-nodeset    Type definitions (optional)
  │
  └── opcua-cli                           Developer tooling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each package has a single responsibility. You can use just &lt;code&gt;opcua-client&lt;/code&gt; in a CLI script, or the entire stack in an enterprise Laravel application. The only dependency required everywhere is &lt;code&gt;ext-openssl&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Can Build With It Today
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Real-time dashboards&lt;/strong&gt; — Read process variables from PLCs in Laravel, display charts, fire alerts: all in the same stack as your existing web application. No sidecar, no extra microservice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SCADA-to-ERP integration&lt;/strong&gt; — Read production counters via OPC UA and write them directly into your PHP-based ERP, MES, or inventory system. In an Eloquent model. Through a queue. With all the tools you already know.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IoT data collection&lt;/strong&gt; — Use the Session Manager to maintain persistent connections to dozens of devices simultaneously. Collect sensor data, store it in your database, process it with Laravel queues or Symfony Messenger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automated OPC UA server testing&lt;/strong&gt; — Use &lt;code&gt;MockClient&lt;/code&gt; for unit tests and the Docker test suite for CI integration. Validate your OPC UA server implementation with a PHP test suite, without needing a separate desktop client.&lt;/p&gt;




&lt;h2&gt;
  
  
  Still not convinced?
&lt;/h2&gt;

&lt;p&gt;Fine — words are cheap. Here's a complete, runnable example you can clone,&lt;br&gt;
&lt;code&gt;composer install&lt;/code&gt;, and watch reconnect itself when you yank the cable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/php-opcua/examples/tree/master/iot-data-collection/only-core" rel="noopener noreferrer"&gt;php-opcua/examples — iot-data-collection/only-core&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A production-shaped IoT data collector built &lt;strong&gt;only&lt;/strong&gt; on &lt;code&gt;opcua-client&lt;/code&gt;:&lt;br&gt;
a long-running daemon that subscribes to monitored items, a cron-style&lt;br&gt;
one-shot for periodic batches, both wired to the same PSR-14 event bus.&lt;br&gt;
Persistence, MQTT forwarding, alerting — all of it lives in a single&lt;br&gt;
user-editable &lt;code&gt;listeners.php&lt;/code&gt; you actually want to write.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's ready for critical workloads&lt;/strong&gt; — designed to bend, not break, where&lt;br&gt;
downtime is genuinely unacceptable. Connection drops? Infinite reconnect&lt;br&gt;
with a configurable backoff schedule. Server failover? Subscription&lt;br&gt;
rebuilt, monitored items re-registered, listeners none the wiser. Listener&lt;br&gt;
throws? Wrapped, metric incremented, daemon stays up.&lt;/p&gt;

&lt;p&gt;The README walks you through customization, the performance envelope, and&lt;br&gt;
a 6-hour worst-case timeline showing exactly what the scaffold survives&lt;br&gt;
without operator intervention.&lt;/p&gt;

&lt;p&gt;Clone it. Run it. Pull the cable. See for yourself.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bonus: It's Already AI-Ready
&lt;/h2&gt;

&lt;p&gt;There's one more thing worth highlighting — because in 2026 it makes a real difference.&lt;/p&gt;

&lt;p&gt;Using a new library with an AI assistant — Cursor, Copilot, Claude — only works well if the AI actually knows the library. If it doesn't, it generates plausible-looking but wrong code: unsupported patterns, non-existent methods, broken configurations. You end up spending more time correcting the AI than you would have spent reading the docs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php-opcua&lt;/code&gt; has addressed this problem explicitly.&lt;/p&gt;

&lt;p&gt;Every package in the ecosystem ships three files designed specifically for AI model consumption:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Structured summary: API, key patterns, core examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;llms-full.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Complete documentation in LLM-optimized format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;llms-skills.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skill file for AI assistants with usage rules and patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Available for every package directly from the website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://www.php-opcua.com/llms/opcua-client/llms.txt
https://www.php-opcua.com/llms/opcua-client/llms-full.txt
https://www.php-opcua.com/llms/opcua-client/llms-skills.md

https://www.php-opcua.com/llms/laravel-opcua/llms.txt
https://www.php-opcua.com/llms/symfony-opcua/llms.txt
https://www.php-opcua.com/llms/opcua-session-manager/llms.txt
https://www.php-opcua.com/llms/opcua-cli/llms.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a centralized index for the entire ecosystem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://www.php-opcua.com/llms.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What changes in practice?&lt;/strong&gt; Point your AI assistant at &lt;code&gt;llms-full.txt&lt;/code&gt; for the package you need, or load &lt;code&gt;llms-skills.md&lt;/code&gt; as context, and from that moment the AI generates correct code: the right NodeId strings, the right fluent builders, the right typed DTOs, the right retry and security patterns. Zero tokens wasted correcting hallucinations about an API the model never had in its training data.&lt;/p&gt;

&lt;p&gt;The library isn't just AI-compatible — it's &lt;strong&gt;AI-first by design&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The historical PHP gap for OPC UA still lives on in tutorials, forum threads, and industrial conference slides. But in practice, from 2026, it's no longer a real problem.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php-opcua&lt;/code&gt; is a mature, tested, documented, and actively maintained ecosystem. Zero C extensions. Zero gateways. Zero architectural compromises. The full OPC UA binary protocol, in pure PHP, with native integration for Laravel and Symfony.&lt;/p&gt;

&lt;p&gt;Next time someone tells you &lt;em&gt;"PHP isn't good enough for OPC UA"&lt;/em&gt;, you have a concrete answer.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;a href="https://www.php-opcua.com/" rel="noopener noreferrer"&gt;php-opcua.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://github.com/php-opcua/opcua-client" rel="noopener noreferrer"&gt;github.com/php-opcua/opcua-client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🏭 &lt;a href="https://www.php-opcua.com/laravel-opcua" rel="noopener noreferrer"&gt;Laravel Integration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 &lt;a href="https://www.php-opcua.com/symfony-opcua" rel="noopener noreferrer"&gt;Symfony Bundle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🛠️ &lt;a href="https://www.php-opcua.com/opcua-cli" rel="noopener noreferrer"&gt;CLI Tool&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📚 &lt;a href="https://www.php-opcua.com/opcua-session-manager" rel="noopener noreferrer"&gt;Session Manager&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>industrialautomation</category>
      <category>laravel</category>
      <category>opcua</category>
    </item>
    <item>
      <title>OPC UA from PHP? Yes, with Zero C Extensions — Introducing php-opcua/opcua-client</title>
      <dc:creator>Gianfrancesco</dc:creator>
      <pubDate>Tue, 28 Apr 2026 09:06:08 +0000</pubDate>
      <link>https://dev.to/gianfriaur/opc-ua-from-php-yes-with-zero-c-extensions-introducing-php-opcuaopcua-client-p6</link>
      <guid>https://dev.to/gianfriaur/opc-ua-from-php-yes-with-zero-c-extensions-introducing-php-opcuaopcua-client-p6</guid>
      <description>&lt;p&gt;If you've ever tried to connect a PHP application to industrial machinery — a PLC, a SCADA system, a historian — you've probably hit a wall. The OPC UA standard is the lingua franca of industrial IoT, but most implementations assume you're writing in C++, Python, or .NET. PHP? Good luck finding anything that isn't a thin HTTP wrapper around a gateway you have to run separately.&lt;/p&gt;

&lt;p&gt;That changes with &lt;a href="https://github.com/php-opcua/opcua-client" rel="noopener noreferrer"&gt;&lt;code&gt;php-opcua/opcua-client&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is OPC UA?
&lt;/h2&gt;

&lt;p&gt;OPC UA (Unified Architecture) is an industrial communication standard developed by the OPC Foundation. It lets software clients talk to sensors, PLCs, SCADA systems, historians, and IoT devices over a standardized protocol — with built-in security, data typing, discovery, and more. It's the backbone of Industry 4.0 and IIoT architectures worldwide.&lt;/p&gt;

&lt;p&gt;The protocol runs over TCP (binary encoding) and is notoriously complex to implement: it includes asymmetric and symmetric encryption, certificate management, session handling, subscriptions, historical queries, and a rich address space model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a Pure PHP Implementation?
&lt;/h2&gt;

&lt;p&gt;Most PHP projects that need OPC UA resort to one of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;HTTP REST gateway&lt;/strong&gt; (adds a sidecar process, latency, and a point of failure)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;COM bridge on Windows&lt;/strong&gt; (commercial, not portable)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shelling out&lt;/strong&gt; to a Python or Node.js script&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;php-opcua/opcua-client&lt;/code&gt; is different. It implements the entire OPC UA binary protocol stack &lt;strong&gt;natively in PHP&lt;/strong&gt;, with only &lt;code&gt;ext-openssl&lt;/code&gt; as a runtime dependency. No FFI. No COM. No gateway. Just &lt;code&gt;composer require&lt;/code&gt; and you're connecting to PLCs from your Laravel app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\ClientBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.tcp://localhost:4840'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'i=2259'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 0 = Running&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines. No config files, no XML, no service containers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NodeId strings like &lt;code&gt;'i=2259'&lt;/code&gt;, &lt;code&gt;'ns=2;i=1001'&lt;/code&gt;, or &lt;code&gt;'ns=2;s=MyNode'&lt;/code&gt; are accepted everywhere. Invalid strings throw &lt;code&gt;InvalidNodeIdException&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Core Features in Practice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Browse the Address Space
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$refs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;browse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'i=85'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Objects folder&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$refs&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;displayName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nodeId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// =&amp;gt; Server (ns=0;i=2253)&lt;/span&gt;
    &lt;span class="c1"&gt;// =&amp;gt; MyPLC (ns=2;i=1000)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Read Multiple Values in One Round-Trip
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;readMulti&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'i=2259'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;i=1001'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;s=Temperature'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$results&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$dataValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$dataValue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fluent builder auto-batches requests transparently — one TCP round-trip regardless of how many nodes you chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write to a PLC
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\Types\BuiltinType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Auto-detect type (reads the node first, caches the result)&lt;/span&gt;
&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;i=1001'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Explicit type&lt;/span&gt;
&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;i=1001'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BuiltinType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Subscribe to Real-Time Data Changes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$sub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createSubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publishingInterval&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;500.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createMonitoredItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;subscriptionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'nodeId'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;NodeId&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;notifications&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$notif&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$notif&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'dataValue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Call Methods on the Server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\Types\Variant&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'i=2253'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// Server object&lt;/span&gt;
    &lt;span class="s1"&gt;'i=11492'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// GetMonitoredItems method&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Variant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BuiltinType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;UInt32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                   &lt;span class="c1"&gt;// 0 (Good)&lt;/span&gt;
&lt;span class="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;outputArguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [1001, 1002, ...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Query Historical Data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;historyReadRaw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'ns=2;i=1001'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DateTimeImmutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-1 hour'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DateTimeImmutable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$dv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$dv&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sourceTimestamp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'H:i:s'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$dv&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Enterprise-Grade Security
&lt;/h2&gt;

&lt;p&gt;The library supports &lt;strong&gt;6 security policies&lt;/strong&gt;, from &lt;code&gt;None&lt;/code&gt; up to &lt;code&gt;Aes256Sha256RsaPss&lt;/code&gt;, and three authentication modes: anonymous, username/password, and X.509 certificates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\Security\SecurityPolicy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\Security\SecurityMode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setSecurityPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityPolicy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Basic256Sha256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setSecurityMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityMode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;SignAndEncrypt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setClientCertificate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/certs/client.pem'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/certs/client.key'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/certs/ca.pem'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setUserCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'operator'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'secret'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.tcp://192.168.1.100:4840'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Omit &lt;code&gt;setClientCertificate()&lt;/code&gt; and a self-signed cert is auto-generated in memory — perfect for development or servers with auto-accept enabled.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The library also ships a &lt;strong&gt;persistent trust store&lt;/strong&gt; with Trust-On-First-Use (TOFU) support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\TrustStore\FileTrustStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\TrustStore\TrustPolicy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTrustStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileTrustStore&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;      &lt;span class="c1"&gt;// ~/.opcua/trusted/&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTrustPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TrustPolicy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Fingerprint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.tcp://192.168.1.100:4840'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Laravel Integration
&lt;/h2&gt;

&lt;p&gt;If you're on Laravel, there's a dedicated package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/laravel-opcua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It ships a service provider, a facade, and config scaffolding so you can inject &lt;code&gt;OpcUaClient&lt;/code&gt; from the container and configure connections in &lt;code&gt;config/opcua.php&lt;/code&gt;. Fully compatible with Laravel's PSR-3 logger and PSR-14 event dispatcher.&lt;/p&gt;




&lt;h2&gt;
  
  
  47 PSR-14 Events — Zero Overhead When Unused
&lt;/h2&gt;

&lt;p&gt;The library fires granular events for every lifecycle moment: connection, session, data change, alarms, retries, cache hits, and more. Plug in any PSR-14 dispatcher to react to them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\Event\AlarmActivated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AlarmHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handleActivated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;AlarmActivated&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;critical&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Alarm: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sourceName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (severity: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;severity&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without a dispatcher, the default &lt;code&gt;NullEventDispatcher&lt;/code&gt; ensures zero overhead.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing Without a Real PLC
&lt;/h2&gt;

&lt;p&gt;The library ships a &lt;code&gt;MockClient&lt;/code&gt; that implements the same interface as the real client — no TCP connection required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\Testing\MockClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Client\Types\DataValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MockClient&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;onRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;NodeId&lt;/span&gt; &lt;span class="nv"&gt;$nodeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;DataValue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;ofDouble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;23.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ns=2;s=Temperature'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 23.5&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;callCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'read'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register handlers for &lt;code&gt;onRead()&lt;/code&gt;, &lt;code&gt;onWrite()&lt;/code&gt;, &lt;code&gt;onBrowse()&lt;/code&gt;, &lt;code&gt;onCall()&lt;/code&gt;, and &lt;code&gt;onResolveNodeId()&lt;/code&gt;. Track calls with &lt;code&gt;getCalls()&lt;/code&gt;, &lt;code&gt;callCount()&lt;/code&gt;, and &lt;code&gt;resetCalls()&lt;/code&gt;. Your CI pipeline never needs a real OPC UA server.&lt;/p&gt;




&lt;h2&gt;
  
  
  The CLI Tool
&lt;/h2&gt;

&lt;p&gt;A companion CLI package lets you explore OPC UA servers from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require php-opcua/opcua-cli

&lt;span class="c"&gt;# Browse the address space&lt;/span&gt;
opcua-cli browse opc.tcp://192.168.1.10:4840 /Objects

&lt;span class="c"&gt;# Read a value&lt;/span&gt;
opcua-cli &lt;span class="nb"&gt;read &lt;/span&gt;opc.tcp://192.168.1.10:4840 &lt;span class="s2"&gt;"ns=2;i=1001"&lt;/span&gt;

&lt;span class="c"&gt;# Watch a value in real time&lt;/span&gt;
opcua-cli watch opc.tcp://192.168.1.10:4840 &lt;span class="s2"&gt;"ns=2;i=1001"&lt;/span&gt;

&lt;span class="c"&gt;# Discover endpoints&lt;/span&gt;
opcua-cli endpoints opc.tcp://192.168.1.10:4840

&lt;span class="c"&gt;# Manage trusted server certificates&lt;/span&gt;
opcua-cli trust opc.tcp://server:4840
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also generates PHP type files from NodeSet2.xml companion specifications — useful when working with vendor-specific data models.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pre-Built Companion Types
&lt;/h2&gt;

&lt;p&gt;The ecosystem includes &lt;code&gt;php-opcua/opcua-client-nodeset&lt;/code&gt;, which ships pre-generated PHP types for &lt;strong&gt;51 OPC Foundation companion specifications&lt;/strong&gt; — Robotics, Machinery, MachineTool, ISA-95, CNC, MTConnect, and more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Nodeset\Robotics\RoboticsRegistrar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PhpOpcua\Nodeset\Robotics\Enums\OperationalModeEnumeration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;loadGeneratedTypes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RoboticsRegistrar&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opc.tcp://192.168.1.100:4840'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Enum values auto-cast to PHP BackedEnum — not raw ints&lt;/span&gt;
&lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoboticsNodeIds&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;OperationalMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// OperationalModeEnumeration::MANUAL_REDUCED_SPEED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Structured types return &lt;strong&gt;typed DTOs&lt;/strong&gt; with IDE autocomplete — no more digging through arrays.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About Long-Lived Connections?
&lt;/h2&gt;

&lt;p&gt;PHP's request/response model doesn't naturally support persistent TCP connections. For continuous monitoring or subscription polling, the ecosystem provides &lt;code&gt;php-opcua/opcua-session-manager&lt;/code&gt; — a ReactPHP daemon that keeps OPC UA sessions alive across short-lived PHP requests via Unix sockets. It's a separate package by design: bundling a ReactPHP daemon would break the zero-dependency philosophy of the core library.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Browse / Path resolution&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read / Write (single &amp;amp; batch)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subscriptions &amp;amp; data change events&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Historical data (raw, processed, at-time)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method calls&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 security policies (None → Aes256Sha256RsaPss)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anonymous / Username / X.509 auth&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSR-3 logging, PSR-14 events, PSR-16 cache&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MockClient for testing&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laravel service provider + facade&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLI tool&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;51 companion NodeSet types&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP 8.2 / 8.3 / 8.4 / 8.5&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero runtime deps (except ext-openssl)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1290+ tests, 99%+ coverage&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;php-opcua/opcua-client&lt;/code&gt; fills a real gap: industrial systems speak OPC UA, and PHP has always been left out of that conversation. This library brings the full protocol stack to PHP with production-grade security, a clean API, a MockClient for testing, and a growing ecosystem of companion packages.&lt;/p&gt;

&lt;p&gt;If you're building anything in the IIoT or Industry 4.0 space with PHP — connecting Laravel to factory floor equipment, pulling data from historians, or monitoring production lines — this library is worth a look.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 Website: &lt;a href="https://www.php-opcua.com/" rel="noopener noreferrer"&gt;php-opcua.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 GitHub: &lt;a href="https://github.com/php-opcua/opcua-client" rel="noopener noreferrer"&gt;github.com/php-opcua/opcua-client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 Packagist: &lt;a href="https://packagist.org/packages/php-opcua/opcua-client" rel="noopener noreferrer"&gt;packagist.org/packages/php-opcua/opcua-client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🛠️ CLI: &lt;a href="https://github.com/php-opcua/opcua-cli" rel="noopener noreferrer"&gt;github.com/php-opcua/opcua-cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🏭 Laravel: &lt;a href="https://github.com/php-opcua/laravel-opcua" rel="noopener noreferrer"&gt;github.com/php-opcua/laravel-opcua&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>iot</category>
      <category>industrialautomation</category>
      <category>laravel</category>
    </item>
  </channel>
</rss>
