Александр Некрасов · Автономное руководство

PHP: полный мануал с примерами, функциями и ООП

Разделы этой страницы
  1. SOAP в PHP: полный справочник клиента, сервера, WSDL, типов и ошибок
  2. SOAP без профессиональной деформации: от заказа к Envelope и обратно
  3. Маршрут от задачи
  4. Установка и конфигурация как четыре проверяемых слоя
  5. Требования: libxml, поддерживаемый SOAP/WSDL и доступность всех импортов
  6. Установка ext/soap: включить в том процессе, который обслуживает код
  7. Runtime configuration и WSDL cache без магических очисток
  8. Все 81 предопределённая константа: категории, значение и место применения
  9. Полное дерево функций и методов официального book.soap
  10. SoapClient: договор, состояние, transport и диагностика
  11. SoapServer: узкий endpoint вместо файла со случайно экспортированными функциями
  12. SoapFault: машинный код, безопасное сообщение и отдельный внутренний лог
  13. SoapHeader: бизнес-метаданные внутри Envelope, а не HTTP-заголовок
  14. SoapParam: имя аргумента для serializer, особенно без WSDL
  15. SoapVar: значение с явным XSD-типом, именем и namespace
  16. Soap\Sdl: непрозрачное внутреннее представление WSDL с PHP 8.4
  17. Soap\Url: непрозрачный transport URL object с PHP 8.4
  18. Функции и методы этой темы
  19. Код и руководство с собой
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 115 · От первого вызова до эксплуатации

SOAP в PHP: полный справочник клиента, сервера, WSDL, типов и ошибок

От первого локального Envelope до WSDL-клиента, production endpoint, SOAP Fault, headers, типизации, cache и диагностики. Полная официальная ветвь book.soap с 46 узлами и практическим маршрутом.

SOAP без профессиональной деформации: от заказа к Envelope и обратно

Осязаемая цель. Есть старый сервис перевозчика, банка или ERP: он принимает XML Envelope, выполняет операцию и возвращает XML/Fault. После первой главы вы сможете вызвать sum одной строкой, увидеть реальный request/response и понять, где искать сбой: в PHP-значении, SOAP XML, HTTP или удалённой логике.

Один вызов без магии
  1. PHP: массив/объект параметров заказа.
  2. Serializer: WSDL/XSD превращает значения в Envelope.
  3. HTTP transport: POST уходит на endpoint.
  4. SoapServer: выбирает handler и выполняет его.
  5. Ответ: Envelope превращается в scalar/object либо SoapFault.

Граница модели. Стрелки показывают логические слои, а не отдельные процессы: клиент и сервер могут находиться на разных машинах, а WSDL может загружаться до первого вызова и кэшироваться. SOAP не «вызывает PHP-функцию через интернет» напрямую: между ними остаются XML, HTTP и договор.

Маршрут от задачи

Если вам нужноС чего начатьЧто проверить следующим
Подключиться к готовому WSDLSoapClient::__constructSoapClient::__getFunctions и SoapClient::__getTypes
Отправить одну операциюSoapClient::__soapCallSoapClient::__getLastRequest и обработка Fault
Добавить auth/correlation headerSoapHeader::__constructSoapClient::__setSoapHeaders
Опубликовать PHP endpointSoapServer::__constructSoapServer::addFunction/SoapServer::setClass → SoapServer::handle
Объяснить «Could not connect»SoapClient::__getLastRequestHeadersразделение WSDL download, DNS/TLS/connect/read timeout и call
Сохранить состояние между callsSoapServer::setPersistenceSoapClient::__getCookies и session boundary

Установка и конфигурация как четыре проверяемых слоя

Чтобы пример заработал, нужны четыре независимых слоя. Ошибка «SOAP не работает» без указания слоя ничего не диагностирует.

СлойЧто даётКак проверить
PHP/SAPIЗапускает код CLI/FPM/Apache.PHP_VERSION; CLI и web могут читать разные ini.
ext/soapSoapClient/SoapServer/value objects.extension_loaded("soap").
libxml/XMLРазбор WSDL/XSD/Envelope.extension_loaded("libxml"); valid XML/import paths.
Сеть/endpointDNS, TLS, proxy, connect/read.Отдельно получить WSDL и отдельно вызвать operation; сравнить окружения.
Правильный порядок диагностики
  1. Проверить extension в том же SAPI.
  2. Загрузить главный WSDL и все imports.
  3. Получить список operations/types.
  4. Сделать локальный loopback call.
  5. Только затем проверять удалённый endpoint/auth/TLS.

Требования: libxml, поддерживаемый SOAP/WSDL и доступность всех импортов

Официальное расширение опирается на libxml и поддерживает подмножества SOAP 1.1, SOAP 1.2 и WSDL 1.1. «Подмножество» означает: конкретный vendor contract надо прогнать на выбранной версии PHP; одной надписи WSDL 1.1 недостаточно.

  • XML well-formedness: namespace URI, QName и encoding значимы; красивый префикс ns1 — нет.
  • WSDL/XSD reachability: главный файл может импортировать другие схемы с отдельными URL/TLS/DNS.
  • Transport: ext/soap выполняет HTTP; firewall, proxy, SELinux/container policy живут вне WSDL.
  • Contract data: minOccurs/maxOccurs, nillable, wrapper style и fault messages важнее PHP var_dump.

Перед интеграцией запросите у поставщика версию WSDL, test endpoint, тестовые credentials, sample request/response, список faults, timeout/rate-limit/idempotency policy и правила изменения контракта.

Установка ext/soap: включить в том процессе, который обслуживает код

В Windows DLL уже входит в локальный PHP 8.5.11 этого проекта. Для изоляции она загружается только в дочернем процессе: php -d extension=/absolute/path/php_soap.dll script.php. Общий php.ini и публичный сайт не меняются.

СредаУстановка/включениеПосле изменения
Сборка PHP из исходников./configure --with-libxml --enable-soap ..., затем обычные make/install шаги вашей сборки.Проверить build flags и php -m.
Debian / Ubuntu packageapt install php-soap либо versioned пакет вроде php8.5-soap, если он есть в выбранном repository.Перезапустить нужный PHP-FPM pool или Apache; CLI перечитывает ini при новом запуске.
RHEL / Fedora packagednf install php-soap из repository, совместимого с установленным PHP.Перезапустить FPM или Apache и проверить модуль через web SAPI.
Windows ZIP PHPУбедиться, что есть ext/php_soap.dll, и добавить extension=soap в ini конкретного SAPI.Новый CLI process; для Apache/FastCGI — restart соответствующего процесса.
ПроверкаКоманда/кодОжидаемый смысл
Модуль загрузилсяphp -d extension=php_soap.dll -mВ списке есть soap.
Версия совпалаphpversion("soap")На стенде 8.5.11.
Классы доступныclass_exists(SoapClient::class)true в том же процессе.
CLI iniphp --iniПуть CLI может отличаться от FPM/Apache.
FPM / Apache SAPIphp_ini_loaded_file() и extension_loaded("soap") в закрытом healthcheckНе полагаться на успешный CLI, если запрос обслуживает другой SAPI.

Runtime configuration и WSDL cache без магических очисток

WSDL cache сохраняет разобранный контракт, а не ответы операций. Поэтому «операция старая» после deploy может быть cache issue, а «медленный call» после быстрого конструктора — уже endpoint/transport issue.

INIТипDocumented defaultChangeabilityЛокальное 8.5.11Договор
soap.wsdl_cache_enabledint1INI_ALL1Главный переключатель WSDL cache.
soap.wsdl_cache_dirstring/tmpINI_ALL/tmpКаталог disk cache; web process должен иметь безопасные права.
soap.wsdl_cache_ttlint86400INI_ALL86400Срок записи в секундах; 86400 = сутки.
soap.wsdl_cacheint1INI_ALL1Стратегия: 0 none, 1 disk, 2 memory, 3 both.
soap.wsdl_cache_limitint5INI_ALL5Максимум in-memory WSDL entries.

INI_ALL означает, что значение можно менять на уровнях, допускаемых PHP INI_ALL, включая runtime через ini_set(). Это не делает изменение безопасным посреди long-lived worker: cache policy должна быть предсказуемой для всего процесса.

СредаРазумная политика
Разработка меняющегося WSDLcache_wsdl=WSDL_CACHE_NONE на клиенте либо короткий контролируемый TTL; не удалять чужие cache files.
Production immutable/versioned WSDLDisk/memory cache уменьшает download/parse; обновление проходит отдельным deploy/contract test.
Long-lived workerMemory cache живёт с process; после смены WSDL нужен lifecycle/restart согласно deploy policy.
Несколько tenants/contractsУчитывать cache key, URL, credentials/imports; не выдавать один контракт за другой.

Все 81 предопределённая константа: категории, значение и место применения

Константа — подписанное значение для options/serializer. Совпавшие числа не делают константы взаимозаменяемыми: SOAP_1_1 и SOAP_RPC равны 1, но отвечают на разные вопросы.

КонстантаЗначение 8.5.11КатегорияГде применяется
SOAP_1_11ВерсияВыбор SOAP 1.1/1.2 в options клиента или сервера.
SOAP_1_22ВерсияВыбор SOAP 1.1/1.2 в options клиента или сервера.
SOAP_PERSISTENCE_SESSION1Состояние сервераRequest или PHP-session lifecycle объекта setClass.
SOAP_PERSISTENCE_REQUEST2Состояние сервераRequest или PHP-session lifecycle объекта setClass.
SOAP_FUNCTIONS_ALL999ЭкспортDeprecated с PHP 8.4: используйте явный массив имён функций.
SOAP_ENCODED1BindingStyle/use SOAP binding; в WSDL-mode берётся из контракта.
SOAP_LITERAL2BindingStyle/use SOAP binding; в WSDL-mode берётся из контракта.
SOAP_RPC1BindingStyle/use SOAP binding; в WSDL-mode берётся из контракта.
SOAP_DOCUMENT2BindingStyle/use SOAP binding; в WSDL-mode берётся из контракта.
SOAP_ACTOR_NEXT1Роли HeaderПредопределённая роль/actor для обработки SOAP Header.
SOAP_ACTOR_NONE2Роли HeaderПредопределённая роль/actor для обработки SOAP Header.
SOAP_ACTOR_UNLIMATERECEIVER3Роли HeaderПредопределённая роль/actor для обработки SOAP Header.
SOAP_COMPRESSION_ACCEPT32HTTP compressionКомбинируется в option compression; уровень 1–9 добавляется отдельно.
SOAP_COMPRESSION_GZIP0HTTP compressionКомбинируется в option compression; уровень 1–9 добавляется отдельно.
SOAP_COMPRESSION_DEFLATE16HTTP compressionКомбинируется в option compression; уровень 1–9 добавляется отдельно.
SOAP_AUTHENTICATION_BASIC0HTTP authBasic/Digest authentication transport, не SOAP Header.
SOAP_AUTHENTICATION_DIGEST1HTTP authBasic/Digest authentication transport, не SOAP Header.
UNKNOWN_TYPE999998SOAP encodingНизкоуровневый идентификатор типа encoded-модели.
XSD_STRING101XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_BOOLEAN102XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_DECIMAL103XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_FLOAT104XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_DOUBLE105XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_DURATION106XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_DATETIME107XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_TIME108XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_DATE109XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_GYEARMONTH110XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_GYEAR111XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_GMONTHDAY112XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_GDAY113XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_GMONTH114XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_HEXBINARY115XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_BASE64BINARY116XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_ANYURI117XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_QNAME118XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NOTATION119XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NORMALIZEDSTRING120XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_TOKEN121XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_LANGUAGE122XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NMTOKEN123XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NAME124XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NCNAME125XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_ID126XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_IDREF127XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_IDREFS128XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_ENTITY129XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_ENTITIES130XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_INTEGER131XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NONPOSITIVEINTEGER132XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NEGATIVEINTEGER133XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_LONG134XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_INT135XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_SHORT136XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_BYTE137XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NONNEGATIVEINTEGER138XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_UNSIGNEDLONG139XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_UNSIGNEDINT140XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_UNSIGNEDSHORT141XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_UNSIGNEDBYTE142XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_POSITIVEINTEGER143XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_NMTOKENS144XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_ANYTYPE145XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_ANYXML147XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
APACHE_MAP200SOAP encodingНизкоуровневый идентификатор типа encoded-модели.
SOAP_ENC_OBJECT301SOAP encodingНизкоуровневый идентификатор типа encoded-модели.
SOAP_ENC_ARRAY300SOAP encodingНизкоуровневый идентификатор типа encoded-модели.
XSD_1999_TIMEINSTANT401Legacy XSDУстаревший XML Schema 1999 namespace/type для совместимости старых сервисов.
XSD_NAMESPACE'http://www.w3.org/2001/XMLSchema'XSD typeИдентификатор XML Schema типа для SoapVar/serializer.
XSD_1999_NAMESPACE'http://www.w3.org/1999/XMLSchema'Legacy XSDУстаревший XML Schema 1999 namespace/type для совместимости старых сервисов.
SOAP_SINGLE_ELEMENT_ARRAYS1FeaturesБитовый feature flag SoapClient/SoapServer.
SOAP_WAIT_ONE_WAY_CALLS2FeaturesБитовый feature flag SoapClient/SoapServer.
SOAP_USE_XSI_ARRAY_TYPE4FeaturesБитовый feature flag SoapClient/SoapServer.
WSDL_CACHE_NONE0WSDL cacheСтратегия none/disk/memory/both для разбора WSDL.
WSDL_CACHE_DISK1WSDL cacheСтратегия none/disk/memory/both для разбора WSDL.
WSDL_CACHE_MEMORY2WSDL cacheСтратегия none/disk/memory/both для разбора WSDL.
WSDL_CACHE_BOTH3WSDL cacheСтратегия none/disk/memory/both для разбора WSDL.
SOAP_SSL_METHOD_TLS0Legacy TLSКонстанта deprecated option ssl_method; используйте stream_context/современный TLS.
SOAP_SSL_METHOD_SSLv21Legacy TLSКонстанта deprecated option ssl_method; используйте stream_context/современный TLS.
SOAP_SSL_METHOD_SSLv32Legacy TLSКонстанта deprecated option ssl_method; используйте stream_context/современный TLS.
SOAP_SSL_METHOD_SSLv233Legacy TLSКонстанта deprecated option ssl_method; используйте stream_context/современный TLS.

Полное дерево функций и методов официального book.soap

Это полный вызываемый API текущей официальной ветви: 31 страница. Дерево идёт по категориям и ведёт в карточки с сигнатурой, двумя выполненными сценариями, отказами и связанными операциями.

