Open-source project
phpro/soap-client avatar
phpro/soap-client

soap-client: typed PHP objects instead of arrays for SOAP integrations

A general purpose SOAP client for PHP

890 stars173 forksPHPMIT

At a glance

What is it?
phpro/soap-client is a PHP client for SOAP services that generates request and response value objects from a WSDL, wraps the native SoapClient so you only expose the operations you need, and layers logging, validation and caching on through event subscribers. The development work lives across several php-soap packages, and the six line branch has just seen its first three releases.
Who is it for?
soap-client suits a PHP team integrating with a SOAP service whose WSDL is stable and whose operations are worth typing properly, because the generated value objects and the wrapped client remove the array and stdClass handling that makes native SoapClient awkward to test.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 147 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem with the native SoapClient

The readme opens with a blunt question, Sick and tired of building crappy SOAP implementations?, and the rest of the document is an argument about why the native PHP SoapClient is awkward in modern PHP.

The complaint is specific. By default the SoapClient works with a mix of arrays, stdClasses and other scalar types, and the documentation lists four consequences: it makes your code hard to test, it breaks code completion, it is hard to track changes in the response and request objects, and the content of a result is never explicit.

That last one is the heart of it. A SOAP response is a nested structure, and handing it back as an array means the caller has to know the shape by convention. Type it as objects and the shape is in the signature.

So the package forces value objects for requests and responses. The documentation is honest that maintaining those objects by hand is a lot of work, and answers that with the code generation tooling described below.

A second complaint follows from the first. The native SoapClient works with a lot of magic methods, which are hard to debug and give no code completion, and both SOAP and the implementation methods sit on the same object. The package's answer is to force you to wrap the SoapClient into your own client, where you can choose to expose only the methods you need. The claim is that it will always be clear what is in your client, how it works and what it returns, and there is a base client provided with common methods for debugging, authentication and an event system.

The third point is about separation of concerns. In lots of SOAP integrations the logging, the caching and the SOAP call live in the same method, which makes the code hard to read and dependent on other classes and packages. Hence the event system.

The seven step path from WSDL to a tested client

The documentation gives a numbered path, and it is worth following because each step is a separate tool.

sh
composer require phpro/soap-client

Then the sequence is: create your own SOAP client, generate PHP classes based on SOAP types, generate a class map, generate your own SOAP client, generate a client factory, use your SOAP client, and test your SOAP client. Each of those steps has its own documentation page under docs/, covering the client, the CLI generate-types, generate-classmap, generate-client and generate-clientfactory commands, then usage and testing.

The class map step exists for a reason stated in the design section. The SoapClient needs a class map of WSDL to PHP classes, so the class map generator is what connects the service description to the generated types.

The separation of generate-client from generate-clientfactory is also deliberate. One produces the client class for a single service, the other produces the factory that wires several services together, which is what you need when an integration talks to more than one endpoint.

And the order matters. Types first, then the class map, then the client that uses them, then the factory, then usage, then tests. Each artifact is generated from the previous one, so the WSDL is the single source of truth and the generated code is a function of it.

There is also a shortcut for people who would rather not read any of that. Since life is too short to read documentation, the project ships a scaffolding wizard.

sh
./vendor/bin/soap-client wizard

It gets you communicating with a SOAP server without going through the seven steps by hand, and the documentation points at the manual installation pages for customizing what it generates.

Events are where the logging and validation go

The event listener is described as a way to hook in at every important step of the SOAP flow, so that logging, validation and error handling can be added with event subscribers.

Two subscribers are documented explicitly. The Logger Subscriber handles logging, and the Validator Subscriber handles validation. Both are separate from the request and response objects themselves, which is the point of the design.

The extension story is broader. Implementing SOAP extensions is described as a real pain because it forces you to overwrite core methods of the built-in SOAP client, and the documentation names WSA and WSSE as examples of things you would have had to do that way. The package instead lets you specify which data transfer handler you want to use, for example Guzzle, and depending on the handler you can add support for SOAP extensions or advanced authentication through HTTP middlewares.

That last point is the one that changes what the library is. Because the transport is pluggable, the security features that are hardest to implement, WS-Security headers, WS-Addressing, advanced authentication schemes, become a middleware concern rather than a subclassing concern.

The advanced configuration section lists the rest of the surface. Type converters can be added to transform values of a specific SOAP type from and to a PHP type, with basic transformers for date and datetime included and custom ones easy to add. There is a separate Psr-18 HTTP Transport package with a middleware configuration guide, a WSDL loader you can select, and a metadata manipulation page.

The README also notes that this is a client implementation on top of the php-soap packages, and that more advanced configuration is documented inside those packages rather than here. So the boundary matters when you evaluate: soap-client is the layer you depend on, and the behaviour lives underneath it.

Prerequisites, drivers and the choice of HTTP client

The prerequisites section is worth reading carefully, because it determines whether the package installs at all.

