首页 > 解决方案 > 将数据存储到数组中,然后在while循环中一个一个地访问它

问题描述


背景



客观的



问题


我的问题是我对如何实现数据的搜索和存储缺乏了解。到目前为止,我有这个尝试访问每个地址并计算距离:

$sql = "SELECT name, address FROM users";
$result = $conn->query($sql);
$distance = []; // an array so we can store our distance result in here
if ($result->num_rows > 0) {
  // output data of each row
  while($row = $result->fetch_assoc()) {
    $distance[] = [
  'name' => $row['name'], // user id so you can use it later
  'distance' => getDistance($row['address'],$addressTo)
] // get the distance from api and save it on an array
  }
}

// now somehow have to get the min distance and name associated with it from that array
  1. 由于某种原因,这甚至无法编译,在 while 循环结束时会出现解析错误

解析错误:语法错误,意外的 '}'

  1. 由于我对数组在 PHP 中的工作方式的理解有限,因此我处理此问题的方式不是很有效(至少在我对其他语言中的数组的理解下)。是否有一种功能或方法可以有效地提取地址和随附的相关名称来执行此操作?我将不胜感激。

距离函数


以供参考

function getDistance($addressFrom, $addressTo, $unit = ''){
    // Google API key
    $apiKey = ' The API key';
    
    // Change address format
    $formattedAddrFrom    = str_replace(' ', '+', $addressFrom);
    $formattedAddrTo     = str_replace(' ', '+', $addressTo);
    
    // Geocoding API request with start address
    $geocodeFrom = file_get_contents('https://maps.googleapis.com/maps/api/geocode/json?address='.$formattedAddrFrom.'&sensor=false&key='.$apiKey);
    $outputFrom = json_decode($geocodeFrom);
    if(!empty($outputFrom->error_message)){
        return $outputFrom->error_message;
    }
    
    // Geocoding API request with end address
    $geocodeTo = file_get_contents('https://maps.googleapis.com/maps/api/geocode/json?address='.$formattedAddrTo.'&sensor=false&key='.$apiKey);
    $outputTo = json_decode($geocodeTo);
    if(!empty($outputTo->error_message)){
        return $outputTo->error_message;
    }
    
    // Get latitude and longitude from the geodata
    $latitudeFrom    = $outputFrom->results[0]->geometry->location->lat;
    $longitudeFrom    = $outputFrom->results[0]->geometry->location->lng;
    $latitudeTo        = $outputTo->results[0]->geometry->location->lat;
    $longitudeTo    = $outputTo->results[0]->geometry->location->lng;
    
    // Calculate distance between latitude and longitude
    $theta    = $longitudeFrom - $longitudeTo;
    $dist    = sin(deg2rad($latitudeFrom)) * sin(deg2rad($latitudeTo)) +  cos(deg2rad($latitudeFrom)) * cos(deg2rad($latitudeTo)) * cos(deg2rad($theta));
    $dist    = acos($dist);
    $dist    = rad2deg($dist);
    $miles    = $dist * 60 * 1.1515;
    
    // Convert unit and return distance
    $unit = strtoupper($unit);
    if($unit == "K"){
        return round($miles * 1.609344, 2).' km';
    }elseif($unit == "M"){
        return round($miles * 1609.344, 2).' meters';
    }else{
        return round($miles, 2).' miles';
    }
}

标签: php

解决方案


遍历数据库中的每个条目并循环调用 API 会非常慢。另外,我注意到您的距离计算是从 lat 和 lng 执行的,而不是由 API 直接返回。

您将获得更好的性能(特别是如果您计划拥有大量数据),将每个地址的 lat 和 lng 存储在数据库中(这意味着您只需为每个新地址调用一次) ,然后在没有 API 调用的情况下执行计算。

更好的是只重写查询,以便它执行计算并返回最高结果。看看这个 db fiddle,里面有一些随机的城市。

https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=56014857919d57a9465938982caced7f

我输出了两个版本的查询,一个显示按距离排序的所有结果,一个限制为最高结果,这样您就可以看到所有城市的排名。

我没有检查距离公式。我试图从你的代码中直接转录,但我没有验证它是否准确,我只是让它在 mySQL 中工作,而且城市的排序似乎是正确的。我没有转换成英里或其他任何东西,所以你可能想在那里检查我的公式,但我假设你比我更了解正确的公式。我只是在这里提供一些 SQL。

计算结果后,在 php 中处理单位转换。

根据您期望拥有的数据量,像这样进行无限制的自我加入可能会减慢速度。有一些方法可以解决这个问题,但由于我不确切知道你的数据会是什么样子,我认为这是另一个话题。

此外,mySQL 中有一个 POINT 数据类型,它可能更适合这种类型的工作,并且可以采用空间索引,这可能会使对数据的任何查询性能更高,如果有很多数据,它可能值得研究。我个人从未使用过它,所以我只是将 lat 和 lng 分别存储在 DECIMAL 中。

https://dev.mysql.com/doc/refman/5.7/en/gis-data-formats.html


推荐阅读