Две функции расширения
SoapClient — 14 методов
SoapServer — 10 методов
SoapFault — 2 метода
SoapHeader / SoapParam / SoapVar

Как выбирать: новичок идёт по маршруту задачи в начале главы; опытный разработчик раскрывает это дерево и сразу переходит к карточке. Оба пути ведут к одному и тому же проверенному материалу.

SoapClient: договор, состояние, transport и диагностика

SoapClient — stateful adapter вокруг WSDL mapping, transport settings, cookies/default headers и последнего trace. Один настроенный объект уменьшает повтор настройки, но его состояние нельзя случайно делить между чужими пользователями.

Жизнь клиента
  1. Конструктор загружает/кэширует WSDL и options.
  2. Вызов получает PHP args.
  3. Serializer создаёт XML.
  4. __doRequest выполняет transport.
  5. Decoder возвращает value/Fault.
  6. Cookie/trace state остаётся в объекте.
OptionЧто контролирует
locationEndpoint URL; обязателен без WSDL, с WSDL переопределяет soap:address.
uriTarget namespace; обязателен без WSDL, игнорируется WSDL-mode.
styleSOAP_RPC или SOAP_DOCUMENT; в WSDL-mode берётся из binding.
useSOAP_ENCODED или SOAP_LITERAL; в WSDL-mode берётся из binding.
soap_versionSOAP_1_1 по умолчанию либо SOAP_1_2.
authenticationSOAP_AUTHENTICATION_BASIC или SOAP_AUTHENTICATION_DIGEST для HTTP auth.
loginUsername HTTP Basic/Digest.
passwordPassword HTTP Basic/Digest; не путать с passphrase certificate.
local_certPEM client certificate/private key для mutual TLS; файл защищают правами.
passphrasePassphrase private key из local_cert.
proxy_hostHostname HTTP proxy.
proxy_portTCP port proxy; нужен вместе с proxy_host.
proxy_loginUsername Basic auth на proxy.
proxy_passwordPassword Basic auth на proxy.
compressionACCEPT + GZIP/DEFLATE + уровень 1–9.
encodingВнутренняя кодировка PHP values; wire request остаётся UTF-8.
traceСохранять последний request/response и HTTP headers.
classmapWSDL type → fully-qualified PHP class; с PHP 8.4 доступна Clark notation.
typemaptype_name/type_ns + from_xml/to_xml callbacks.
exceptionstrue бросает SoapFault, false возвращает SoapFault object.
connection_timeoutТолько connect timeout seconds; не общий deadline ответа.
cache_wsdlWSDL_CACHE_NONE/DISK/MEMORY/BOTH.
user_agentHTTP User-Agent интеграции.
stream_contextTLS/HTTP context; не отключать verification как постоянное решение.
featuresБитовые SOAP_SINGLE_ELEMENT_ARRAYS/WAIT_ONE_WAY_CALLS/USE_XSI_ARRAY_TYPE.
keep_aliveHTTP connection reuse; lifecycle клиента должен соответствовать worker/очереди.
ssl_methodDeprecated с PHP 8.1; SOAP_SSL_METHOD_TLS не влияет на выбор протокола с PHP 7.2. Применять современную TLS настройку stream_context.
Все private properties из официального synopsis PHP 8.5.11

Это видимое описание внутреннего состояния, а не разрешение читать свойства: они private и могут меняться. Public API приведён выше.

Property из synopsisVisibilityТип 8.5.11DefaultВнутренняя рольИстория
$uriprivate?stringnullcontract/mappingБез отдельной записи changelog в frozen class page.
$styleprivate?intnullcontract/mappingБез отдельной записи changelog в frozen class page.
$useprivate?intnullcontract/mappingБез отдельной записи changelog в frozen class page.
$locationprivate?stringnullcontract/mappingБез отдельной записи changelog в frozen class page.
$traceprivateboolfalseinternal stateБез отдельной записи changelog в frozen class page.
$compressionprivate?intnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$sdlprivate?Soap\Sdlnullcontract/mappingPHP 8.4: Soap\Sdl object заменил внутренний resource.
$typemapprivate?arraynullcontract/mappingPHP 8.4: array; раньше внутренний resource.
$httpsocketprivateresource|mixednulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$httpurlprivate?Soap\Urlnulltransport/TLS/proxyPHP 8.4: Soap\Url object заменил внутренний resource.
$_loginprivate?stringnullHTTP authБез отдельной записи changelog в frozen class page.
$_passwordprivate?stringnullHTTP authБез отдельной записи changelog в frozen class page.
$_use_digestprivateboolfalseHTTP authБез отдельной записи changelog в frozen class page.
$_digestprivate?stringnullHTTP authБез отдельной записи changelog в frozen class page.
$_proxy_hostprivate?stringnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_proxy_portprivate?intnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_proxy_loginprivate?stringnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_proxy_passwordprivate?stringnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_exceptionsprivatebooltruefault/traceБез отдельной записи changelog в frozen class page.
$_encodingprivate?stringnullcontract/mappingБез отдельной записи changelog в frozen class page.
$_classmapprivate?arraynullcontract/mappingБез отдельной записи changelog в frozen class page.
$_featuresprivate?intnullcontract/mappingБез отдельной записи changelog в frozen class page.
$_connection_timeoutprivateint0transport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_stream_contextprivateresource|mixednulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_user_agentprivate?stringnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_keep_aliveprivatebooltruetransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_ssl_methodprivate?intnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_soap_versionprivateintНет class default; значение устанавливает конструктор/runtime.contract/mappingБез отдельной записи changelog в frozen class page.
$_use_proxyprivate?intnulltransport/TLS/proxyБез отдельной записи changelog в frozen class page.
$_cookiesprivatearray[]cookies/default headersБез отдельной записи changelog в frozen class page.
$__default_headersprivate?arraynullcookies/default headersБез отдельной записи changelog в frozen class page.
$__soap_faultprivate?SoapFaultnullfault/traceБез отдельной записи changelog в frozen class page.
$__last_requestprivate?stringnullfault/traceБез отдельной записи changelog в frozen class page.
$__last_responseprivate?stringnullfault/traceБез отдельной записи changelog в frozen class page.
$__last_request_headersprivate?stringnullfault/traceБез отдельной записи changelog в frozen class page.
$__last_response_headersprivate?stringnullfault/traceБез отдельной записи changelog в frozen class page.

Основные карточки: SoapClient::__construct, SoapClient::__soapCall, SoapClient::__getLastRequest, SoapClient::__doRequest.

SoapServer: узкий endpoint вместо файла со случайно экспортированными функциями

SoapServer — dispatcher: он не содержит бизнес-логику магазина, а связывает Envelope с узким набором PHP handlers. Полезный выигрыш — единая сериализация/fault contract и явная поверхность операций.

Модель handlerКогда выбиратьГраница
SoapServer::addFunctionНесколько маленьких stateless операций.Только явный allowlist; не SOAP_FUNCTIONS_ALL.
SoapServer::setClassСвязанные методы и создаваемый handler.Публичные методы; constructor args; optional session persistence.
SoapServer::setObjectУже собранный object/dependencies/test double.State текущего process/request; session persistence не обещана.
Один request
  1. HTTP route не печатает лишний output.
  2. handle разбирает Envelope.
  3. Registry выбирает handler.
  4. Return/Header/Fault сериализуются.
  5. HTTP layer пишет status/headers/log.
Private property из официального synopsis
Property из synopsisVisibilityТип 8.5.11DefaultВнутренняя рольИстория
$__soap_faultprivate?SoapFaultnullfault/traceБез отдельной записи changelog в frozen class page.

SoapFault: машинный код, безопасное сообщение и отдельный внутренний лог

SoapFault одновременно является SOAP-структурой и PHP Exception. Это мост между remote fault contract и локальным try/catch, но поля надо переводить в политику приложения осознанно.

СвойствоVisibilityТип 8.5.11DefaultНазначениеИстория
$faultstringpublicstringНет class default; значение устанавливает конструктор/runtime.Человекочитаемое SOAP fault message.Без отдельной записи changelog в frozen class page.
$faultcodepublic?stringnullМашинный code/local name либо null.Без отдельной записи changelog в frozen class page.
$faultcodenspublic?stringnullNamespace URI fault code, если code задан QName-массивом.Без отдельной записи changelog в frozen class page.
$faultactorpublic?stringnullURI actor/node, сообщившего ошибку.Без отдельной записи changelog в frozen class page.
$detailpublicmixednullДополнительные структурированные детали Fault.Без отдельной записи changelog в frozen class page.
$_namepublic?stringnullИмя WSDL fault binding, если оно выбрано.Без отдельной записи changelog в frozen class page.
$headerfaultpublicmixednullДанные Fault, относящиеся к SOAP Header.Без отдельной записи changelog в frozen class page.
$langpublicstring''Язык SOAP 1.2 reason; exact PHP 8.5.11 caveat разобран в карточке конструктора.Свойство добавлено в PHP 8.5.

Унаследованный API Exception

Поскольку SoapFault extends Exception, у него есть protected свойства $message (default ""), $code (default 0), $file (default "") и $line (default 0). Их не читают напрямую снаружи: используют final public методы getMessage(), getCode(), getFile(), getLine(), getTrace(), getTraceAsString() и getPrevious(). SoapFault::__toString() переопределяет строковое представление Fault. Visibility и default здесь важны: они объясняют, почему $fault->message не является корректным внешним контрактом.

СлойРеакция
Неверные данные запросаClient/Sender/domain fault; не повторять без исправления.
Временная зависимостьServer/Receiver; retry только если операция idempotent и есть bounded backoff.
Auth/permissionНе печатать credentials; различать HTTP auth и SOAP business fault.
Parser/WSDL mismatchПроверить contract/cache/imports и фактический XML.

Карточки: SoapFault::__construct, SoapFault::__toString, is_soap_fault.

SoapHeader: бизнес-метаданные внутри Envelope, а не HTTP-заголовок

SOAP Header находится внутри XML Envelope. HTTP Header находится перед body. Одинаковое слово «header» не делает их одним механизмом: Basic auth/User-Agent/Cookie живут в HTTP, Credentials/RequestId по SOAP-договору — в Envelope.

СвойствоVisibilityТип 8.5.11DefaultНазначениеИстория
$namespacepublicstringНет class default; значение устанавливает конструктор/runtime.URI namespace элемента Header.Без отдельной записи changelog в frozen class page.
$namepublicstringНет class default; значение устанавливает конструктор/runtime.Local name элемента Header.Без отдельной записи changelog в frozen class page.
$datapublicmixednullPHP-значение/SoapVar для содержимого элемента.Без отдельной записи changelog в frozen class page.
$mustUnderstandpublicboolНет class default; значение устанавливает конструктор/runtime.Требование обязательной обработки получателем.Без отдельной записи changelog в frozen class page.
$actorpublicstring|int|nullНет class default; значение устанавливает конструктор/runtime.Роль/actor, для которой предназначен Header.Без отдельной записи changelog в frozen class page.
Как QName становится XML
  1. namespace URI + name задают смысл элемента.
  2. data превращается в дочерние узлы/значение.
  3. Serializer сам выбирает префикс.
  4. mustUnderstand/actor задают обязательность и роль.

Создание: SoapHeader::__construct; клиент: SoapClient::__setSoapHeaders; сервер: SoapServer::addSoapHeader.

SoapParam: имя аргумента для serializer, особенно без WSDL

В non-WSDL mode обычное значение может получить имя param0, которое не узнает сервис. SoapParam явно говорит serializer: значение 731 относится к аргументу orderId.

СвойствоVisibilityТип 8.5.11DefaultНазначениеИстория
$param_namepublicstringНет class default; значение устанавливает конструктор/runtime.Имя аргумента операции в XML.Без отдельной записи changelog в frozen class page.
$param_datapublicmixedНет class default; значение устанавливает конструктор/runtime.PHP-значение аргумента.Без отдельной записи changelog в frozen class page.
Именованный параметр
  1. PHP value 731.
  2. SoapParam(data=731, name=orderId).
  3. XML 731.
  4. Удалённый handler сопоставляет имя.

Подробный выполненный пример: SoapParam::__construct. В WSDL-mode сначала доверяйте корректному контракту; ручная обёртка не лечит неверную wrapper structure.

SoapVar: значение с явным XSD-типом, именем и namespace

SoapVar нужен, когда одного PHP-типа мало: бинарная строка должна стать xsd:base64Binary, DateTime — xsd:dateTime, объект — конкретным QName. Он хранит value плюс metadata сериализации.

СвойствоVisibilityТип 8.5.11DefaultНазначениеИстория
$enc_typepublicintНет class default; значение устанавливает конструктор/runtime.Numeric XSD_/SOAP_ENC_ encoding id.Без отдельной записи changelog в frozen class page.
$enc_valuepublicmixednullИсходное PHP-значение.Без отдельной записи changelog в frozen class page.
$enc_stypepublic?stringnullЯвное имя XSD-типа либо null.Без отдельной записи changelog в frozen class page.
$enc_nspublic?stringnullNamespace URI явного XSD-типа.Без отдельной записи changelog в frozen class page.
$enc_namepublic?stringnullLocal name XML-узла.Без отдельной записи changelog в frozen class page.
$enc_namenspublic?stringnullNamespace URI XML-узла.Без отдельной записи changelog в frozen class page.
Явный тип
  1. PHP value/bytes/object.
  2. encoding выбирает XSD_/SOAP_ENC_.
  3. type/name namespaces задают QName.
  4. Serializer создаёт lexical XML form.

Карточка с dateTime и binary: SoapVar::__construct.

Soap\Sdl: непрозрачное внутреннее представление WSDL с PHP 8.4

Soap\Sdl — final fully opaque class, которая с PHP 8.4 заменила внутренний resource soap_sdl. У неё нет публичного конструктора, методов и свойств для прикладного кода.

МожноНельзя/не следует
Увидеть тип через Reflection/внутреннее состояние SoapClient.Создавать напрямую или читать разобранный WSDL через private internals.
Учитывать при диагностике type changes PHP 8.4.Сериализовать/хранить как свой domain object.
Использовать public __getFunctions/__getTypes.Полагаться на layout opaque object между версиями.

Практический public API для этой задачи: SoapClient::__getFunctions и SoapClient::__getTypes.

Soap\Url: непрозрачный transport URL object с PHP 8.4

Soap\Url — final fully opaque class, которая с PHP 8.4 заменила внутренний resource soap_url. Она обслуживает внутренний URL state transport и не является альтернативой parse_url/URI API приложения.

