通过 PHP 获取远程 XML 文件的一部分最有效的方法是什么?
这个问题无法具体回答,因为它有很多含义。
实际上,您在这里处理的是远程服务。我通常建议总是包装/代理这些(比较:The Daily Mistake: Not to Proxy Remote Services)。这是因为它们总是带有许多含义。您已经通过将数据检索包装到一个函数中来部分地做到这一点:
function slug_get_coordinates( $zip ) {
$url = "http://maps.googleapis.com/maps/api/geocode/xml?address={$zip}&sensor=false";
$result = simplexml_load_file( $url );
$coordinates = $result->result->geometry->location;
return $coordinates;
}
然而,这个单一的功能不足以处理此类服务可能带来的所有问题。例如。远程位置可能刚刚关闭 - 这样的 响应超时 可能符合条件 - 或者正如您所经历的那样,它需要的时间太长了。
所以你对服务质量基本不满意。
由于远程服务很常见,您无法完全控制它们并且您对服务质量的影响很小,包装它的好处是您可以在包装器中处理此类问题,因此保护您的应用程序逻辑的其余部分免受所有这些影响。
这不仅需要您封装数据的解析(就像您开始使用您拥有的功能一样),还需要封装检索(远程请求)。您还需要进行函数中缺少的错误处理。这里的另一个提示是为失败而设计。例如。即使您尝试检索(添加)的信息丢失,您的应用程序仍然可以工作。
这种代理的另一个好处是,您可以在其中实现调试功能。比如你提供的代码,我快速检索数据完全没有问题:
$zip = '55416';
$start = microtime(true);
slug_get_coordinates($zip)->asXML('php://output');
printf("\n----\nTook %.5f seconds\n", microtime(true) - $start);
输出:
<location>
<lat>44.9465193</lat>
<lng>-93.3439291</lng>
</location>
----
Took 0.11873 seconds
如果您需要更深入地了解远程请求,您可以挂钩到 PHP 的流通知。我已经编译了一个StreamNotifyPrinter,它可以完成这项工作并且可以轻松注册:
$zip = '55416';
$notifier = new StreamNotifyPrinter();
libxml_set_streams_context($notifier->registerOnContext());
$start = microtime(true);
slug_get_coordinates($zip)->asXML('php://output');
printf("\n----\nTook %.5f seconds\n", microtime(true) - $start);
输出:
2014-07-12T09:07:40.146422+0000 [0.00000] Connected...
2014-07-12T09:07:40.228122+0000 [0.08170] Found the mime-type: application/xml; charset=UTF-8
2014-07-12T09:07:40.228251+0000 [0.08183] Made some progress, downloaded 0 so far
2014-07-12T09:07:40.228341+0000 [0.08192] Made some progress, downloaded 757 so far
<location>
<lat>44.9465193</lat>
<lng>-93.3439291</lng>
</location>
----
Took 0.11873 seconds
如果这些信息还不够,您可能需要切换传输层(例如,使用 Curl 作为 Jack suggested,它有一个更专业的 API 用于调试请求;请参阅 Php - Debugging Curl )。
最后一招:如果您无法通过故障排除解决问题,将其正确包装可能会很容易用更好的工作数据库替换远程服务。但也许检查一下地理坐标是否真的可以很好地与邮政编码一起使用:Where can I obtain an up-to-date list of US ZIP Codes with Latitude and Longitude Geocodes?。