如何在PHP8.0中使用WebAPI

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Tech Education Fund 来接受捐赠。

介绍

RESTful API 以各种方式和多种不同的目的使用,例如资源共享、任务自动化、远程验证等。 例如,一些提供 API 的平台包括 Facebook、LinkedIn、Twitter、GitHub 和 DigitalOcean。 通过利用这些平台的 API,您的应用程序可以与这些远程系统进行交互,而无需人工干预。 例如,您可以让您的应用程序将图片发布到其用户的 Facebook 墙上,使用 LinkedIn 来证实用户的身份,并在负载过重时生成新的 Digital Ocean 液滴。

如果您熟悉使用 PHP 进行 应用程序开发,您将能够使用现有服务来支持您的应用程序,而无需从头开始编写大型程序或保持复杂的基础设施在线。

在本教程中,您将使用 HTTP POST 和 GET 调用为 RESTful API 构建客户端以与服务器交互。 您将构建一个 Web 应用程序,该应用程序将从 OpenWeather Map API 获取信息并显示它。 在启用用户输入并使用软件开发工具包 (SDK) 帮助代码适应未来发展之前,您将从一个基本应用程序开始。 最终的网络应用程序将为用户提供他们选择的城市的实时天气信息。

在处理新的 API 时,一个很好的起点是阅读文档。 在这种情况下,您可以在 OpenWeather 指南 中找到有用的信息。

先决条件

要完成本教程,您需要:

  • 启用 XML 支持的 PHP 本地开发环境,您可以按照教程的第 1 步进行操作,如何在 Ubuntu 20.04 上安装 PHP 7.4 和设置本地开发环境。 在步骤 1 结束时安装附加包时,在需要的地方将 php7.4 替换为 php8.0 并从包安装命令中删除 php7.4-json
  • Composer 安装在您的机器上,您可以按照教程 如何安装和使用 Composer 的步骤 1-2 进行操作。
  • 熟悉 PHP,您可以从教程系列 How To Code in PHP 中获得。
  • OpenWeather Map的API密钥,您可以通过创建一个免费帐户来获得。 注册后,导航到您帐户下的我的API密钥

第 1 步 — 为 Web 应用程序构建界面

在此步骤中,您将构建 Web 应用程序的基本版本,您将在后面的步骤中对其进行修改。 在这里,您将创建一个 HTML 表单和一个请求处理程序。

首先为项目创建一个目录(weather-app)并导航到它。

mkdir weather-app 
cd weather-app

使用您喜欢的文本编辑器或 nano,创建一个 index.php 文件:

nano index.php

将以下内容复制到您的文件中:

天气应用程序/index.php

<html>
<body>
    <h1>Weather query</h1>
<?php
if ( 'post' === strtolower($_SERVER['REQUEST_METHOD']) ) {
?>
    <h2>6.36</h2>
<?php
} else {
?>
    <form method="post">
        <input type="submit" value="Get London's temperature">
    </form>
<?php
}
?>
</body>
</html>

第一个 if 语句将 HTML 表单和请求处理程序分开。 它正在检查的条件 ('post' === strtolower($_SERVER['REQUEST_METHOD'])) 是验证使用哪个 HTTP 动词来生成请求。 在这里,您使用比较 'post' === strtolower($_SERVER['REQUEST_METHOD']) 而不是简单的 'post' === $_SERVER['REQUEST_METHOD'] 来规范化值,而不是依赖于网络服务器或浏览器配置。

如果方法是post,则表示请求来自表单提交,所以我们知道我们在第二步。 如果方法不是 post,您可以放心地假设这是用户第一次访问该站点,因此向他们展示表单并让他们启动工作流程是有意义的,在这种情况下,这意味着要求伦敦的温度。

仔细查看 if 语句的 then 部分,您会注意到有一个固定的 6.36 值。 这是一个随机占位符编号,稍后您将用实时数据替换它。

完成后保存并关闭文件。

接下来,通过运行以下命令启动内置 PHP Web 服务器:

php -S localhost:8707

输出将如下所示:

[Wed Nov 17 11:54:10 2021] PHP 8.0.12 Development Server (http://localhost:8707) started

然后,在浏览器中打开一个新选项卡并将其指向 http://localhost:8707

注意:如果你使用的是远程机器,如先决条件教程,如何在Ubuntu 20.04上安装PHP 7.4并设置本地开发环境,可以使用端口转发查看你的应用程序。 启动 PHP Web 服务器后,在本地计算机上打开一个新终端并运行以下命令:ssh -L 8707:localhost:8707 your-non-root-user@your-server-ip。 成功连接远程服务器后,您可以在http://localhost:8707查看您的应用程序。


您将看到一个类似于此的屏幕:

点击【X9X】获取伦敦温度【X37X】查看结果:

由于数据当前在应用程序中是硬编码的,因此 6.36 是唯一可能的响应。

在这一步中,您创建了一个 Web 应用程序,该应用程序允许用户发起对当前硬编码的伦敦当前温度的查询。 在下一步中,您将更新您的应用程序以从 API 检索数据。

第 2 步 — 从 RESTful API 检索数据

在此步骤中,您将更新您的应用程序以从可信来源(OpenWeather Map)获取数据。

您可以通过多种方式使用 PHP 从 RESTful API 获取信息。 最常见的方法之一是使用 curl 库。 虽然这个库功能完善,但它是为对 HTTP 通信进行低级控制而设计的,这在许多情况下会变得很麻烦。

在这里,您将使用函数 file_get_contents 从 RESTful API 中读取。 您可能对使用此函数读取本地文件很熟悉,但 PHP 的 流管理系统 对许多底层存储机制提供了相同的抽象。 您可以使用 file_get_contents 从远程文件中读取,就像它存在于本地驱动器上一样。 由于 RESTful 资源由 URI 标识,因此您可以将其端点提供给函数,它将返回远程服务器发送的响应的内容(已经去除了标头)。

如果您需要以更复杂的方式与服务器交互——例如使用身份验证——您可以通过指定特定的 stream_context 作为第三个参数来实现。

要从 OpenWeather Map API 检索数据,请打开 index.php 进行编辑和更新,如下所示:

天气应用程序/index.php

<html>
<body>
    <h1>Weather query</h1>
<?php
if ( 'post' === strtolower($_SERVER['REQUEST_METHOD'])) {
?>
    <h2><?php echo file_get_contents('https://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric&q=London&appid=YOUR_API_KEY'); ?></h2>
<?php
} else {
    ?>
    <form method="post">
        <input type="submit" value="Get London's temperature">
    </form>
<?php
}?>
</body>
</html>

请记住将 YOUR_API_KEY 更改为 OpenWeather API 密钥的实际值。

该脚本采用一个固定的 URL https://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric&q=London&appid=YOUR_API_KEY,进行 HTTP 调用,并完全按照收到的响应输出。

此 URL 由以下部分组成:

这是 RESTful API 的常见结构。 无论您要查找什么资源,基本 URL 都将是相同的。 端点将根据您要查找的特定信息类型而有所不同,最后,查询字符串将用于提供一些选项来优化您的请求。

在这种情况下,我们使用以下修饰符:

  • mode:我们希望响应使用的格式,在我们的例子中是 xml
  • units:测量单位,在我们的例子中是 metric
  • q:城市表达式,在我们的例子中是 London
  • appid:API 密钥。

更多参数请参见OpenWeather 产品文档

完成后保存并关闭文件。

返回浏览器并刷新页面以查看结果。 输出将类似于以下内容:

此时,结果不是用户所期望的:这将返回英国的国家名称 (GB) 和时区 (3600)。

如果您查看该页面的源代码,您将看到类似于以下内容的输出:

Web 应用程序的源代码

<html>
<body>
<h1>Weather query</h1>
<h2>
  <?xml version="1.0" encoding="UTF-8"?>
  <current>
    <city id="2643743" name="London">
      <coord lon="-0.1257" lat="51.5085"></coord>
      <country>GB</country>
      <timezone>3600</timezone>
      <sun rise="2022-04-12T05:11:24" set="2022-04-12T18:50:48"></sun>
    </city>
    <temperature value="18.21" min="15.02" max="19.87" unit="celsius"></temperature>
    <feels_like value="17.73" unit="celsius"></feels_like>
    <humidity value="63" unit="%"></humidity>
    <pressure value="1006" unit="hPa"></pressure>
    <wind>
      <speed value="4.63" unit="m/s" name="Gentle Breeze"></speed>
      <gusts></gusts>
      <direction value="210" code="SSW" name="South-southwest"></direction>
    </wind>
    <clouds value="40" name="scattered clouds"></clouds>
    <visibility value="10000"></visibility>
    <precipitation mode="no"></precipitation>
    <weather number="802" value="scattered clouds" icon="03d"></weather>
    <lastupdate value="2022-04-12T14:11:48"></lastupdate>
  </current>
</h2>
</body>
</html>

问题是您的脚本输出 API 服务器的响应与它收到的完全一样,因此由浏览器来正确呈现它。 由于 API 服务器的响应是 XML,浏览器会尽其所能解释标签:所有非 HTML 标签(例如 citytemperature 等)都会被浏览器忽略. 为了解决这个问题,您将更新应用程序以解析 XML 响应并提取对用户有意义的片段 — temperature 标记的内容。

在此步骤中,您更新了应用程序以查询远程 API 并获取实时信息。 在下一步中,您将更新应用程序以解析它接收到的 XML 数据。

第 3 步 — 显示数据

此时,您的应用程序会查询远程服务器并接收响应。 由于接收到的信息是 XML,因此需要对其进行解析以获取特定的信息,例如城市的温度。 在此步骤中,您将更新应用程序以转换 XML 响应以显示与用户相关的信息。

一种方法是手动解析数据,例如通过正则表达式。 然而,这种方法既复杂又容易出错。 更好的方法是使用类 SimpleXMLElement。 此类专门设计用于处理复杂的 XML,并提供易于使用的界面。

打开您的 index.php 文件进行编辑并将其更新为如下所示:

天气应用程序/index.php

<html>
<body>
    <h1>Weather query</h1>
<?php
if ( 'post' === strtolower($_SERVER['REQUEST_METHOD'])) {
    ?><h2><?php
    $xml = new SimpleXMLElement('https://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric&q=London&appid=YOUR_API_KEY', 0, true);
    echo $xml->temperature['value'];
    ?></h2>
<?php
} else {
    ?>
    <form method="post">
        <input type="submit" value="Get London's temperature">
    </form>
<?php
}?>
</body>
</html>

请记住将 YOUR_API_KEY 替换为 API 密钥的实际值。

$xmlSimpleXMLElement 的一个实例。 XML 文本中的每个子节点都是它的公共属性,并且属性可以作为数组键访问。

对类构造函数的调用是通过提供三个参数来完成的。 第一个是数据源。 在这种情况下,您指定一个 URL 作为 XML 数据的源:https://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric&q=London&appid=YOUR_API_KEY

接下来是一个选项修饰符,它指定如何解释 XML。 在这种情况下,您使用的是 0,这意味着应该使用默认选项。 第三个参数是 true 值。 可以使用两种可能的来源创建 SimpleXMLElement 对象:文字 XML 值或 URL。 通过发出 true,您是说要使用 URL。

echo $xml->temperature['value']; 行利用了 SimpleXMLElement 提供的面向对象接口。 该类的基本功能是将应该是格式良好的 XML 的字符串转换为易于使用的树形结构。

因此,如果您回顾一下服务器返回的 XML:

Web 应用程序的源代码

<?xml version="1.0" encoding="UTF-8"?>
  <current>
    <city id="2643743" name="London">
      <coord lon="-0.1257" lat="51.5085"></coord>
      <country>GB</country>
      <timezone>3600</timezone>
      <sun rise="2022-04-12T05:11:24" set="2022-04-12T18:50:48"></sun>
    </city>
    <temperature value="18.21" min="15.02" max="19.87" unit="celsius"></temperature>
    <feels_like value="17.73" unit="celsius"></feels_like>
    <humidity value="63" unit="%"></humidity>
    <pressure value="1006" unit="hPa"></pressure>
    <wind>
      <speed value="4.63" unit="m/s" name="Gentle Breeze"></speed>
      <gusts></gusts>
      <direction value="210" code="SSW" name="South-southwest"></direction>
    </wind>
    <clouds value="40" name="scattered clouds"></clouds>
    <visibility value="10000"></visibility>
    <precipitation mode="no"></precipitation>
    <weather number="802" value="scattered clouds" icon="03d"></weather>
    <lastupdate value="2022-04-12T14:11:48"></lastupdate>
  </current>

您会看到 $xml 对象具有以下属性:

  • city
  • temperature
  • feels_like
  • humidity
  • pressure
  • wind
  • clouds
  • visibility
  • precipitation
  • weather
  • lastupdate

这些属性中的每一个也是 SimpleXMLElement 的一个实例。

在这种情况下,您只对 <temperature/> 元素的属性感兴趣:value。 因此,通过使用 $xml->temperature['value'] 可以得到上例中的 18.21

完成后保存并关闭文件。

返回浏览器,刷新页面,您应该会看到类似于以下内容的内容:

您输出中的数字可能不同。 这是意料之中的,因为应用程序正在执行实时查询。

现在您的应用程序可以解析 XML 数据。 SimpleXMLElement 正在读取您提供的 URL,解析结果,并构建远程服务器返回的文本的面向对象表示。 完成后,您的应用程序可以引用温度值作为 SimpleXMLElement 对象的属性。

此时,您的脚本可以以对最终用户有意义的格式显示取自可信来源的实时信息。 在下一步中,您将通过启用用户输入向应用程序引入交互性。

第 4 步 — 启用用户输入

在此步骤中,您将使用户能够查询不同城市的温度。 您将通过更改数据源 URL 以从远程服务器获得不同的结果来做到这一点。

第一个变化是在第一个屏幕中显示一个城市下拉菜单,以便用户可以选择他们感兴趣的城市。 打开index.php进行编辑更新表格,如图:

天气应用程序/index.php

<html>
<body>
    <h1>Weather query</h1>
<?php
if ( 'post' === strtolower($_SERVER['REQUEST_METHOD'])) {
    ?><h2><?php
    $xml = new SimpleXMLElement('https://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric&q=London&appid=YOUR_API_KEY', 0, true);
    echo $xml->temperature['value'];
    ?></h2>
<?php
} else {
    ?>
    <form method="post">
        <label for="city">Select your city</label>
        <select name="city" id="city">
            <option value="London">London</option>
            <option value="Buenos Aires">Buenos Aires</option>
            <option value="New York">New York</option>
            <option value="Paris">Paris</option>
        </select>
        <input type="submit" value="Get your city's temperature">
    </form>
<?php
}?>
</body>
</html>

现在应用程序将为用户显示一个下拉选项,因此他们可以选择他们想要获取有关哪个城市的信息,而不是将其固定为 London

但是,要让脚本查询所选城市,您还需要更改 if 语句的第一部分。 更新数据源 URL,如下所示:

天气应用程序/index.php

<html>
<body>
    <h1>Weather query</h1>
<?php
if ( 'post' === strtolower($_SERVER['REQUEST_METHOD'])) {
    ?><h2><?php
    $xml = new SimpleXMLElement('`https://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric&q=`'.$_POST['city'].'&appid=YOUR_API_KEY', 0, true);
    echo $xml->temperature['value'];
    ?></h2>
<?php
} else {
    ?>
    <form method="post">
        <label for="city">Select your city</label>
        <select name="city" id="city">
            <option value="London">London</option>
            <option value="Buenos Aires">Buenos Aires</option>
            <option value="New York">New York</option>
            <option value="Paris">Paris</option>
        </select>
        <input type="submit" value="Get your city's temperature">
    </form>
<?php
}?>
</body>
</html>

在这里,您将 q 参数的值从 London 更改为用户选择的城市。 URL 创建为以下内容的串联:

  1. https://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric&q=
  2. $_POST['city']
  3. '&appid=YOUR_API_KEY'

完成后保存并关闭文件。

注意: 这是OpenWeather Map处理参数的方式。 对于其他 API,您必须查阅特定文档以了解详细信息。


要查看您的更改,请返回浏览器并重新开始导航。 您的应用现在应该显示一个用于选择城市的下拉菜单:

选择不同的城市现在应该返回不同的温度值。

在此步骤中,您在应用程序中启用了用户输入,并更新了数据源 URL 以根据用户的选择检索数据。

但是,此时,您的代码与 API 响应的当前结构紧密耦合,这不是非常面向未来的。 目前,将 temperature 标签作为根元素的第一级子元素是有意义的,但这可能随时改变——如果发生这种情况,应用程序代码必须更新以保持它工作。 解决此问题的一种方法是使用软件开发工具包 (SDK),您将在下一步中使用该工具包。

第 5 步 — 安装软件开发工具包 (SDK)

在这一步中,您将安装 OpenWeather Map PHP Client。 此客户端将您的应用程序逻辑与如何与 OpenWeather 地图服务器通信的具体细节完全隔离开来,从而有效地产生一个更具前瞻性的应用程序。 您无需像在前面的步骤中那样手动检索数据,而是使用 SDK 为您检索数据。

在您的应用程序中使用 SDK 会使它们随着时间的推移更易于维护。 例如,如果服务器希望客户端与其交互的方式发生变化,那么您需要做的就是更新您的 SDK。 相比之下,如果您要自己编写请求代码,那么修改代码将需要花费大量精力来跟踪每个远程调用并对其进行更新。 另外,也有可能出现新的错误。

使用 OpenWeather Map PHP SDK 的第一步是安装它。 在本教程中,您将使用 Composer,这是一个 PHP 依赖项管理器,您已将其作为先决条件的一部分进行安装。

有了 Composer 可用后,运行以下命令来安装 SDK 及其依赖项:

composer require "cmfcmf/openweathermap-php-api" "http-interop/http-factory-guzzle:^1.0" "php-http/guzzle6-adapter:^2.0 || ^1.0"

SDK 本身就是包 cmfcmf/openweathermap-php-apihttp-interop/http-factory-guzzlephp-http/guzzle6-adapter 是在较低级别处理 HTTP 通信所需的辅助包。

这将产生以下输出:

Using version ^3.3 for cmfcmf/openweathermap-php-api
./composer.json has been created
Running composer update cmfcmf/openweathermap-php-api http-interop/http-factory-guzzle php-http/guzzle6-adapter
Loading composer repositories with package information
Updating dependencies
Lock file operations: 16 installs, 0 updates, 0 removals
  - Locking cmfcmf/openweathermap-php-api (v3.3.0)
  - Locking guzzlehttp/guzzle (6.5.5)
  - Locking guzzlehttp/promises (1.5.1)
  - Locking guzzlehttp/psr7 (1.8.3)
  - Locking http-interop/http-factory-guzzle (1.2.0)
  - Locking php-http/guzzle6-adapter (v2.0.2)
  - Locking php-http/httplug (2.2.0)
  - Locking php-http/promise (1.1.0)
  - Locking psr/cache (1.0.1)
  - Locking psr/http-client (1.0.1)
  - Locking psr/http-factory (1.0.1)
  - Locking psr/http-message (1.0.1)
  - Locking ralouphie/getallheaders (3.0.3)
  - Locking symfony/polyfill-intl-idn (v1.23.0)
  - Locking symfony/polyfill-intl-normalizer (v1.23.0)
  - Locking symfony/polyfill-php72 (v1.23.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 16 installs, 0 updates, 0 removals
  - Installing psr/http-message (1.0.1): Extracting archive
  - Installing psr/http-factory (1.0.1): Extracting archive
  - Installing psr/http-client (1.0.1): Extracting archive
  - Installing psr/cache (1.0.1): Extracting archive
  - Installing cmfcmf/openweathermap-php-api (v3.3.0): Extracting archive
  - Installing guzzlehttp/promises (1.5.1): Extracting archive
  - Installing ralouphie/getallheaders (3.0.3): Extracting archive
  - Installing guzzlehttp/psr7 (1.8.3): Extracting archive
  - Installing http-interop/http-factory-guzzle (1.2.0): Extracting archive
  - Installing php-http/promise (1.1.0): Extracting archive
  - Installing php-http/httplug (2.2.0): Extracting archive
  - Installing symfony/polyfill-php72 (v1.23.0): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.23.0): Extracting archive
  - Installing symfony/polyfill-intl-idn (v1.23.0): Extracting archive
  - Installing guzzlehttp/guzzle (6.5.5): Extracting archive
  - Installing php-http/guzzle6-adapter (v2.0.2): Extracting archive
2 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
6 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

现在您的项目中有一个新目录:vendor。 这个目录是找到通过 Composer 安装的每个依赖项的地方。

除了库代码之外,还有一个文件可以访问所有这些:autoload.php。 您需要在需要使用您引入的任何依赖项的每个脚本的开头包含此文件。

在这一步中,您向应用程序添加了一个新依赖项:OpenWeather Map API 的面向对象客户端。 通过依赖它,您将获得一个更清晰的编码界面,这将帮助您减少更新代码以匹配新版本的 API 的整体工作量。

第 6 步 — 使用 SDK 重构您的 Web 应用程序

在此步骤中,您将重构代码以使用上一步中安装的 SDK。 您将需要脚本中的 SDK 代码并使用库中提供的对象来访问远程 API。

打开 index.php 进行编辑并将其更新为如下所示:

天气应用程序/index.php

<?php
use Cmfcmf\OpenWeatherMap;
use Cmfcmf\OpenWeatherMap\Exception as OWMException;
use Http\Factory\Guzzle\RequestFactory;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
?>
<html>
<body>
    <h1>Weather query</h1>
<?php
if ( 'post' === strtolower($_SERVER['REQUEST_METHOD'])) {
    require_once 'vendor/autoload.php';
    $city = $_POST['city'];

    $owm = new OpenWeatherMap('YOUR_API_KEY', GuzzleAdapter::createWithConfig([]), new RequestFactory());

    try {
        $weather = $owm->getWeather($city, 'metric', 'en');
        ?><h2><?php echo $weather->temperature; ?></h2>
        <?php
    } catch(OWMException $e) {
        echo 'OpenWeatherMap exception: ' . $e->getMessage() . ' (Code ' . $e->getCode() . ').';
    } catch(\Exception $e) {
        echo 'General exception: ' . $e->getMessage() . ' (Code ' . $e->getCode() . ').';
    }
} else {
    ?>
    <form method="post">
        <label for="city">Select your city</label>
        <select name="city" id="city">
            <option value="London">London</option>
            <option value="Buenos Aires">Buenos Aires</option>
            <option value="New York">New York</option>
            <option value="Paris">Paris</option>
        </select>
        <input type="submit" value="Get your city's temperature">
    </form>
<?php
}?>
</body>
</html>

请记住将 YOUR_API_KEY 替换为您的 API 密钥的实际值。

首先在顶部声明命名空间(use ... 语句)。 通过这些行,您可以指示解释器如何将短类名称映射到完全分类的名称(例如,OpenWeatherMapCmfcmf\OpenWeatherMap),从而使代码更易于阅读和编写。

您还包括了 vendor/autoload.php 文件。 该文件由 composer 创建并包含对 spl_autoload_register 的必要调用,以允许您创建脚本未明确要求的类的新实例。

最显着的变化是使用一种方法 (getWeather) 来调用远程服务器,使您的代码保持干净并且随着时间的推移更容易维护。 为您完成了 HTTP 调用并将文本转换为 PHP 对象。 在某种程度上,您可能会忘记正在进行远程呼叫,就像您可以直接访问天气信息一样工作。 而且,如果来自服务器的响应发生变化,您所要做的就是更新 SDK 版本,而不是修改碰巧调用 API 的代码的每个实例。

接下来,您进行了更改以捕获异常。 在处理外部系统时,预测问题是一种很好的做法,例如远程服务器变得无响应或本地网络出现故障。 如果您没有捕获异常,一旦发生,它们将产生令人不快的用户体验,甚至可能破坏系统稳定性,因为脚本执行会意外停止。

这里,这个脚本中有两个catch语句,方便调试。 由于方法 OpenWeatherMap::getWeather 抛出特定异常(OWMException),因此使用它们并留下另一个 catch-all 异常处理程序以防万一出现未知异常处理程序是有意义的。

完成后保存并关闭文件。

如果刷新页面,您会看到输出略有变化:

现在,摄氏符号出现在温度旁边。

发生这种情况是因为您的应用程序现在使用 echo $weather->temperature; 来生成其输出,并且 $weather->temperatureCmfcmf\OpenWeatherMap\Util\Temperature 类的对象,它实现了 __toString 方法,其中包括返回值中的单位。 如果您想获得与上一步相同的输出,可以使用 echo $weather->temperature->getValue() 代替。

在这一步中,您通过利用现有 SDK 来抽象低级通信细节,使您的应用程序更易于维护。

让您的应用程序可以投入生产只有最后一步:删除硬编码的 API_KEY。 如果密钥仍然是硬编码的,那么每次您在不同的环境中部署应用程序时,您都必须进入代码以使其工作,这是错误的来源。

第 7 步 — 删除硬编码

到目前为止,您一直在处理一段硬编码数据:您的 OpenWeather API 密钥。 删除硬编码信息允许您的应用程序在不同的环境中运行,这对于您希望拥有多个执行上下文(开发、测试、生产等)的实际应用程序来说是一个关键功能。

在此步骤中,您将通过删除硬编码的 API 密钥来准备您的应用程序以在不同环境中部署。

一种技术是将此类信息存储在环境变量中,可以通过 $_ENV 数组在 PHP 脚本中访问这些信息。

要使用这种方法,请打开您的 index.php 文件进行编辑并更新突出显示的部分:

天气应用程序/index.php

<?php
use Cmfcmf\OpenWeatherMap;
use Cmfcmf\OpenWeatherMap\Exception as OWMException;
use Http\Factory\Guzzle\RequestFactory;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
?>
<html>
<body>
    <h1>Weather query</h1>
<?php
if ( 'post' === strtolower($_SERVER['REQUEST_METHOD'])) {
    require_once 'vendor/autoload.php';
    $city = $_POST['city'];

    $owm = new OpenWeatherMap($_ENV['API_KEY'], GuzzleAdapter::createWithConfig([]), new RequestFactory());

    try {
        $weather = $owm->getWeather($city, 'metric', 'en');
        ?><h2><?php echo $weather->temperature; ?></h2>
        <?php
    } catch(OWMException $e) {
        echo 'OpenWeatherMap exception: ' . $e->getMessage() . ' (Code ' . $e->getCode() . ').';
    } catch(\Exception $e) {
        echo 'General exception: ' . $e->getMessage() . ' (Code ' . $e->getCode() . ').';
    }
} else {
    ?>
    <form method="post">
        <label for="city">Select your city</label>
        <select name="city" id="city">
            <option value="London">London</option>
            <option value="Buenos Aires">Buenos Aires</option>
            <option value="New York">New York</option>
            <option value="Paris">Paris</option>
        </select>
        <input type="submit" value="Get your city's temperature">
    </form>
<?php
}?>
</body>
</html>

完成后保存并关闭文件。

要使更改生效,您需要停止本地网络服务器并使用以下命令重新启动它:

API_KEY=YOUR_API_KEY php -d variables_order=EGPCS -S localhost:8707 

YOUR_API_KEY 替换为您的 API 密钥的实际值。

在此调用中,您首先建立环境变量的值,然后调用 PHP 解释器。 操作系统将为 PHP 进程创建一个新的运行环境,包括 API Key 定义。

-d 修饰符应用于 php 命令并用于更改 PHP 的配置。 在这种情况下,variables_order 定义确定了如何填充 super globals。 值 EGPCS 表示 Environment、Get、Post、Cookies、Server。 您可以在 PHP 文档 中阅读有关此 的更多信息。

在生产环境的情况下,您可以使用 webserver 配置来建立这些值。

在此步骤中,您删除了 API 密钥的硬编码并改用环境变量。 您的应用程序现在更适合在不同的环境中运行。

结论

在本文中,您构建了一个 Web 应用程序,允许用户查询 OpenWeather 地图并获取他们选择的城市的当前温度。 您使用 file_get_contents 从远程 RESTful API 检索数据并使用 SimpleXMLElement 解析 XML 数据。 您还使用了 SDK 来访问可用的远程 API。 最后,您更新了应用程序以从环境变量中获取机密,而不是硬编码。

下一步,您可以转向更复杂的 API,看看基本原理是如何相同的。

请记住,RESTful API 并不是唯一存在的 API 类型。 SOAP 是一种非常不同的协议,仍然在许多场景中使用,尤其是在政府机构中,因此您可能还想熟悉其他 API 类型。