Практическая задачаPublic путь
Задать endpointSoapClient::__construct option location или SoapClient::__setLocation
Переопределить endpoint одного callSoapClient::__soapCall option location
Особо разобрать redirect URI в PHP 8.5SoapClient::__doRequest параметр uriParserClass
Защититься от SSRFAllowlist scheme/host/port до передачи URL; opaque class этого не делает.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

is_soap_faultПроверяет, является ли результат объектом SoapFault; нужен прежде всего для режима клиента <code>exceptions=false</code>.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

function is_soap_fault(mixed $object): bool

Проверяет, является ли результат объектом SoapFault; нужен прежде всего для режима клиента exceptions=false.

Функция и документированная запись. function is_soap_fault(mixed $object): bool. Reflection PHP 8.5.11: is_soap_fault(mixed $object): bool. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
mixed $objectПроверяемое значение либо конкретный объект-обработчик — смысл зависит от операции; тип указан в сигнатуре.

Возврат и договор. Возвращает true только для SoapFault, иначе false. Значение не меняется.

Отказ. Сама функция не делает HTTP-запрос и не выбрасывает Fault. Ошибка возникает раньше, при SOAP-вызове; при exceptions=true нужен catch (SoapFault $fault).

Путь данных именно этого вызова
  1. Код получает результат SOAP-вызова.
  2. PHP проверяет класс объекта.
  3. Ветка ошибки читает faultcode/faultstring, успешная — полезные данные.
Отличить SOAP Fault от обычного результатаСамостоятельный пример
<?php
declare(strict_types=1);

$ok = (object) ['status' => 'paid'];
$fault = new SoapFault('Server', 'Склад временно недоступен');

echo is_soap_fault($ok) ? "fault\n" : "result\n";
echo is_soap_fault($fault) ? "fault\n" : "result\n";
Ожидаемый результат
result
fault

Проверка не анализирует строку и не считает любой Exception SOAP-ошибкой: она отвечает, является ли значение именно SoapFault. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Обработать Fault, когда exceptions отключеныСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(
    manualSoapFault('Server', 'Товар не найден'),
    null,
    ['exceptions' => false],
);
$result = $client->__soapCall('findProduct', [['sku' => 'NO-404']]);

if (is_soap_fault($result)) {
    echo "fault: {$result->faultstring}\n";
} else {
    echo "product received\n";
}
Ожидаемый результат
fault: Товар не найден

При exceptions=false не сработает catch: Fault приходит как возвращаемый объект, поэтому проверка должна стоять сразу после вызова. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Не смешивайте два режима обработки: либо exceptions=true и catch, либо exceptions=false и обязательный is_soap_fault после каждого вызова. Молчаливое чтение результата без проверки превращает faultstring в «данные».

Связанные операции: SoapFault::__construct, SoapClient::__soapCall.

use_soap_error_handlerПереключает специальный обработчик ошибок SoapServer и возвращает его прежнее состояние.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

function use_soap_error_handler(bool $enable = true): bool

Переключает специальный обработчик ошибок SoapServer и возвращает его прежнее состояние.

Функция и документированная запись. function use_soap_error_handler(bool $enable = true): bool. Reflection PHP 8.5.11: use_soap_error_handler(bool $enable = true): bool. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
bool $enable = truetrue включает преобразование PHP-ошибок обработчика в SOAP Fault, false возвращает обычный PHP error handler.

Возврат и договор. Возвращает прежнее булево состояние. true позволяет SoapServer оформить PHP-ошибку как SOAP Fault; это не заменяет логирование и безопасную политику send_errors.

Отказ. Неверный тип аргумента даёт TypeError. Ошибка вне обработки SoapServer не превращается этой функцией в SOAP-ответ.

Путь данных именно этого вызова
  1. Приложение сохраняет прежний режим.
  2. SoapServer выполняет обработчик запроса.
  3. PHP-ошибка превращается в Fault либо идёт обычному PHP handler.
  4. После ограниченного участка режим восстанавливают.
Временно изменить SOAP error handler и восстановить настройкуСамостоятельный пример
<?php
declare(strict_types=1);

$initial = use_soap_error_handler(false);
$previous = use_soap_error_handler(true);
echo $previous === false ? "до включения: обычный handler\n" : "unexpected\n";
use_soap_error_handler($initial);
echo "настройка восстановлена\n";
Ожидаемый результат
до включения: обычный handler
настройка восстановлена

Функция возвращает прошлое значение, поэтому библиотека может аккуратно восстановить окружение после локального опыта или теста. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Скрыть внутреннюю PHP-ошибку за безопасным SOAP FaultСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';

function loadWarehouse(): string
{
    missing_inventory_driver(); // намеренная ошибка учебного обработчика
    return 'never';
}

use_soap_error_handler(true);
$server = new SoapServer(null, ['uri' => 'urn:manual', 'send_errors' => false]);
$server->addFunction('loadWarehouse');
$xml = manualHandle($server, manualSoapRequest('loadWarehouse', []));
echo manualXmlValue($xml, 'faultstring'), "\n";
Ожидаемый результат
Internal Error

SOAP handler превращает фатальную ошибку в корректный Envelope. send_errors=false не выдаёт клиенту имя внутренней функции; подробности пишут в закрытый журнал процесса. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. В production не включайте выдачу внутренних сообщений только ради диагностики. Сочетайте SOAP Fault для клиента с серверным журналом и correlation id.

Связанные операции: SoapServer::handle, SoapServer::fault.

SoapFault::__constructСоздаёт стандартную SOAP-ошибку для ответа сервера или локального представления fault от клиента.

PHP 5+; параметр $lang добавлен в PHP 8.5 · soap; XML/libxml; HTTP transport for real remote calls

SoapFault::__construct( array|string|null $code, string $string, ?string $actor = null, mixed $details = null, ?string $name = null, mixed $headerFault = null, string $lang = "" )

Создаёт стандартную SOAP-ошибку для ответа сервера или локального представления fault от клиента.

Метод и документированная запись. SoapFault::__construct( array|string|null $code, string $string, ?string $actor = null, mixed $details = null, ?string $name = null, mixed $headerFault = null, string $lang = "" ). Reflection PHP 8.5.11: SoapFault::__construct(array|string|null $code, string $string, ?string $actor = null, mixed $details = null, ?string $name = null, mixed $headerFault = null, string $lang = ""). Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
array|string|null $codeSOAP fault code. Для SOAP 1.1 обычно Client/Server, для SOAP 1.2 — соответствующий QName/код договора.
string $stringБезопасное клиентское описание ошибки без трассировки, SQL и секретов.
?string $actor = nullURI участника/роли, который создал или должен обработать header/fault; null/пустая строка оставляют значение неуказанным.
mixed $details = nullСтруктурированные дополнительные сведения Fault; не включайте внутренние секреты и stack trace.
?string $name = nullИмя удалённой операции, cookie, fault binding или XML-узла — точный смысл задаёт текущий метод.
mixed $headerFault = nullДанные ошибки SOAP Header при специальном WSDL-контракте.
string $lang = ''Язык текста Fault для SOAP 1.2, например ru; параметр добавлен в PHP 8.5.

Возврат и договор. Создаёт объект SoapFault; конструктор ничего не отправляет. Публичные поля faultcode, faultstring, faultactor, detail, headerfault и lang доступны после создания.

Отказ. Неверные PHP-типы дают TypeError. Пустой строковый code либо QName-массив не ровно из двух строк [namespace, localCode] даёт ValueError «not a valid fault code». Секреты в details окажутся в XML-ответе, если сервер сериализует fault.

Путь данных именно этого вызова
  1. Код выбирает машинный fault code.
  2. Добавляет безопасное сообщение и при необходимости detail.
  3. SoapServer сериализует объект либо приложение ловит его как Exception.
Создать предметную ошибку заказа с деталямиСамостоятельный пример
<?php
declare(strict_types=1);

$fault = new SoapFault(
    ['urn:shop', 'OrderRejected'],
    'Order cannot be confirmed',
    'urn:shop:checkout',
    ['orderId' => 731, 'reason' => 'stock'],
    'OrderFault',
    null,
    'ru',
);
echo $fault->faultcode, "\n";
echo $fault->faultstring, "\n";
echo $fault->detail['orderId'], ' / ', $fault->lang, "\n";
Ожидаемый результат
OrderRejected
Order cannot be confirmed
731 / en

QName-код, понятное сообщение и structured detail отделяют машинный договор от текста. В PHP 8.5.11 аргумент lang у прямого SoapFault::__construct разбирается, но exact source всё ещё записывает en; для реально сериализованного SOAP 1.2 Reason используйте проверенный SoapServer::fault и contract test. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Поймать SoapFault как исключение и выбрать безопасную реакциюСамостоятельный пример
<?php
declare(strict_types=1);

try {
    throw new SoapFault('Client', 'Неверный код склада');
} catch (SoapFault $fault) {
    echo "SOAP {$fault->faultcode}: {$fault->faultstring}\n";
    echo "HTTP ответ приложения: 422\n";
}
try {
    new SoapFault(['urn:shop'], 'Неполный QName');
} catch (ValueError $error) {
    echo "invalid QName rejected\n";
}
Ожидаемый результат
SOAP Client: Неверный код склада
HTTP ответ приложения: 422
invalid QName rejected

SoapFault наследует Exception, поэтому участвует в обычном try/catch. QName-массив обязан состоять ровно из namespace URI и local code; неполный массив даёт ValueError. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. SOAP 1.1 и 1.2 по-разному задают допустимые коды/структуру. Сверяйте QName и WSDL fault; не используйте PHP exception message как публичный договор без фильтрации. На проверенном PHP 8.5.11 прямой конструктор пока сохраняет lang=en даже при другом седьмом аргументе — это зафиксированная runtime/source граница, а не обещание спецификации.

Связанные операции: SoapFault::__toString, SoapServer::fault, is_soap_fault.

SoapFault::__toStringВозвращает строковое представление SoapFault в формате исключения для диагностики разработчиком.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapFault::__toString(): string

Возвращает строковое представление SoapFault в формате исключения для диагностики разработчиком.

Метод и документированная запись. SoapFault::__toString(): string. Reflection PHP 8.5.11: SoapFault::__toString(): string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает строку с классом, сообщением, местом возникновения и stack trace. Формат предназначен для диагностики и не является стабильным API ответа.

Отказ. Метод не отправляет SOAP XML. Случайная публикация строки может раскрыть локальные пути и внутреннюю структуру приложения.

Путь данных именно этого вызова
  1. PHP берёт поля у объекта Fault.
  2. Exception formatter добавляет файл, строку и trace.
  3. Разработчик пишет результат в закрытый лог либо извлекает стабильные поля отдельно.
Проверить, что строка Fault содержит класс и сообщениеСамостоятельный пример
<?php
declare(strict_types=1);

$fault = new SoapFault('Server', 'Сервис доставки не ответил');
$text = (string) $fault;
echo str_contains($text, 'SoapFault') ? "class present\n" : "class missing\n";
echo str_contains($text, 'Сервис доставки не ответил') ? "message present\n" : "message missing\n";
Ожидаемый результат
class present
message present

Полная строка похожа на строку Exception и содержит файл/trace, поэтому тест проверяет смысловые признаки, а не нестабильные номера строк. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Собрать устойчивую строку журнала вместо полного traceСамостоятельный пример
<?php
declare(strict_types=1);

$fault = new SoapFault('Server', 'Timeout', 'urn:carrier', ['requestId' => 'req-42']);
$raw = $fault->__toString();
$requestId = is_array($fault->detail) ? ($fault->detail['requestId'] ?? '-') : '-';
printf("soap_fault code=%s actor=%s request=%s\n", $fault->faultcode, $fault->faultactor, $requestId);
echo str_contains($raw, 'SoapFault') && str_contains($raw, 'Timeout') ? "raw trace captured\n" : "raw trace missing\n";
Ожидаемый результат
soap_fault code=Server actor=urn:carrier request=req-42
raw trace captured

Пример действительно вызывает __toString(), но в стабильную строку журнала выводит отдельные поля. Полную трассировку сохраняют отдельно с контролем доступа. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Для машинной обработки читайте faultcode/faultstring/detail. Не сравнивайте полную строку в тестах и не отдавайте её посетителю.

Связанные операции: SoapFault::__construct.

SoapHeader::__constructСоздаёт типизированный элемент SOAP Header — например, credential, correlation id или контекст операции.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapHeader::__construct( string $namespace, string $name, mixed $data = ?, bool $mustunderstand = ?, string $actor = ? )

Создаёт типизированный элемент SOAP Header — например, credential, correlation id или контекст операции.

Метод и документированная запись. SoapHeader::__construct( string $namespace, string $name, mixed $data = ?, bool $mustunderstand = ?, string $actor = ? ). Reflection PHP 8.5.11: SoapHeader::__construct(string $namespace, string $name, mixed $data /* optional; Reflection default unavailable */, bool $mustUnderstand = false, string|int|null $actor = null). Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
string $namespaceURI XML namespace бизнес-заголовка; это не произвольный префикс вроде ns1.
string $nameИмя удалённой операции, cookie, fault binding или XML-узла — точный смысл задаёт текущий метод.
mixed $dataPHP-значение для сериализации; форма должна соответствовать XSD/WSDL либо явной SoapVar.
bool $mustUnderstand = falseЕсли true, получатель обязан понять заголовок или вернуть Fault.
string|int|null $actor = nullURI участника/роли, который создал или должен обработать header/fault; null/пустая строка оставляют значение неуказанным.

Возврат и договор. Создаёт SoapHeader с публичными полями namespace, name, data, mustUnderstand и actor. Сам по себе объект ещё не прикреплён к запросу/ответу.

Отказ. Пустые namespace или name дают ValueError. Строковый actor должен быть длиннее двух символов; integer actor допускает только SOAP_ACTOR_NEXT, SOAP_ACTOR_NONE или SOAP_ACTOR_UNLIMATERECEIVER, иначе ValueError. Неправильный, но непустой namespace обычно обнаружит уже удалённый сервис.

Путь данных именно этого вызова
  1. Приложение знает namespace и имя из WSDL/спецификации.
  2. PHP сериализует data в дочерние XML-узлы.
  3. Клиент прикрепляет header через __setSoapHeaders/__soapCall, сервер — через addSoapHeader.
Создать заголовок авторизации и увидеть его частиСамостоятельный пример
<?php
declare(strict_types=1);

