使用garethp/php-ews处理EWS推送通知遇SOAP编码错误求助
object has no 'SubscriptionStatus' property 我之前也踩过SOAP编码匹配的坑,结合你的代码和描述,咱们一步步来排查和解决:
1. 先检查SendNotificationResultType类的定义
这个错误大概率是类属性和SOAP元素的映射出了问题。你可以打开库文件garethp/ews/src/API/Message/SendNotificationResultType.php,确认几个点:
- 类里有没有定义
SubscriptionStatus相关的属性?比如是不是写成了小写开头的subscriptionStatus? - 对应的
setSubscriptionStatus方法是否正确关联到了属性,并且有没有SOAP序列化的注释?
如果类里确实没有这个属性,或者注释缺失,你可以手动补充:
use garethp\ews\API\Enumeration\SubscriptionStatusType; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\XmlElement; class SendNotificationResultType { // ... 其他代码 ... /** * @var SubscriptionStatusType * @SerializedName("SubscriptionStatus") * @XmlElement(namespace="http://schemas.microsoft.com/exchange/services/2006/messages") */ protected $subscriptionStatus; public function setSubscriptionStatus($status) { $this->subscriptionStatus = $status; return $this; } }
(注意命名空间要和WSDL里的一致)
2. 验证WSDL与类的结构匹配
打开你修改的NotificationService.wsdl,找到SendNotificationResultType的定义,确认它的元素声明是不是这样:
<xs:complexType name="SendNotificationResultType"> <xs:sequence> <xs:element name="SubscriptionStatus" type="tns:SubscriptionStatusType"/> </xs:sequence> </xs:complexType>
如果WSDL里的元素名(比如SubscriptionStatus)和类里的属性名/序列化注释不匹配,SOAP扩展就会抛出"属性不存在"的错误。
3. 临时绕过类,直接返回数组测试
如果暂时不想修改库代码,可以尝试直接返回符合WSDL结构的数组,代替SendNotificationResultType对象:
// 替换原来的返回逻辑 return [ 'SubscriptionStatus' => SubscriptionStatusType::OK ];
SoapServer对数组的映射通常更直接,这样能快速验证是不是类的序列化问题。
4. 开启SOAP调试日志,抓包看XML
排查SOAP问题最有效的方式是看实际的请求/响应XML。在初始化SoapServer前添加这些配置:
ini_set('soap.wsdl_cache_enabled', 0); ini_set('soap.trace', 1);
然后在handle()之后打印日志:
$server->handle(); // 打印请求和响应XML,方便排查 echo "Request XML:\n" . $server->__getLastRequest() . "\n"; echo "Response XML:\n" . $server->__getLastResponse() . "\n";
通过XML你能直观看到:Exchange发来的请求结构是否符合预期,你的服务返回的响应里有没有正确包含<SubscriptionStatus>元素,以及命名空间是否正确。
5. 跟进库的Issue进展
你提到已经给garethp/php-ews提交了Issue,这步很对。很多时候这类问题是库本身的bug(比如旧版本遗漏了Push响应的属性定义),可以关注作者的回复,要么等官方修复,要么自己fork库修改对应的类文件临时解决。
内容的提问来源于stack exchange,提问作者AJefferiss