You can choose what HTTP client you want to use, and the package expects certain PSR implementations to be present. PSR-6 as a psr/cache-implementation, with symfony/cache or a cache adapter named as examples. PSR-7 as a psr/http-message-implementation, with nyholm/psr7 and guzzlehttp/psr7 given. PSR-17 as a psr/http-factory-implementation, the same two examples. PSR-18 as a psr/http-client-implementation, with symfony/http-client and guzzlehttp/guzzle named.

That is four separate interfaces to satisfy, which is the price of the pluggable transport design.

The example install shows the two you would normally reach for together.

sh
composer require symfony/http-client nyholm/psr7

The last prerequisite paragraph is also a design statement. Dealing with ext-soap is not for all developers, there are quirks you need to know about, and therefore the project made it possible to use whichever driver you want. The README is cut off mid-sentence describing the default, but the intent is clear from the driver packages linked in the advanced configuration section.

This matters for the six line branch in particular, because the WSDL loader is listed as a separate package with its own documentation, and driver choice in that package is what decides which PHP extensions you need on the target server.

For an evaluator, the practical checklist is therefore: does your service publish a WSDL, and are you willing to have four PSR packages in your composer.json.

The 6.x branch and the cost of upgrading

The release history is short and recent. Version 6.0.0 on 2026-03-27, 6.1.0 on 2026-05-28 and 6.2.0 on 2026-05-29, with the last push on 2026-05-29.

Three releases in two months on a brand new major version is the shape of a project resetting its API surface after a long-lived five line, and the default branch is named v6.x to match.

For an adopter the consequence is the one that applies to any generated-code library. If your integration has a few thousand lines of value objects, the upgrade from 5.x to 6.x is not a composer constraint bump, it is a regeneration and a review. The presence of an UPGRADING.md at the repository root suggests the maintainers have written down what changed, and for a project with this many generated classes, that document is the first thing to read.

The release process is visible in the Makefile, which has a single target. The tag target requires a TAG variable, rewrites the APP_VERSION constant in the console Application class with sed, runs a PHP syntax check on that file, commits everything, and creates a signed git tag.

bash
sed -i '' -e "s/APP_VERSION = '.*'/APP_VERSION = '$(TAG)'/" src/Phpro/SoapClient/Console/Application.php

The use of sed with the macOS style empty argument for in place editing is a small portability detail that will annoy anyone tagging a release on Linux, and it is the kind of thing you discover the day you need to cut a version yourself.

The repository also carries a grumphp.yml for GrumPHP, phpstan.neon for static analysis, phpunit.xml for tests, a spec/ directory alongside test/, and a .phpspec/ directory, so the testing story covers both PHPUnit and PHPSpec.

Editorial conclusion

soap-client suits a PHP team integrating with a SOAP service whose WSDL is stable and whose operations are worth typing properly, because the generated value objects and the wrapped client remove the array and stdClass handling that makes native SoapClient awkward to test. It does not suit a one-off call to a simple endpoint, where the native extension and a hand written array is faster to reach for, and the cost of a 6.x major upgrade is real for a codebase built around generated classes. Before adopting it, check that the WSDL is something you want modelled in full, because the generator produces a class per type and the cost scales with the size of the service.

Frequently asked questions

Why would I use phpro/soap-client instead of the native PHP SoapClient?

The documentation argues that the native SoapClient works with a mix of arrays, stdClasses and scalars, which makes code hard to test, breaks code completion, makes changes hard to track and leaves the content of a result implicit. soap-client forces typed value objects for requests and responses and wraps the native client so you expose only the operations you need.

How do I install phpro/soap-client?

Run composer require phpro/soap-client. You also need PSR implementations present: psr/cache-implementation, psr/http-message-implementation, psr/http-factory-implementation and psr/http-client-implementation, for example composer require symfony/http-client nyholm/psr7. You choose which HTTP client to use.

What does the soap-client scaffolding wizard do?

It is a command line tool, run as ./vendor/bin/soap-client wizard, that sets up communication with a SOAP server without you reading the documentation first. You can then customize the generated code using the manual installation pages.

How do I add logging and validation to soap-client calls?

The client has an event system you can hook into at every important step of the SOAP flow, and the documentation ships a Logger Subscriber and a Validator Subscriber as event subscribers. Type converters can also be added to transform values of a specific SOAP type, with date and datetime transformers included.

Which versions of phpro/soap-client are recent?

The default branch is v6.x, with 6.0.0 released on 2026-03-27, 6.1.0 on 2026-05-28 and 6.2.0 on 2026-05-29, and the last push on 2026-05-29. The repository includes an UPGRADING.md at the root, and the licence field says MIT with a LICENSE file present.

Official sources

  1. Issues
  2. License: MIT
  3. phpro/soap-client on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/phpro-soap-client.svg)](https://hysenlabs.com/projects/phpro-soap-client)

Was this useful?