$header = new SoapHeader(
    'urn:shop:auth',
    'Credentials',
    ['login' => 'robot-17', 'token' => 'demo-token'],
    true,
    SOAP_ACTOR_NEXT,
);
echo $header->namespace, "\n";
echo $header->name, ' / ', ($header->mustUnderstand ? 'required' : 'optional'), "\n";
try {
    new SoapHeader('urn:shop:auth', 'Credentials', null, false, 999);
} catch (ValueError $error) {
    echo "invalid actor rejected\n";
}
Ожидаемый результат
urn:shop:auth
Credentials / required
invalid actor rejected

Namespace — URI словаря сервиса, name — имя элемента, data — его содержимое. Integer actor разрешён только как SOAP_ACTOR_NEXT, SOAP_ACTOR_NONE или SOAP_ACTOR_UNLIMATERECEIVER. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Убедиться, что бизнес-заголовок реально попал в EnvelopeСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7'));
$client->__setSoapHeaders(new SoapHeader(
    'urn:shop:auth',
    'Credentials',
    ['login' => 'robot-17', 'token' => 'demo-token'],
));
$client->__soapCall('sum', [new SoapParam(3, 'a'), new SoapParam(4, 'b')]);

echo str_contains($client->seenRequest, '<SOAP-ENV:Header>') ? "header present\n" : "header missing\n";
echo str_contains($client->seenRequest, 'demo-token') ? "token present\n" : "token missing\n";
Ожидаемый результат
header present
token present

Trace/XML подтверждает фактическую сериализацию. В реальном журнале токен маскируют; здесь используется учебное значение. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Документированный synopsis и Reflection 8.5.11 расходятся в defaults/types optional-параметров: выше показаны обе записи. HTTP Authorization и SOAP Header — разные слои. Не используйте envelope namespace как namespace бизнес-заголовка.

Связанные операции: SoapClient::__setSoapHeaders, SoapServer::addSoapHeader, SoapVar::__construct.

SoapParam::__constructОборачивает значение с именем SOAP-параметра, чтобы non-WSDL вызов создал ожидаемый XML-узел.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapParam::__construct(mixed $data, string $name)

Оборачивает значение с именем SOAP-параметра, чтобы non-WSDL вызов создал ожидаемый XML-узел.

Метод и документированная запись. SoapParam::__construct(mixed $data, string $name). Reflection PHP 8.5.11: SoapParam::__construct(mixed $data, string $name). Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
mixed $dataPHP-значение для сериализации; форма должна соответствовать XSD/WSDL либо явной SoapVar.
string $nameИмя удалённой операции, cookie, fault binding или XML-узла — точный смысл задаёт текущий метод.

Возврат и договор. Создаёт SoapParam с публичными param_name и param_data. Возвращаемого значения конструктора нет.

Отказ. Пустое имя даёт ValueError «must not be empty». Непустое, но неверное по договору имя сериализуется и обычно приводит к Fault удалённого сервиса. Тип значения всё ещё должен соответствовать XSD.

Путь данных именно этого вызова
  1. Код берёт имя параметра из договора операции.
  2. SoapParam хранит имя и PHP-значение.
  3. SoapClient создаёт одноимённый XML-элемент при вызове.
Дать аргументу операции точное имяСамостоятельный пример
<?php
declare(strict_types=1);

$parameter = new SoapParam(731, 'orderId');
echo $parameter->param_name, "\n";
echo $parameter->param_data, "\n";
try {
    new SoapParam(731, '');
} catch (ValueError $error) {
    echo "empty name rejected\n";
}
Ожидаемый результат
orderId
731
empty name rejected

Объект связывает PHP-значение 731 с именем orderId. Пустое имя отклоняет сам PHP с ValueError до сериализации. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Сериализовать два именованных аргумента расчётаСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7'));
$result = $client->__soapCall('sum', [
    new SoapParam(3, 'a'),
    new SoapParam(4, 'b'),
]);
echo $result, "\n";
echo preg_match('/<a[^>]*>3<\/a>/', $client->seenRequest) ? "a named\n" : "a missing\n";
echo preg_match('/<b[^>]*>4<\/b>/', $client->seenRequest) ? "b named\n" : "b missing\n";
Ожидаемый результат
7
a named
b named

Это полезно в non-WSDL режиме, где клиент не может взять имена из контракта. В WSDL-mode обычно достаточно обычного массива, если WSDL корректен. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Не добавляйте SoapParam механически в WSDL-mode. Сначала посмотрите __getFunctions и фактический request trace; проблема может быть в структуре wrapper, а не в имени scalar.

Связанные операции: SoapClient::__soapCall, SoapVar::__construct.

SoapVar::__constructЯвно задаёт XSD/SOAP тип, имя и namespace значения, когда автоматическая сериализация не совпадает с контрактом.

PHP 5+; typeName/typeNamespace/nodeName/nodeNamespace nullable с PHP 8.0.3; DateTimeInterface для date/time исправлен в PHP 8.4 · soap; XML/libxml; HTTP transport for real remote calls

SoapVar::__construct( mixed $data, ?int $encoding, ?string $typeName = null, ?string $typeNamespace = null, ?string $nodeName = null, ?string $nodeNamespace = null )

Явно задаёт XSD/SOAP тип, имя и namespace значения, когда автоматическая сериализация не совпадает с контрактом.

Метод и документированная запись. SoapVar::__construct( mixed $data, ?int $encoding, ?string $typeName = null, ?string $typeNamespace = null, ?string $nodeName = null, ?string $nodeNamespace = null ). Reflection PHP 8.5.11: SoapVar::__construct(mixed $data, ?int $encoding, ?string $typeName = null, ?string $typeNamespace = null, ?string $nodeName = null, ?string $nodeNamespace = null). Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
mixed $dataPHP-значение для сериализации; форма должна соответствовать XSD/WSDL либо явной SoapVar.
?int $encodingXSD_/SOAP_ENC_ идентификатор способа сериализации либо null для вывода типа по значению.
?string $typeName = nullИмя XSD-типа из контракта, когда одного numeric encoding недостаточно.
?string $typeNamespace = nullURI namespace указанного XSD-типа.
?string $nodeName = nullИмя XML-элемента, которое должен получить сервис.
?string $nodeNamespace = nullURI namespace XML-элемента.

Возврат и договор. Создаёт SoapVar с enc_type, enc_value, enc_stype, enc_ns, enc_name и enc_namens. Реальный XML появляется только при сериализации клиентом/сервером.

Отказ. Numeric encoding, которого нет в таблице XSD_/SOAP_ENC_, даёт ValueError «not a valid encoding». Существующий encoding с неверным type/namespace может создать несовместимый XML и удалённый Fault.

Путь данных именно этого вызова
  1. Приложение знает нужный XSD-тип и QName из WSDL.
  2. SoapVar связывает значение с метаданными сериализации.
  3. ext/soap создаёт XML lexical form и namespace узла.
Описать XML-узел даты точнее обычной строкиСамостоятельный пример
<?php
declare(strict_types=1);

$date = new DateTimeImmutable('2026-10-15T12:30:00+03:00');
$value = new SoapVar($date, XSD_DATETIME, null, null, 'shippedAt', 'urn:shop');
echo $value->enc_type === XSD_DATETIME ? "xsd:dateTime\n" : "other\n";
echo $value->enc_name, ' / ', $value->enc_namens, "\n";
try {
    new SoapVar('value', 999999);
} catch (ValueError $error) {
    echo "unknown encoding rejected\n";
}
Ожидаемый результат
xsd:dateTime
shippedAt / urn:shop
unknown encoding rejected

С PHP 8.4 DateTimeInterface для xsd:dateTime сериализуется как ISO 8601. Неизвестный numeric encoding PHP отклоняет ValueError до сериализации. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Передать бинарный фрагмент как base64BinaryСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(manualSoapResponse('upload', 'string', 'accepted'));
$payload = new SoapVar("PDF\x00demo", XSD_BASE64BINARY, null, null, 'content', 'urn:files');
$result = $client->__soapCall('upload', [new SoapParam($payload, 'file')]);
echo $result, "\n";
echo str_contains($client->seenRequest, base64_encode("PDF\x00demo")) ? "base64 payload\n" : "payload missing\n";
Ожидаемый результат
accepted
base64 payload

SoapVar сообщает сериализатору XSD-тип; бинарные байты не вставляются в XML напрямую, а кодируются Base64. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. SoapVar — точечный инструмент для несовместимого контракта. Не заменяйте им чтение WSDL; для пользовательского XML безопаснее DOM/XMLWriter, а типы SOAP должны соответствовать XSD lexical rules.

Связанные операции: SoapParam::__construct, SoapHeader::__construct, SoapClient::__soapCall.

SoapClient::__constructСоздаёт клиент и фиксирует контракт, endpoint, transport, сериализацию, диагностику и политику ошибок будущих вызовов.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__construct(?string $wsdl, array $options = [])

Создаёт клиент и фиксирует контракт, endpoint, transport, сериализацию, диагностику и политику ошибок будущих вызовов.

Метод и документированная запись. SoapClient::__construct(?string $wsdl, array $options = []). Reflection PHP 8.5.11: SoapClient::__construct(?string $wsdl, array $options = []). Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
?string $wsdlURL или локальный путь к WSDL; null включает non-WSDL mode, где приложение само задаёт uri и endpoint.
array $options = []Ассоциативный массив настроек. Допустимые ключи зависят от client/server и подробно разобраны в карточке конструктора.

Возврат и договор. Конструктор создаёт объект или выбрасывает SoapFault, если WSDL нельзя загрузить/разобрать. В non-WSDL mode обязательны location и uri. Ключи options включают soap_version, style/use, login/password/authentication, local_cert/passphrase, proxy_*, compression, encoding, trace, classmap, typemap, exceptions, connection_timeout, cache_wsdl, user_agent, stream_context, features, keep_alive и deprecated ssl_method.

Отказ. Недоступный/невалидный WSDL даёт SoapFault. В non-WSDL mode отсутствие location или uri — фатальная ошибка конфигурации. connection_timeout ограничивает соединение, а не медленный ответ; для чтения действует default_socket_timeout/архитектурный deadline.

Путь данных именно этого вызова
  1. PHP загружает и при необходимости кэширует WSDL либо принимает ручной договор.
  2. Создаёт внутренние mapping/transport settings.
  3. Последующие методы сериализуют аргументы согласно этому состоянию.
Создать non-WSDL клиент и выполнить понятный расчётСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '9'));
$result = $client->__soapCall('sum', [new SoapParam(4, 'a'), new SoapParam(5, 'b')]);
echo $result, "\n";
echo $client->seenLocation, "\n";
Ожидаемый результат
9
http://local.invalid/soap

В non-WSDL mode приложение само задаёт location и uri. Mock заменяет только сеть; Envelope создаёт и разбирает настоящий ext/soap. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Загрузить локальный WSDL и получить объявленную операциюСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(
    manualSoapResponse('sum', 'int', '15'),
    __DIR__ . '/service.wsdl',
    ['cache_wsdl' => WSDL_CACHE_NONE],
);
echo $client->__getFunctions()[0], "\n";
echo $client->sum(7, 8), "\n";
Ожидаемый результат
int sum(int $a, int $b)
15

WSDL задаёт имя, типы, SOAPAction и endpoint. Cache отключён только в локальном изменяемом контракте; production WSDL обычно версионируют и кэшируют. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. WSDL может импортировать другие XSD/WSDL: доступны должны быть все зависимости. trace=true удерживает последний XML с возможными секретами. TLS verification не отключают ради «починить SOAP»; доверие настраивают CA/stream_context. В dev cache можно выключить, в production это цена повторного download/parse.

Связанные операции: SoapClient::__soapCall, SoapClient::__getFunctions, SoapClient::__getTypes.

SoapClient::__callMagic-dispatch неизвестного PHP-метода в SOAP-операцию; напрямую вызывать этот метод deprecated.

PHP 5+; прямой вызов deprecated в текущем руководстве · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__call(string $name, array $args): mixed

Magic-dispatch неизвестного PHP-метода в SOAP-операцию; напрямую вызывать этот метод deprecated.

Метод и документированная запись. SoapClient::__call(string $name, array $args): mixed. Reflection PHP 8.5.11: SoapClient::__call(string $name, array $args): mixed. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
string $nameИмя удалённой операции, cookie, fault binding или XML-узла — точный смысл задаёт текущий метод.
array $argsАргументы операции. Для SOAP-вызова это упорядоченный/именованный массив; для setClass — variadic аргументы конструктора обработчика.

Возврат и договор. Возвращает один scalar/object либо associative array нескольких output-параметров. При exceptions=false ошибка возвращается как SoapFault.

Отказ. При exceptions=true удалённый Fault/transport error выбрасывает SoapFault; при false возвращается объект Fault, который проверяют is_soap_fault.

Путь данных именно этого вызова
  1. PHP не находит объявленный метод вроде sum.
  2. __call получает имя и аргументы.
  3. SoapClient строит Envelope, выполняет transport и декодирует ответ.
Вызвать WSDL-операцию как обычный метод объектаСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(
    manualSoapResponse('sum', 'int', '12'),
    __DIR__ . '/service.wsdl',
);
echo $client->sum(5, 7), "\n";
echo str_contains($client->seenAction, 'sum') ? "action: sum\n" : "action: other\n";
Ожидаемый результат
12
action: sum

Когда PHP не находит реальный метод sum, magic dispatch направляет вызов в SoapClient::__call. Такой синтаксис — обычный путь для WSDL-клиента. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Заменить deprecated прямой __call на __soapCallСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7'));
$old = $client->__call('sum', [new SoapParam(3, 'a'), new SoapParam(4, 'b')]);
$new = $client->__soapCall('sum', [new SoapParam(3, 'a'), new SoapParam(4, 'b')]);
echo 'direct: ', $old, "\n";
echo 'soapCall: ', $new, "\n";
Ожидаемый результат
direct: 7
soapCall: 7

Прямой вызов __call() документация помечает deprecated, хотя проверенный runtime 8.5.11 не обязан выдавать E_DEPRECATED. Результат показан рядом с явным __soapCall(); magic $client->sum() остаётся нормальным WSDL-синтаксисом. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Не пишите $client->__call(...) в новом коде. Для красивого WSDL-вызова используйте $client->Operation(); для per-call options/headers — __soapCall().

Связанные операции: SoapClient::__soapCall, is_soap_fault.

SoapClient::__soapCallНизкоуровневый вызов SOAP-операции с per-call endpoint/action/uri и входными/выходными SOAP headers.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__soapCall( string $name, array $args, ?array $options = null, SoapHeader|array|null $inputHeaders = null, array &$outputHeaders = null ): mixed

