phpro/soap-client
A general-purpose SOAP client for PHP with WSDL-based code generation, type-safe wrappers, PSR-18 transport, middleware, and extensible event-driven customization for clean, maintainable integrations.
Architecture fit. phpro/soap-client is framework-agnostic and built on PSR abstractions (PSR-18 HTTP client, PSR-17 factories, PSR-3 logger, PSR-16 cache, Symfony EventDispatcher), which maps cleanly onto Laravel's service container, config repository, logging, and queue primitives. Its defining characteristic is code generation: from a WSDL/XSD it emits a typed client class plus request/response value objects, so SOAP calls become typed method calls instead of hand-built SoapClient::__soapCall arrays. That is the strongest architectural argument for adopting it — it makes a legacy protocol statically analyzable (PHPStan/Psalm/IDE completion) and testable, and it isolates transport concerns into a middleware pipeline (logging, last-request capture, validation, event dispatch) rather than scattering them across call sites.
Integration feasibility. For a single, well-formed WSDL this is roughly a one-to-two-day spike for a mid-level PHP developer: install, configure a ClientSpecification, run the generator, wire a container binding. Effort scales with the contract, not the library: WS-Security (UsernameToken, X.509 sign/encrypt), WS-Addressing, MTOM/attachments, SOAP 1.2-vs-1.1 quirks, and custom HTTP headers each require bespoke middleware or manual envelope manipulation. Authentication is the most common hidden cost — HTTP Basic is trivial; WS-Security and certificate rotation are not.
Technical risk.
Key questions.
ext-soap permitted in our runtime image, or must we stay pure-PHP/PSR-18?Stack fit. Composer-installable, PHP 8.x, no framework assumptions. Pairs with a PSR-18 implementation (Guzzle 7 satisfies PSR-18 directly) for transport, symfony/event-dispatcher for lifecycle hooks, and Laravel's container for per-service client bindings. It sits naturally behind a repository/gateway interface, so domain code depends on our interface, not on generated classes.
Migration path. Treat it as a strangler-fig replacement:
Compatibility. Verify the PHP constraint against the runtime image, Laravel version (service-provider and config-publishing APIs are stable across 10/11/12), and the Guzzle/PSR-18 adapter version. Pin the generator and library versions in composer.lock; regeneration must be reproducible. Keep generated code in a dedicated namespace/directory so it is excluded from coverage and static-analysis baselines.
Sequencing.
generate script, committed output or build artifact, with a drift check that fails the build if regeneration produces a diff.Maintenance. Recurring cost concentrates in three places: (a) regenerating and reviewing clients when a vendor WSDL changes, (b) the bespoke glue layer (providers, config, middleware, exception mapping) that no upstream package will maintain for us, and (c) dependency churn — laminas/laminas-code, Symfony EventDispatcher, and PSR adapter updates flow through composer.lock and need periodic, low-drama upgrades. Budget a standing fraction of one engineer for a multi-endpoint integration; a single stable endpoint is near-zero after the pilot.
Support. Upstream support is best-effort by a small maintainer group. Realistic escalation model: internal owner for the glue layer and generated code; upstream GitHub issues only for genuine library bugs; the SOAP provider is the escalation path for schema and fault semantics. Make WSDL change notification a contractual line item with the vendor — the absence of that clause is the single most common cause of unplanned outage in SOAP integrations.
Scaling. Throughput is bounded by the remote service, not by this library; keep-alive and connection reuse come from the underlying PSR-18 client. Real constraints to plan for: WSDL/XSD parsing is CPU- and memory-heavy — cache parsed metadata and never fetch the WSDL at request time in production; large responses can breach memory_limit, so stream or paginate where the provider allows; bulk operations should run on queues with explicit concurrency limits and idempotency keys, because SOAP endpoints rarely tolerate retry storms.
Failure modes to instrument and alert on.
Ramp-up. Expect one to two weeks for a competent Laravel developer unfamiliar with SOAP to become productive, and longer to become confident with WS-Security. The friction is conceptual, not syntactic: developers must learn to read WSDL/XSD, understand envelope structure and faults, and accept that generated classes are build artifacts rather than hand-edited code. Mitigate with a runbook covering "how to regenerate," "how to add an endpoint," "how to read a SOAP fault," a recorded-request testing pattern, and a code-owners entry for the generated namespace so review expectations are explicit.
How can I help you explore Laravel packages today?