Низкоуровневый вызов SOAP-операции с per-call endpoint/action/uri и входными/выходными SOAP headers.

Метод и документированная запись. SoapClient::__soapCall( string $name, array $args, ?array $options = null, SoapHeader|array|null $inputHeaders = null, array &$outputHeaders = null ): mixed. Reflection PHP 8.5.11: SoapClient::__soapCall(string $name, array $args, ?array $options = null, mixed $inputHeaders = null, mixed &$outputHeaders = null): mixed. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
string $nameИмя удалённой операции, cookie, fault binding или XML-узла — точный смысл задаёт текущий метод.
array $argsАргументы операции. Для SOAP-вызова это упорядоченный/именованный массив; для setClass — variadic аргументы конструктора обработчика.
?array $options = nullАссоциативный массив настроек. Допустимые ключи зависят от client/server и подробно разобраны в карточке конструктора.
mixed $inputHeaders = nullЗаголовок или массив заголовков только для текущего вызова.
mixed &$outputHeaders = nullВыходной аргумент: после вызова PHP запишет сюда заголовки SOAP-ответа; переменную передают по ссылке.

Возврат и договор. Если операция имеет один output, возвращается scalar/object; несколько именованных output-параметров дают ассоциативный массив. При exceptions=false отказ возвращается объектом SoapFault, который проверяют через is_soap_fault. $outputHeaders заполняется по ссылке и не является return value.

Отказ. С exceptions=true SOAP/transport fault бросается как SoapFault; с exceptions=false тот же отказ возвращается как SoapFault и не должен ошибочно считаться предметным результатом. Неверные parameter names/QName часто доходят до сервиса и возвращаются как Fault.

Путь данных именно этого вызова
  1. Имя и args превращаются в Body.
  2. options уточняют transport/action текущего вызова.
  3. inputHeaders входят в Envelope Header.
  4. Ответ разбирается в return и outputHeaders.
Переопределить endpoint только для одного вызоваСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7'));
$result = $client->__soapCall(
    'sum',
    [new SoapParam(3, 'a'), new SoapParam(4, 'b')],
    ['location' => 'https://backup.example.test/soap', 'soapaction' => 'urn:manual#sum'],
);
echo $result, "\n";
echo $client->seenLocation, "\n";
Ожидаемый результат
7
https://backup.example.test/soap

Per-call location не меняет WSDL и удобен для управляемого failover. Endpoint всё равно берут из доверенной конфигурации, а не из пользовательского ввода. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Передать request header и получить response header по ссылкеСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$replyHeader = '<m:RequestId xmlns:m="urn:meta">req-42</m:RequestId>';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7', $replyHeader));
$responseHeaders = [];
$result = $client->__soapCall(
    'sum',
    [new SoapParam(3, 'a'), new SoapParam(4, 'b')],
    null,
    new SoapHeader('urn:meta', 'ClientId', 'shop-1'),
    $responseHeaders,
);
echo $result, "\n";
echo $responseHeaders['RequestId'], "\n";
Ожидаемый результат
7
req-42

Пятый аргумент — выходной: PHP заполняет переданную переменную. Это SOAP headers внутри Envelope, не HTTP response headers. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Не путайте массив аргументов операции с массивом одного wrapper-объекта: точную форму показывает WSDL и __getFunctions. Документация типизирует array &$outputHeaders = null, а Reflection PHP 8.5.11 оставляет inputHeaders/outputHeaders без runtime type; передавайте SoapHeader/массив и отдельную переменную по ссылке.

Связанные операции: SoapClient::__call, SoapParam::__construct, SoapHeader::__construct.

SoapClient::__doRequestВыполняет transport готового SOAP XML; переопределяется для тестов, очереди, наблюдаемости или особого протокола.

PHP 5+; $oneWay изменён с int на bool в PHP 8.0; $uriParserClass добавлен в PHP 8.5 · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__doRequest( string $request, string $location, string $action, int $version, bool $oneWay = false, ?string $uriParserClass = null ): ?string

Выполняет transport готового SOAP XML; переопределяется для тестов, очереди, наблюдаемости или особого протокола.

Метод и документированная запись. SoapClient::__doRequest( string $request, string $location, string $action, int $version, bool $oneWay = false, ?string $uriParserClass = null ): ?string. Reflection PHP 8.5.11: SoapClient::__doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false, ?string $uriParserClass = null): ?string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
string $requestПолный XML SOAP Envelope. В handle(null) сервер читает raw POST body; в тесте строку можно передать явно.
string $locationEndpoint URL для HTTP-запроса; это адрес транспорта, а не target namespace.
string $actionSOAPAction конкретной операции. Значение берут из WSDL/договора сервиса, не угадывают по имени PHP-метода.
int $versionSOAP_1_1 или SOAP_1_2; версия определяет envelope namespace и HTTP media type.
bool $oneWay = falsetrue, если договор не предусматривает предметный SOAP-ответ. Базовый transport после успешной отправки возвращает пустую строку, а при transport failure — null; внешний SOAP-вызов без SOAP_WAIT_ONE_WAY_CALLS не ждёт полезную нагрузку ответа.
?string $uriParserClass = nullС PHP 8.5 имя класса разбора redirect URI; null оставляет стандартный разбор на основе parse_url.

Возврат и договор. При обычном вызове возвращает XML SOAP response или null при transport failure. При base one-way transport успешная отправка возвращает пустую строку, отказ — null. Feature SOAP_WAIT_ONE_WAY_CALLS заставляет ждать response и снимает one-way поведение. В PHP 8.5 добавлен $uriParserClass.

Отказ. Base transport возвращает null при неуспешном HTTP transport; внешний SOAP-вызов затем применяет exceptions policy. Некорректный response XML ломает разбор после возврата. One-way не доказывает бизнес-доставку.

Путь данных именно этого вызова
  1. Serializer строит request XML.
  2. __doRequest получает endpoint/action/version.
  3. Transport возвращает response XML.
  4. SoapClient декодирует его в PHP-значение.
Перехватить сформированный XML в собственном transportСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';

$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7'));
echo $client->__soapCall('sum', [new SoapParam(3, 'a'), new SoapParam(4, 'b')]), "\n";
printf("version=%d action=%s\n", $client->seenVersion, $client->seenAction);
echo str_contains($client->seenRequest, '<a xsi:type="xsd:int">3</a>') ? "body checked\n" : "body differs\n";
Ожидаемый результат
7
version=1 action=urn:manual#sum
body checked

Переопределение получает уже готовый Envelope и transport metadata. Это точка для test double, очереди или нестандартного транспорта, но не повод переписывать XML строковыми заменами. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Увидеть точные return base transport для one-way успеха и отказаСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$request = '<?xml version="1.0"?>'
    . '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">'
    . '<SOAP-ENV:Body><m:sum xmlns:m="urn:manual"><a>1</a><b>2</b></m:sum></SOAP-ENV:Body>'
    . '</SOAP-ENV:Envelope>';
$client = new SoapClient(null, ['location' => $url, 'uri' => 'urn:manual', 'exceptions' => false]);
$success = $client->__doRequest($request, $url, 'urn:manual#sum', SOAP_1_1, true);
echo $success === '' ? "success: empty string\n" : "success: unexpected\n";
$failure = $client->__doRequest($request, 'http://127.0.0.1:1/unavailable', 'urn:manual#sum', SOAP_1_1, true);
echo $failure === null ? "failure: null\n" : "failure: unexpected\n";
Ожидаемый результат
success: empty string
failure: null

Base transport PHP 8.5.11 при oneWay=true возвращает пустую строку после успешной отправки и null при transport failure. Это не подтверждение обработки бизнес-события. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. Не логируйте сырой request без маскирования SOAP Header. При override сохраняйте сигнатуру, timeout/TLS policy и возвращайте полный Envelope. Редиректы и SSRF требуют allowlist endpoint.

Связанные операции: SoapClient::__getLastRequest, SoapClient::__getLastResponse.

SoapClient::__getCookiesВозвращает текущий cookie jar SoapClient для диагностики stateful SOAP/HTTP взаимодействия.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__getCookies(): array

Возвращает текущий cookie jar SoapClient для диагностики stateful SOAP/HTTP взаимодействия.

Метод и документированная запись. SoapClient::__getCookies(): array. Reflection PHP 8.5.11: SoapClient::__getCookies(): array. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает массив cookie; каждое имя указывает на массив значения и возможных атрибутов. Пустой jar — пустой массив.

Отказ. Метод не проверяет срок/пригодность cookie у удалённого сервиса. Секрет в debug output становится утечкой.

Путь данных именно этого вызова
  1. Set-Cookie ответа или __setCookie меняет jar.
  2. Метод возвращает снимок состояния.
  3. Следующий HTTP-вызов применяет подходящие cookie.
Посмотреть cookie jar клиента и удалить одно значениеСамостоятельный пример
<?php
declare(strict_types=1);

$client = new SoapClient(null, ['location' => 'http://local.invalid', 'uri' => 'urn:manual']);
$client->__setCookie('manual_session', 'abc');
$client->__setCookie('region', 'msk');
$client->__setCookie('region');
$cookies = $client->__getCookies();
echo $cookies['manual_session'][0], "\n";
echo array_key_exists('region', $cookies) ? "region kept\n" : "region removed\n";
Ожидаемый результат
abc
region removed

Cookie jar хранит дополнительные атрибуты массивом. Не предполагайте, что значение всегда лежит прямо по ключу без вложенности. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Отправить cookie реальному loopback SOAP endpointСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => $url, 'uri' => 'urn:manual']);
$client->__setCookie('manual_session', 'cart-731');
echo $client->__soapCall('readManualCookie', []), "\n";
echo $client->__getCookies()['manual_session'][0], "\n";
Ожидаемый результат
cart-731
cart-731

Здесь cookie прошёл через настоящий HTTP loopback. Для удалённого сервиса помните про область домена/path/secure и не выводите session token. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. SoapClient — stateful объект: переиспользование переносит cookies между вызовами. Не делите один клиент между разными пользователями/тенантами без явной изоляции.

Связанные операции: SoapClient::__setCookie.

SoapClient::__getFunctionsВозвращает текстовые прототипы операций, разобранных из WSDL.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__getFunctions(): ?array

Возвращает текстовые прототипы операций, разобранных из WSDL.

Метод и документированная запись. SoapClient::__getFunctions(): ?array. Reflection PHP 8.5.11: SoapClient::__getFunctions(): ?array. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает array строк в WSDL-mode и null без WSDL. Строки предназначены для диагностики, не для eval/code generation.

Отказ. Пустой/устаревший список часто означает другой WSDL/cache, а не отсутствие endpoint. Ошибка разбора WSDL возникает в конструкторе.

Путь данных именно этого вызова
  1. Конструктор разбирает WSDL portType/messages.
  2. Метод форматирует операции в PHP-подобные прототипы.
  3. Разработчик сверяет имя/типы перед вызовом.
Узнать сигнатуру операции из WSDLСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '0'), __DIR__ . '/service.wsdl');
foreach ($client->__getFunctions() ?? [] as $signature) {
    echo $signature, "\n";
}
Ожидаемый результат
int sum(int $a, int $b)

Список полезен для быстрой диагностики имени и порядка аргументов, но не заменяет документацию ограничений типов и предметных ошибок. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Увидеть границу non-WSDL modeСамостоятельный пример
<?php
declare(strict_types=1);

$client = new SoapClient(null, ['location' => 'http://local.invalid', 'uri' => 'urn:manual']);
echo $client->__getFunctions() === null ? "no WSDL prototypes\n" : "prototypes found\n";
Ожидаемый результат
no WSDL prototypes

В non-WSDL mode PHP не может вывести список удалённых операций: договор должен храниться в спецификации приложения. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. После обновления контракта учитывайте WSDL cache. Один прототип не показывает facets, minOccurs/maxOccurs, namespaces и fault contract.

Связанные операции: SoapClient::__getTypes, SoapClient::__construct.

SoapClient::__getTypesВозвращает текстовые описания XSD complex/simple types, разобранных из WSDL.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__getTypes(): ?array

Возвращает текстовые описания XSD complex/simple types, разобранных из WSDL.

Метод и документированная запись. SoapClient::__getTypes(): ?array. Reflection PHP 8.5.11: SoapClient::__getTypes(): ?array. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает array строк в WSDL-mode и null в non-WSDL mode.

Отказ. Метод не валидирует ваши PHP DTO и не сообщает все XSD facets. Не загруженный import проявится ещё при создании клиента.

Путь данных именно этого вызова
  1. WSDL импортирует XSD.
  2. Parser строит внутреннюю модель типов.
  3. Метод форматирует её в читаемые строки.
Посмотреть complex type заказа из схемыСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '0'), __DIR__ . '/service.wsdl');
$types = $client->__getTypes() ?? [];
echo str_contains($types[0], 'struct Order') ? "Order type\n" : "other type\n";
echo str_contains($types[0], 'string status') ? "status: string\n" : "status missing\n";
Ожидаемый результат
Order type
status: string

Тип помогает понять форму объекта ответа до var_dump реального заказа. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Не требовать типов там, где WSDL отсутствуетСамостоятельный пример
<?php
declare(strict_types=1);

$client = new SoapClient(null, ['location' => 'http://local.invalid', 'uri' => 'urn:manual']);
var_export($client->__getTypes());
echo "\n";
Ожидаемый результат
NULL

null — ожидаемая граница режима, а не сетевой сбой. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Classmap связывают с точным type name/namespace, а не с именем XML-элемента. Для одинаковых имён в разных namespace с PHP 8.4 доступна Clark notation.

Связанные операции: SoapClient::__getFunctions, SoapClient::__construct.

SoapClient::__getLastRequestВозвращает XML последнего SOAP request, если клиент создан с <code>trace=true</code>.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__getLastRequest(): ?string

Возвращает XML последнего SOAP request, если клиент создан с trace=true.

Метод и документированная запись. SoapClient::__getLastRequest(): ?string. Reflection PHP 8.5.11: SoapClient::__getLastRequest(): ?string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает строку XML либо null, когда request ещё не было или trace выключен.

Отказ. Это не повтор запроса и не доказательство доставки. XML может содержать пароль/token/персональные данные.

Путь данных именно этого вызова
  1. Последний вызов создаёт Envelope.
  2. При trace=true клиент сохраняет копию.
  3. Метод отдаёт её для локальной диагностики.
Найти операцию и аргумент в последнем request XMLСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7'));
$client->__soapCall('sum', [new SoapParam(3, 'a'), new SoapParam(4, 'b')]);
$xml = $client->__getLastRequest();
echo is_string($xml) && str_contains($xml, '<ns1:sum>') ? "sum envelope\n" : "missing\n";
echo is_string($xml) && str_contains($xml, '>4</b>') ? "b=4\n" : "b missing\n";
Ожидаемый результат
sum envelope
b=4

Вместо угадывания структуры сравниваем фактический Envelope с документацией поставщика. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Понять, почему request недоступен без traceСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '3'), null, ['trace' => false]);
$client->__soapCall('sum', [new SoapParam(1, 'a'), new SoapParam(2, 'b')]);
echo $client->__getLastRequest() === null ? "trace is off\n" : "request retained\n";
Ожидаемый результат
trace is off

Transport был выполнен, но диагностическая копия не сохранена. Это отдельная настройка, а не ошибка вызова. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Маскируйте secrets до журнала и ограничивайте размер. Не включайте trace постоянно в высоконагруженном long-lived worker без необходимости.

Связанные операции: SoapClient::__getLastRequestHeaders, SoapClient::__getLastResponse.

SoapClient::__getLastResponseВозвращает XML последнего SOAP response при включённом trace.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__getLastResponse(): ?string

Возвращает XML последнего SOAP response при включённом trace.

Метод и документированная запись. SoapClient::__getLastResponse(): ?string. Reflection PHP 8.5.11: SoapClient::__getLastResponse(): ?string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает строку XML либо null. Декодированный return/Fault метод не заменяет.

Отказ. Ответ может быть большим и содержать персональные данные. Невалидный XML может вызвать Fault до полезной диагностики.

Путь данных именно этого вызова
  1. Transport возвращает Envelope.
  2. Trace сохраняет raw response.
  3. Decoder строит PHP-результат отдельно.
  4. Разработчик сравнивает два слоя.
Сверить декодированное число с исходным response XMLСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '7'));
$value = $client->__soapCall('sum', [new SoapParam(3, 'a'), new SoapParam(4, 'b')]);
$xml = $client->__getLastResponse();
echo $value, "\n";
echo is_string($xml) && str_contains($xml, '>7</return>') ? "raw return=7\n" : "raw missing\n";
Ожидаемый результат
7
raw return=7

Так находят границу: XML правильный, а PHP mapping неожиданен — значит исследуют WSDL/classmap/typemap, а не сеть. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Посмотреть безопасный признак Fault в raw responseСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapFault('Server', 'Stock unavailable'), null, ['exceptions' => false]);
$result = $client->__soapCall('reserve', [['sku' => 'A-1']]);
echo is_soap_fault($result) ? "fault object\n" : "result object\n";
echo str_contains((string) $client->__getLastResponse(), '<SOAP-ENV:Fault>') ? "fault XML\n" : "no fault XML\n";
Ожидаемый результат
fault object
fault XML

Raw XML помогает подтвердить, что Fault пришёл от transport double/сервиса; приложение всё равно работает со структурированным SoapFault. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Логируйте correlation id, timing и redacted fragment, а не полный ответ без ограничений. Binary base64 резко увеличивает размер trace.

Связанные операции: SoapClient::__getLastResponseHeaders, SoapClient::__getLastRequest.

SoapClient::__getLastRequestHeadersВозвращает HTTP-заголовки последнего SOAP request при <code>trace=true</code>.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__getLastRequestHeaders(): ?string

Возвращает HTTP-заголовки последнего SOAP request при trace=true.

Метод и документированная запись. SoapClient::__getLastRequestHeaders(): ?string. Reflection PHP 8.5.11: SoapClient::__getLastRequestHeaders(): ?string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает строку заголовков либо null. SOAP Envelope Header смотрят в __getLastRequest, это другой слой.

Отказ. Метод не доступен до реального HTTP transport и ничего не возвращает при trace=false. Заголовки могут содержать Authorization/Cookie.

Путь данных именно этого вызова
  1. HTTP transport собирает request line/headers.
  2. Trace сохраняет текст.
  3. Метод отдаёт его для диагностики proxy/auth/content type/action.
Увидеть реальные HTTP method, Content-Type и SOAPActionСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => $url, 'uri' => 'urn:manual', 'trace' => true]);
$client->__soapCall('sum', [new SoapParam(2, 'a'), new SoapParam(3, 'b')]);
$headers = (string) $client->__getLastRequestHeaders();
echo str_starts_with($headers, 'POST ') ? "POST\n" : "method differs\n";
echo stripos($headers, 'Content-Type: text/xml') !== false ? "SOAP 1.1 content type\n" : "content type differs\n";
echo stripos($headers, 'SOAPAction:') !== false ? "SOAPAction present\n" : "SOAPAction missing\n";
Ожидаемый результат
POST
SOAP 1.1 content type
SOAPAction present

Выполняется настоящий HTTP-запрос к одноразовому loopback-серверу, поэтому заголовки созданы transport ext/soap. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Проверить управляемый User-Agent без показа bodyСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, [
    'location' => $url,
    'uri' => 'urn:manual',
    'trace' => true,
    'user_agent' => 'ManualService/1.0',
]);
$client->__soapCall('greet', [new SoapParam('Анна', 'name')]);
$headers = (string) $client->__getLastRequestHeaders();
echo stripos($headers, 'User-Agent: ManualService/1.0') !== false ? "agent ok\n" : "agent missing\n";
Ожидаемый результат
agent ok

User-Agent помогает поставщику различать интеграции; он не должен содержать секреты или пользовательский ввод. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. Перед журналом удаляйте Authorization, Cookie и proxy credentials. Для SOAP 1.2 Content-Type/action устроены иначе, чем для SOAP 1.1.

Связанные операции: SoapClient::__getLastRequest, SoapClient::__getLastResponseHeaders.

SoapClient::__getLastResponseHeadersВозвращает HTTP response headers последнего SOAP transport при trace=true.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__getLastResponseHeaders(): ?string

Возвращает HTTP response headers последнего SOAP transport при trace=true.

Метод и документированная запись. SoapClient::__getLastResponseHeaders(): ?string. Reflection PHP 8.5.11: SoapClient::__getLastResponseHeaders(): ?string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает строку либо null. Заголовки SOAP Envelope получают пятым аргументом __soapCall, а не здесь.

Отказ. Промежуточный proxy может менять/добавлять заголовки. Наличие 200 не означает успешную предметную операцию.

Путь данных именно этого вызова
  1. Endpoint отвечает status/headers/body.
  2. Transport сохраняет headers при trace.
  3. Decoder отдельно разбирает SOAP body.
Прочитать диагностический HTTP header loopback-сервераСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => $url, 'uri' => 'urn:manual', 'trace' => true]);
$client->__soapCall('sum', [new SoapParam(2, 'a'), new SoapParam(3, 'b')]);
$headers = (string) $client->__getLastResponseHeaders();
echo str_contains($headers, '200 OK') ? "HTTP 200\n" : "status differs\n";
echo stripos($headers, 'X-Manual-Server: loopback') !== false ? "server marker\n" : "marker missing\n";
Ожидаемый результат
HTTP 200
server marker

HTTP status/header диагностируют gateway и transport; предметный SOAP Fault при этом способен прийти и с HTTP 200. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Увидеть создание PHP session cookie у stateful сервераСамостоятельный пример
<?php
declare(strict_types=1);

$base = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, [
    'location' => $base . '?persistence=1',
    'uri' => 'urn:manual',
    'trace' => true,
]);
echo $client->__soapCall('increment', []), "\n";
$headers = (string) $client->__getLastResponseHeaders();
echo stripos($headers, 'Set-Cookie: PHPSESSID=') !== false ? "session issued\n" : "session missing\n";
Ожидаемый результат
1
session issued

Пример показывает transport state, необходимый SOAP_PERSISTENCE_SESSION. В production session cookie защищают Secure/HttpOnly/SameSite там, где это применимо. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. Смотрите HTTP status, Retry-After, Set-Cookie и correlation headers вместе с SoapFault. Маскируйте cookies и auth challenges в логах.

Связанные операции: SoapClient::__getLastResponse, SoapClient::__soapCall.

SoapClient::__setCookieДобавляет, обновляет или удаляет HTTP cookie для следующих вызовов этого SoapClient.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__setCookie(string $name, ?string $value = null): void

Добавляет, обновляет или удаляет HTTP cookie для следующих вызовов этого SoapClient.

Метод и документированная запись. SoapClient::__setCookie(string $name, ?string $value = null): void. Reflection PHP 8.5.11: SoapClient::__setCookie(string $name, ?string $value = null): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
string $nameИмя удалённой операции, cookie, fault binding или XML-узла — точный смысл задаёт текущий метод.
?string $value = nullЗначение cookie; null удаляет cookie из состояния клиента.

Возврат и договор. Возвращаемого значения нет. Любая строка, включая пустую, сохраняется в jar; null или пропущенный второй аргумент удаляет cookie. Параметр value nullable с PHP 8.0.

Отказ. Неверный тип даёт TypeError. Сервер может игнорировать cookie из-за domain/path/secure policy или собственного договора.

Путь данных именно этого вызова
  1. Приложение меняет cookie jar объекта.
  2. Следующий HTTP request получает Cookie header.
  3. Set-Cookie ответа может обновить jar снова.
Обновить и удалить cookie в состоянии клиентаСамостоятельный пример
<?php
declare(strict_types=1);

$client = new SoapClient(null, ['location' => 'http://local.invalid', 'uri' => 'urn:manual']);
$client->__setCookie('region', 'spb');
$client->__setCookie('region', 'msk');
echo $client->__getCookies()['region'][0], "\n";
$client->__setCookie('empty', '');
echo array_key_exists('empty', $client->__getCookies()) && $client->__getCookies()['empty'][0] === '' ? "empty string kept\n" : "empty string lost\n";
$client->__setCookie('region', null);
echo array_key_exists('region', $client->__getCookies()) ? "kept\n" : "deleted\n";
Ожидаемый результат
msk
empty string kept
deleted

Повторная установка меняет значение. Пустая строка — настоящее сохранённое значение; только null или пропущенный второй аргумент удаляет cookie. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Передать correlation cookie реальному endpointСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => $url, 'uri' => 'urn:manual']);
$client->__setCookie('manual_session', 'request-42');
echo $client->__soapCall('readManualCookie', []), "\n";
Ожидаемый результат
request-42

Loopback-сервис читает обычный HTTP Cookie. Если договор требует SOAP Header, __setCookie — не тот инструмент. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. Пустая строка и отсутствие cookie — разные состояния. Не используйте cookie вместо SOAP Header/HTTP Authorization, если сервис требует другой механизм. Не переиспользуйте клиент с чужим session cookie.

Связанные операции: SoapClient::__getCookies.

SoapClient::__setLocationМеняет endpoint последующих вызовов и возвращает прежний override. <code>null</code> или пустая строка очищают override; endpoint из WSDL становится fallback только в WSDL-mode. У non-WSDL клиента после очистки нет endpoint до новой настройки.

PHP 5+; $location nullable с PHP 8.0.3 · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__setLocation(?string $location = null): ?string

Меняет endpoint последующих вызовов и возвращает прежний override. null или пустая строка очищают override; endpoint из WSDL становится fallback только в WSDL-mode. У non-WSDL клиента после очистки нет endpoint до новой настройки.

Метод и документированная запись. SoapClient::__setLocation(?string $location = null): ?string. Reflection PHP 8.5.11: SoapClient::__setLocation(?string $location = null): ?string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
?string $location = nullEndpoint URL для HTTP-запроса; это адрес транспорта, а не target namespace.

Возврат и договор. Возвращает прежний endpoint как string либо null. Изменяет состояние именно текущего клиента.

Отказ. Неверный/запрещённый URL проявится при следующем вызове. URL из пользовательского ввода создаёт SSRF-риск.

Путь данных именно этого вызова
  1. Клиент хранит основной endpoint.
  2. Метод заменяет его и возвращает старый.
  3. Следующий transport использует новый адрес.
Сменить endpoint и получить прежний адресСамостоятельный пример
<?php
declare(strict_types=1);

$client = new SoapClient(null, ['location' => 'https://primary.example.test/soap', 'uri' => 'urn:manual']);
$old = $client->__setLocation('https://backup.example.test/soap');
echo "old: ", $old, "\n";
$beforeEmpty = $client->__setLocation('');
echo "empty cleared: ", $beforeEmpty, "\n";
echo $client->__setLocation('https://next.example.test/soap') === null ? "after empty: no override\n" : "after empty: override remained\n";
$beforeNull = $client->__setLocation(null);
echo "null cleared: ", $beforeNull, "\n";
echo $client->__setLocation('https://last.example.test/soap') === null ? "after null: no override\n" : "after null: override remained\n";
Ожидаемый результат
old: https://primary.example.test/soap
empty cleared: https://backup.example.test/soap
after empty: no override
null cleared: https://next.example.test/soap
after null: no override

И пустая строка, и null очищают location override. WSDL-клиент после очистки снова берёт endpoint из WSDL; у non-WSDL клиента fallback нет, поэтому до запроса нужно снова задать location или передать per-call option. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Переключить настроенный клиент на работающий loopback endpointСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => 'http://127.0.0.1:1/unavailable', 'uri' => 'urn:manual']);
$previous = $client->__setLocation($url);
echo str_contains((string) $previous, ':1/') ? "old endpoint recorded\n" : "old endpoint differs\n";
echo $client->__soapCall('sum', [new SoapParam(8, 'a'), new SoapParam(9, 'b')]), "\n";
Ожидаемый результат
old endpoint recorded
17

Failover выполняется до запроса; не нужно ждать заведомо недоступный адрес в учебном опыте. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. Location nullable с PHP 8.0.3. Failover адреса задают allowlist/конфигурацией. Смена location не меняет target namespace, SOAPAction и XSD-контракт.

Связанные операции: SoapClient::__soapCall, SoapClient::__construct.

SoapClient::__setSoapHeadersЗадаёт default SOAP headers для всех последующих вызовов клиента либо очищает их.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapClient::__setSoapHeaders(SoapHeader|array|null $headers = null): bool

Задаёт default SOAP headers для всех последующих вызовов клиента либо очищает их.

Метод и документированная запись. SoapClient::__setSoapHeaders(SoapHeader|array|null $headers = null): bool. Reflection PHP 8.5.11: SoapClient::__setSoapHeaders(mixed $headers = null): bool. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
mixed $headers = nullОдин SoapHeader, массив заголовков либо null для удаления ранее установленных.

Возврат и договор. Возвращает bool успеха. Один SoapHeader или массив заменяет предыдущий набор; null удаляет его.

Отказ. Прямой аргумент другого типа (например string/stdClass) даёт TypeError. Массив принимается как container, но любой элемент не SoapHeader вызывает немедленный фатальный E_ERROR «Invalid SOAP header», который обычный try/catch не перехватывает. Семантически неверный namespace обычно обнаруживает удалённый сервис.

Путь данных именно этого вызова
  1. Код создаёт типизированные SoapHeader.
  2. Метод сохраняет набор в состоянии клиента.
  3. Каждый следующий Envelope получает эти headers до замены/очистки.
Установить default header, затем удалить егоСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '3'));
$client->__setSoapHeaders(new SoapHeader('urn:meta', 'RequestId', 'req-1'));
$client->__soapCall('sum', [new SoapParam(1, 'a'), new SoapParam(2, 'b')]);
echo str_contains($client->seenRequest, 'req-1') ? "header sent\n" : "missing\n";
$client->__setSoapHeaders(null);
$client->__soapCall('sum', [new SoapParam(1, 'a'), new SoapParam(2, 'b')]);
echo str_contains($client->seenRequest, 'req-1') ? "header kept\n" : "header cleared\n";
Ожидаемый результат
header sent
header cleared

Метод заменяет весь default header set. Null удаляет прежние значения для будущих вызовов. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Отправить correlation id и locale двумя SOAP headersСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/mock-soap.php';
$client = new ManualMockSoapClient(manualSoapResponse('sum', 'int', '3'));
$ok = $client->__setSoapHeaders([
    new SoapHeader('urn:meta', 'RequestId', 'req-42'),
    new SoapHeader('urn:meta', 'Locale', 'ru-RU'),
]);
$client->__soapCall('sum', [new SoapParam(1, 'a'), new SoapParam(2, 'b')]);
echo $ok ? "headers accepted\n" : "headers rejected\n";
echo str_contains($client->seenRequest, 'req-42') && str_contains($client->seenRequest, 'ru-RU') ? "both sent\n" : "missing value\n";
Ожидаемый результат
headers accepted
both sent

Массив нужен для нескольких sibling элементов Header, а не для произвольного вложенного XML. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Default header легко случайно перенести в другой вызов. Для одноразового значения используйте четвёртый аргумент __soapCall. Никогда не печатайте auth header в журнал без маскирования.

Связанные операции: SoapHeader::__construct, SoapClient::__soapCall.

SoapServer::__constructСоздаёт SOAP endpoint в WSDL или non-WSDL mode и задаёт политику сериализации/ошибок.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::__construct(?string $wsdl, array $options = [])

Создаёт SOAP endpoint в WSDL или non-WSDL mode и задаёт политику сериализации/ошибок.

Метод и документированная запись. SoapServer::__construct(?string $wsdl, array $options = []). Reflection PHP 8.5.11: SoapServer::__construct(?string $wsdl, array $options = []). Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
?string $wsdlURL или локальный путь к WSDL; null включает non-WSDL mode, где приложение само задаёт uri и endpoint.
array $options = []Ассоциативный массив настроек. Допустимые ключи зависят от client/server и подробно разобраны в карточке конструктора.

Возврат и договор. Конструктор создаёт объект сервера. С WSDL он читает контракт; с null требует uri. Options включают soap_version, actor, encoding, classmap, typemap, cache_wsdl, features, send_errors и trace.

Отказ. Невалидный WSDL/option даёт SoapFault/Error до обработки request. send_errors=true способен раскрыть внутренние сообщения клиенту.

Путь данных именно этого вызова
  1. Сервер загружает WSDL либо ручной namespace.
  2. Приложение регистрирует функции/класс/объект.
  3. handle получает Envelope и возвращает Envelope.
Создать non-WSDL сервер и вернуть суммуСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';

function sum(int $a, int $b): int { return $a + $b; }
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->addFunction('sum');
$response = manualHandle($server, manualSoapRequest('sum', ['a' => 6, 'b' => 7]));
echo manualXmlValue($response), "\n";
Ожидаемый результат
13

Non-WSDL серверу обязательно сообщают target namespace. Строка request передана явно, поэтому пример работает в CLI без HTTP. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Создать сервер по локальному WSDL и выполнить объявленную операциюСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';

function sum(int $a, int $b): int { return $a + $b; }
$server = new SoapServer(__DIR__ . '/service.wsdl', ['cache_wsdl' => WSDL_CACHE_NONE]);
$server->addFunction('sum');
$response = manualHandle($server, manualSoapRequest('sum', ['a' => 10, 'b' => 5]));
echo manualXmlValue($response), "\n";
Ожидаемый результат
15

WSDL задаёт operation/messages/binding; PHP-функция реализует поведение. В production контракт версионируют и проверяют на совместимость до deploy. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. SoapServer не генерирует WSDL из PHP-кода. Server option classmap принимает WSDL type → PHP class; с PHP 8.4 ключ может использовать Clark notation {namespace}type для одинаковых имён из разных namespace. Отдельно проектируйте контракт, ограничения и faults.

Связанные операции: SoapServer::handle, SoapServer::addFunction, SoapServer::setClass.

SoapServer::addFunctionРегистрирует одну или несколько PHP-функций как доступные SOAP-операции.

PHP 5+; int/SOAP_FUNCTIONS_ALL deprecated с PHP 8.4 · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::addFunction(array|string|int $functions): void

Регистрирует одну или несколько PHP-функций как доступные SOAP-операции.

Метод и документированная запись. SoapServer::addFunction(array|string|int $functions): void. Reflection PHP 8.5.11: SoapServer::addFunction(mixed $functions): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
mixed $functionsИмя функции или allowlist имён. Передача int/SOAP_FUNCTIONS_ALL deprecated с PHP 8.4 и опасна экспортом лишних функций.

Возврат и договор. Возвращаемого значения нет. Принимает string или array имён; int/SOAP_FUNCTIONS_ALL ещё принимается, но deprecated с PHP 8.4.

Отказ. Несуществующее/неподходящее имя обнаруживается при регистрации или вызове. Экспорт всех функций раскрывает лишнюю поверхность и поэтому deprecated.

Путь данных именно этого вызова
  1. Код составляет allowlist функций.
  2. SoapServer сохраняет registry.
  3. handle сопоставляет operation с разрешённой функцией.
Экспортировать только одну разрешённую функциюСамостоятельный пример
<?php
declare(strict_types=1);

$server = new SoapServer(null, ['uri' => 'urn:manual']);
function quoteTotal(int $quantity, int $price): int { return $quantity * $price; }
$server->addFunction('quoteTotal');
echo implode(', ', $server->getFunctions()), "\n";
Ожидаемый результат
quoteTotal

Allowlist делает поверхность сервиса явной: локальные вспомогательные функции наружу не выходят. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Экспортировать небольшой явный набор операцийСамостоятельный пример
<?php
declare(strict_types=1);

function reserveStock(string $sku): string { return 'reserved:' . $sku; }
function releaseStock(string $sku): string { return 'released:' . $sku; }
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->addFunction(['reserveStock', 'releaseStock']);
$names = $server->getFunctions();
sort($names);
echo implode(' | ', $names), "\n";
Ожидаемый результат
releaseStock | reserveStock

С PHP 8.4 int/SOAP_FUNCTIONS_ALL deprecated: массив имён безопаснее и показывает намерение. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Сигнатура/порядок входов должны совпасть с WSDL. Output-параметры в PHP-функцию не передают; несколько выходов возвращают ассоциативным массивом имён.

Связанные операции: SoapServer::getFunctions, SoapServer::handle.

SoapServer::addSoapHeaderДобавляет SoapHeader к ответу, формируемому для текущего обрабатываемого запроса.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::addSoapHeader(SoapHeader $header): void

Добавляет SoapHeader к ответу, формируемому для текущего обрабатываемого запроса.

Метод и документированная запись. SoapServer::addSoapHeader(SoapHeader $header): void. Reflection PHP 8.5.11: SoapServer::addSoapHeader(SoapHeader $header): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
SoapHeader $headerГотовый SoapHeader для SOAP-ответа текущего запроса.

Возврат и договор. Возвращаемого значения нет. Header сериализуется рядом с Body только в рамках активного handle().

Отказ. Метод разрешён только во время обработки активного SOAP request. Вызов до/после handle() даёт Error: «may be called only during SOAP request processing». Аргумент другого типа даёт TypeError; неверный namespace/data может дать несовместимый XML.

Путь данных именно этого вызова
  1. Обработчик создаёт SoapHeader.
  2. addSoapHeader прикрепляет его к текущему response context.
  3. handle сериализует Header и Body.
Вернуть correlation id в SOAP Header ответаСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';

function ping(): string
{
    $GLOBALS['manualServer']->addSoapHeader(new SoapHeader('urn:meta', 'RequestId', 'req-42'));
    return 'pong';
}
$manualServer = new SoapServer(null, ['uri' => 'urn:manual']);
$manualServer->addFunction('ping');
$xml = manualHandle($manualServer, manualSoapRequest('ping', []));
echo manualXmlValue($xml, 'RequestId'), "\n";
echo manualXmlValue($xml), "\n";
Ожидаемый результат
req-42
pong

Header добавляется во время текущего handle. Он отделён от бизнес-return и подходит для correlation metadata. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Вернуть остаток лимита отдельным SOAP HeaderСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';

function checkLimit(): string
{
    $GLOBALS['manualServer']->addSoapHeader(new SoapHeader('urn:meta', 'RateLimitRemaining', 9));
    return 'accepted';
}
$manualServer = new SoapServer(null, ['uri' => 'urn:manual']);
$manualServer->addFunction('checkLimit');
$xml = manualHandle($manualServer, manualSoapRequest('checkLimit', []));
echo manualXmlValue($xml, 'RateLimitRemaining'), "\n";
echo manualXmlValue($xml), "\n";
Ожидаемый результат
9
accepted

Метаданные не приходится добавлять в каждую предметную response structure, если это согласовано SOAP-контрактом. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Это SOAP Header, не HTTP header(). Клиент получает его через outputHeaders __soapCall; namespace и mustUnderstand согласуют заранее.

Связанные операции: SoapHeader::__construct, SoapClient::__soapCall.

SoapServer::faultФормирует SOAP Fault и завершает нормальный ответ текущего запроса.

PHP 5+; $lang добавлен в PHP 8.5 · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::fault( string $code, string $string, string $actor = "", mixed $details = null, string $name = "", string $lang = "" ): void

Формирует SOAP Fault и завершает нормальный ответ текущего запроса.

Метод и документированная запись. SoapServer::fault( string $code, string $string, string $actor = "", mixed $details = null, string $name = "", string $lang = "" ): void. Reflection PHP 8.5.11: SoapServer::fault(string $code, string $string, string $actor = "", mixed $details = null, string $name = "", string $lang = ""): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
string $codeSOAP fault code. Для SOAP 1.1 обычно Client/Server, для SOAP 1.2 — соответствующий QName/код договора.
string $stringБезопасное клиентское описание ошибки без трассировки, SQL и секретов.
string $actor = ''URI участника/роли, который создал или должен обработать header/fault; null/пустая строка оставляют значение неуказанным.
mixed $details = nullСтруктурированные дополнительные сведения Fault; не включайте внутренние секреты и stack trace.
string $name = ''Имя удалённой операции, cookie, fault binding или XML-узла — точный смысл задаёт текущий метод.
string $lang = ''Язык текста Fault для SOAP 1.2, например ru; параметр добавлен в PHP 8.5.

Возврат и договор. Возвращаемого значения нет; метод отправляет fault code/string, actor, detail, optional WSDL fault name и с PHP 8.5 language.

Отказ. Метод формирует и выводит SOAP Fault, затем делает bailout: следующий PHP-код не выполняется. Вызывайте его на настроенном SoapServer — обычно из обработчика операции либо для отказа уровня endpoint. Секреты в detail/string уйдут клиенту.

Путь данных именно этого вызова
  1. Обработчик обнаруживает предметный/технический отказ.
  2. Выбирает публичный code/message/detail.
  3. SoapServer сериализует Fault вместо успешного response.
Остановить резервирование и вернуть предметный FaultСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';

function reserve(string $sku): string
{
    $GLOBALS['manualServer']->fault('Client', 'Нет остатка', 'urn:shop', ['sku' => $sku]);
    return 'unreachable';
}
$manualServer = new SoapServer(null, ['uri' => 'urn:manual', 'encoding' => 'UTF-8']);
$manualServer->addFunction('reserve');
ob_start();
register_shutdown_function(static function (): void {
    $xml = (string) ob_get_clean();
    echo manualXmlValue($xml, 'faultcode'), "\n";
    echo manualXmlValue($xml, 'faultstring'), "\n";
});
$manualServer->handle(manualSoapRequest('reserve', ['sku' => 'OUT']));
Ожидаемый результат
SOAP-ENV:Client
Нет остатка

Метод сразу формирует Fault текущего request; код после него не должен считаться продолжением успешной операции. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Указать язык SOAP 1.2 ReasonСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';

function reject(): string
{
    $GLOBALS['manualServer']->fault('Sender', 'Неверный заказ', '', null, '', 'ru');
    return 'unreachable';
}
$manualServer = new SoapServer(null, ['uri' => 'urn:manual', 'soap_version' => SOAP_1_2, 'encoding' => 'UTF-8']);
$manualServer->addFunction('reject');
$request = str_replace(
    'http://schemas.xmlsoap.org/soap/envelope/',
    'http://www.w3.org/2003/05/soap-envelope',
    manualSoapRequest('reject', []),
);
ob_start();
register_shutdown_function(static function (): void {
    $xml = (string) ob_get_clean();
    echo str_contains($xml, 'xml:lang="ru"') ? "lang=ru\n" : "lang missing\n";
    echo manualXmlValue($xml, 'Text'), "\n";
});
$manualServer->handle($request);
Ожидаемый результат
lang=ru
Неверный заказ

Параметр lang добавлен в PHP 8.5 для соответствия SOAP 1.2. Код Fault для реального сервиса сверяют со спецификацией. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Client/Sender используют для проблем запроса, Server/Receiver — для неспособности обработать корректный запрос, но точные QName задаёт договор. Внутренний exception логируют отдельно.

Связанные операции: SoapFault::__construct, SoapServer::handle.

SoapServer::getFunctionsВозвращает список операций, зарегистрированных через addFunction, setClass или setObject.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::getFunctions(): array

Возвращает список операций, зарегистрированных через addFunction, setClass или setObject.

Метод и документированная запись. SoapServer::getFunctions(): array. Reflection PHP 8.5.11: SoapServer::getFunctions(): array. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает array имён. Список отражает текущий server registry, а не полный WSDL contract/доступность зависимостей.

Отказ. Совпавшее имя ещё не доказывает совместимость параметров/return с WSDL.

Путь данных именно этого вызова
  1. Код регистрирует обработчики.
  2. Метод читает registry.
  3. Тест сравнивает allowlist с ожидаемым API.
Проверить реестр после addFunctionСамостоятельный пример
<?php
declare(strict_types=1);

function ping(): string { return 'pong'; }
function health(): string { return 'ok'; }
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->addFunction(['ping', 'health']);
$names = $server->getFunctions();
sort($names);
echo implode(', ', $names), "\n";
Ожидаемый результат
health, ping

Такой smoke-check подтверждает allowlist до запуска HTTP endpoint. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Посмотреть операции уже созданного объектаСамостоятельный пример
<?php
declare(strict_types=1);

final class CatalogService
{
    public function find(string $sku): string { return $sku; }
    public function price(string $sku): int { return 100; }
    private function secret(): string { return 'hidden'; }
}
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->setObject(new CatalogService());
$names = $server->getFunctions();
sort($names);
echo implode(', ', $names), "\n";
Ожидаемый результат
find, price

getFunctions учитывает setObject так же, как setClass: внешними становятся публичные методы; private helper не экспортируется. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Используйте как smoke-check и источник диагностик, а contract tests строите на WSDL + sample requests/faults.

Связанные операции: SoapServer::addFunction, SoapServer::setClass, SoapServer::setObject.

SoapServer::__getLastResponseВозвращает последний XML, сформированный SoapServer, если включён <code>trace</code>.

PHP 8.4+ · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::__getLastResponse(): ?string

Возвращает последний XML, сформированный SoapServer, если включён trace.

Метод и документированная запись. SoapServer::__getLastResponse(): ?string. Reflection PHP 8.5.11: SoapServer::__getLastResponse(): ?string. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
Аргументов нетМетод читает состояние клиента/сервера, созданное предыдущими вызовами.

Возврат и договор. Возвращает string или null. Метод доступен с PHP 8.4.

Отказ. До handle или без trace возвращает null. XML способен содержать персональные/секретные данные.

Путь данных именно этого вызова
  1. handle сериализует return/Fault.
  2. Trace сохраняет копию Envelope.
  3. Метод отдаёт её для теста/диагностики.
Сравнить выведенный и сохранённый responseСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';
function ping(): string { return 'pong'; }
$server = new SoapServer(null, ['uri' => 'urn:manual', 'trace' => true]);
$server->addFunction('ping');
$output = manualHandle($server, manualSoapRequest('ping', []));
$saved = $server->__getLastResponse();
echo is_string($saved) && $saved === $output ? "same response\n" : "different\n";
echo manualXmlValue($output), "\n";
Ожидаемый результат
same response
pong

PHP 8.4+ позволяет читать именно response текущего server object при trace=true. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Увидеть null, когда server trace выключенСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';
function ping(): string { return 'pong'; }
$server = new SoapServer(null, ['uri' => 'urn:manual', 'trace' => false]);
$server->addFunction('ping');
manualHandle($server, manualSoapRequest('ping', []));
echo $server->__getLastResponse() === null ? "trace is off\n" : "response retained\n";
Ожидаемый результат
trace is off

Отсутствие копии не означает, что ответ не сформирован: trace — отдельная диагностическая опция. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Используйте в contract tests и ограниченной диагностике. Не складывайте полный response каждого production-вызова без маскирования/retention policy.

Связанные операции: SoapServer::handle, SoapClient::__getLastResponse.

SoapServer::handleРазбирает SOAP request, вызывает зарегистрированный обработчик и выводит SOAP response.

PHP 5+; $request nullable с PHP 8.0 · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::handle(?string $request = null): void

Разбирает SOAP request, вызывает зарегистрированный обработчик и выводит SOAP response.

Метод и документированная запись. SoapServer::handle(?string $request = null): void. Reflection PHP 8.5.11: SoapServer::handle(?string $request = null): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
?string $request = nullПолный XML SOAP Envelope. В handle(null) сервер читает raw POST body; в тесте строку можно передать явно.

Возврат и договор. Возвращаемого значения нет: XML пишется в output. С явной строкой обрабатывает её; с null читает raw POST body.

Отказ. Невалидный XML/operation/handler error превращается в Fault либо PHP error согласно handler/send_errors. Любой лишний output до Envelope ломает ответ. С PHP 8.0 параметр request nullable: null читает raw POST body.

Путь данных именно этого вызова
  1. Получает Envelope.
  2. Проверяет версию/body/operation и декодирует аргументы.
  3. Вызывает allowlisted handler.
  4. Сериализует return/header/fault в output.
Передать Envelope строкой и получить вычисленный BodyСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';
function multiply(int $a, int $b): int { return $a * $b; }
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->addFunction('multiply');
$request = manualSoapRequest('multiply', ['a' => 6, 'b' => 7]);
$response = manualHandle($server, $request);
echo manualXmlValue($response), "\n";
Ожидаемый результат
42

Явная строка удобна в unit/contract test: видны входной Envelope, выбранный обработчик и точный результат. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Обработать raw POST body на настоящем loopback endpointСамостоятельный пример
<?php
declare(strict_types=1);

$url = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => $url, 'uri' => 'urn:manual']);
echo $client->__soapCall('greet', [new SoapParam('Мир', 'name')]), "\n";
Ожидаемый результат
Здравствуйте, Мир

В server fixture вызывается handle() без аргумента: ext/soap читает реальный HTTP request body, отправленный SoapClient. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. Не echo/var_dump до/во время handle; журнал пишите в error log. HTTP route должен принимать нужный method/content type и иметь limits на body/time/concurrency.

Связанные операции: SoapServer::__construct, SoapServer::fault, use_soap_error_handler.

SoapServer::setClassЭкспортирует публичные методы класса и создаёт handler с переданными constructor args.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::setClass(string $class, mixed ...$args): void

Экспортирует публичные методы класса и создаёт handler с переданными constructor args.

Метод и документированная запись. SoapServer::setClass(string $class, mixed ...$args): void. Reflection PHP 8.5.11: SoapServer::setClass(string $class, mixed ...$args /* optional; Reflection default unavailable */): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
string $classИмя класса обработчика. Публичные методы становятся операциями сервера.
mixed ...$argsАргументы операции. Для SOAP-вызова это упорядоченный/именованный массив; для setClass — variadic аргументы конструктора обработчика.

Возврат и договор. Возвращаемого значения нет. Вызов меняет модель обработчиков сервера; persistence относится именно к объекту этого класса.

Отказ. Ошибка конструктора/метода превращается по server error policy. Публичный служебный метод может случайно стать доступной операцией.

Путь данных именно этого вызова
  1. Регистрируется имя класса и constructor args.
  2. На request SoapServer создаёт/восстанавливает объект.
  3. Operation вызывает соответствующий публичный метод.
Экспортировать сервис доставки как классСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';
final class DeliveryService
{
    public function estimate(string $city): string { return $city . ': 2 дня'; }
}
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->setClass(DeliveryService::class);
$response = manualHandle($server, manualSoapRequest('estimate', ['city' => 'Тула']));
echo manualXmlValue($response), "\n";
Ожидаемый результат
Тула: 2 дня

Методы одного предметного сервиса и его зависимости собраны в объекте, а не разбросаны по глобальным функциям. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Передать конфигурацию в конструктор обработчикаСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';
final class PriceService
{
    public function __construct(private string $currency, private int $rate) {}
    public function quote(int $units): string { return ($units * $this->rate) . ' ' . $this->currency; }
}
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->setClass(PriceService::class, 'RUB', 125);
$response = manualHandle($server, manualSoapRequest('quote', ['units' => 3]));
echo manualXmlValue($response), "\n";
Ожидаемый результат
375 RUB

Variadic args идут в конструктор при создании handler object. Секреты лучше передавать через настроенный dependency container, а не hardcode. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. Делайте SOAP-facing class узким фасадом; валидация и domain service остаются отдельными зависимостями. Сверяйте public methods с WSDL allowlist.

Связанные операции: SoapServer::setObject, SoapServer::setPersistence, SoapServer::getFunctions.

SoapServer::setObjectНазначает конкретный уже созданный объект обработчиком SOAP-операций.

PHP 5+; актуальные изменения отмечены · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::setObject(object $object): void

Назначает конкретный уже созданный объект обработчиком SOAP-операций.

Метод и документированная запись. SoapServer::setObject(object $object): void. Reflection PHP 8.5.11: SoapServer::setObject(object $object): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
object $objectПроверяемое значение либо конкретный объект-обработчик — смысл зависит от операции; тип указан в сигнатуре.

Возврат и договор. Возвращаемого значения нет. Публичные методы объекта становятся registry сервера; объект используется в текущем request/process.

Отказ. Несовместимый public method/исключение объекта даст Fault. Объект с request-specific данными нельзя безопасно делить между чужими запросами.

Путь данных именно этого вызова
  1. Приложение собирает object с зависимостями.
  2. setObject передаёт его SoapServer.
  3. handle вызывает метод на том же экземпляре.
Передать уже настроенный объект со своим состояниемСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';
final class WarehouseService
{
    public function __construct(private string $warehouse) {}
    public function locate(string $sku): string { return $sku . '@' . $this->warehouse; }
}
$handler = new WarehouseService('MSK-1');
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->setObject($handler);
$response = manualHandle($server, manualSoapRequest('locate', ['sku' => 'A-17']));
echo manualXmlValue($response), "\n";
Ожидаемый результат
A-17@MSK-1

Объект можно заранее собрать с проверенной конфигурацией и зависимостями. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Подменить реальную зависимость test double без изменения SOAP слояСамостоятельный пример
<?php
declare(strict_types=1);

require __DIR__ . '/soap-server-helper.php';
final class StatusStub
{
    public function __construct(private string $status) {}
    public function orderStatus(int $id): string { return $id . ':' . $this->status; }
}
$server = new SoapServer(null, ['uri' => 'urn:manual']);
$server->setObject(new StatusStub('ready'));
$response = manualHandle($server, manualSoapRequest('orderStatus', ['id' => 731]));
echo manualXmlValue($response), "\n";
Ожидаемый результат
731:ready

Contract test управляет состоянием handler object без БД/банка, а сериализацию оставляет настоящему SoapServer. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; внешняя сеть и рабочие сервисы не используются.

Тонкости. setObject и setClass — альтернативные модели. Для session persistence официальный механизм относится к setClass; long-running worker требует явного сброса mutable state.

Связанные операции: SoapServer::setClass, SoapServer::getFunctions.

SoapServer::setPersistenceВыбирает новый handler object на request или сохранение объекта setClass в PHP session.

PHP 5+; session-extension failure исправлен/явно сигнализируется с PHP 8.4 · soap; XML/libxml; HTTP transport for real remote calls

SoapServer::setPersistence(int $mode): void

Выбирает новый handler object на request или сохранение объекта setClass в PHP session.

Метод и документированная запись. SoapServer::setPersistence(int $mode): void. Reflection PHP 8.5.11: SoapServer::setPersistence(int $mode): void. Круглые скобки запускают операцию, аргументы передают входные данные, а возвращаемое значение можно сохранить справа от =. Для SOAP важно разделять PHP-значение, XML Envelope, HTTP transport и удалённый обработчик: ошибка на каждом слое выглядит по-разному. Как устроен вызов функции.

ПараметрЧто передать и зачем
int $modeSOAP_PERSISTENCE_REQUEST либо SOAP_PERSISTENCE_SESSION; session mode требует session_start() до установки.

Возврат и договор. Возвращаемого значения нет. Допустимы SOAP_PERSISTENCE_REQUEST и SOAP_PERSISTENCE_SESSION. Session mode требует session_start() до вызова.

Отказ. В function mode метод всегда даёт Error. После setClass неизвестный mode даёт ValueError; разрешены только REQUEST/SESSION. Для SESSION документация требует session_start() до setPersistence; с PHP 8.4 отсутствие session extension даёт Error вместо прежнего тихого отказа. Resources/DB connections не сериализуются нормально.

Путь данных именно этого вызова
  1. setClass задаёт handler class.
  2. Request mode создаёт объект заново.
  3. Session mode восстанавливает/сохраняет object state по session cookie.
Получить новый объект на каждый HTTP requestСамостоятельный пример
<?php
declare(strict_types=1);

$base = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => $base . '?persistence=request', 'uri' => 'urn:manual']);
echo $client->__soapCall('increment', []), "\n";
echo $client->__soapCall('increment', []), "\n";
Ожидаемый результат
1
1

SOAP_PERSISTENCE_REQUEST — значение по умолчанию: каждый HTTP request получает новый CounterService. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Сохранить объект между двумя запросами одной сессииСамостоятельный пример
<?php
declare(strict_types=1);

$base = getenv('SOAP_TEST_URL') ?: throw new RuntimeException('SOAP_TEST_URL missing');
$client = new SoapClient(null, ['location' => $base . '?persistence=session', 'uri' => 'urn:manual']);
echo $client->__soapCall('increment', []), "\n";
echo $client->__soapCall('increment', []), "\n";

final class PersistenceProbe {}
$classServer = new SoapServer(null, ['uri' => 'urn:manual']);
$classServer->setClass(PersistenceProbe::class);
try {
    $classServer->setPersistence(999);
} catch (ValueError $error) {
    echo "invalid mode: ValueError\n";
}
$functionServer = new SoapServer(null, ['uri' => 'urn:manual']);
try {
    $functionServer->setPersistence(SOAP_PERSISTENCE_REQUEST);
} catch (Error $error) {
    echo "function mode: Error\n";
}
Ожидаемый результат
1
2
invalid mode: ValueError
function mode: Error

SOAP_PERSISTENCE_SESSION сериализует handler object в PHP session; затем пример фиксирует ValueError неверного mode в class mode и Error попытки persistence в function mode. Пример выполнен на локальном PHP 8.5.11 с process-only ext/soap; HTTP endpoint — одноразовый loopback-сервер, без внешней сети.

Тонкости. Stateful SOAP усложняет масштабирование, блокировки сессий и повтор запросов. Предпочитайте явный state в БД/cache; при необходимости реализуйте __sleep/__wakeup для resources и защищайте session cookie.

Связанные операции: SoapServer::setClass, SoapClient::__getCookies.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.