Google погоды API оболочки


Я программист-любитель (самоучка). В любом случае, этот класс обеспечивает несколько методов получить доступ к неофициальным компании Google погоды API. У меня возникли проблемы о том, как идти об обработке ошибок парсинга в parse_xml() так что любые предложения также будет полезно.

<?php
  class weather {
  private $_location;
  private $_url = 'http://www.google.com/ig/api?weather=';
  private $_isParsed = false;
  private $_wData;

  public $lastError;

  public function __construct( $location) {
      // Set location
      $this->_location = $location;

      // urlencode doesn't seem to work so manually add the + for whitespace
      $this->_url = preg_replace('/\s{1}/', '+',$this->_url .= $location);
      $this->parse_xml($this->get_xml());
  }

  public function get_temp($type = "f") {
      if (!$this->_isParsed)
          return false;

      // User specificed celsius, return celsius
      if ($type == "c")
          return $this->_wData['current']['temp_c'];

      // return fahrenheit
      return $this->_wData['current']['temp_f'];
  }

  public function get_condition() {
      if (!$this->_isParsed)
              return false;
      // provide current conditions only
      return $this->_wData['current']['condition'];
  }

  public function get_forecast_for_day($day) {
      if (!$this->_isParsed)
          return false;
      return $this->_wData['forecast'][$day];
  }
  public function get_forecast_assoc() {
      if (!$this->_isParsed)
          return false;
      return $this->_wData['forecast'];
  }

  public function get_cond_assoc() {
      if (!$this->_isParsed)
          return false;
      return $this->_wData['current'];
  }

  public function dump_wData() {
      if (!$this->_isParsed)
          return false;
      return $this->_wData;
  }

  public static function to_celsius($f) {
      // Convert Fahrenheit to Celsius.
      // I figured this would be quicker than trying to parse the XML.
      return floor(((int)$f - 32) * (5 / 9));
  }

  private function get_xml() {
      // Download raw XML to be parsed.
      $ch = curl_init($this->_url);

      // I don't know why I altered the useragent. It must have been for a good reason. Oh well.
      curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; rv:5.0.1) Gecko/20100101 Firefox/5.0.1');
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $rawXML = curl_exec($ch);

      if (!$rawXML)
          return false;
      curl_close($ch);
      return $rawXML;
  }

  private function parse_xml($xData) {
      libxml_use_internal_errors(true);
      try {
        $weather = new SimpleXMLElement($xData);
      } catch (Exception $err) {
          // Set $lastError to getMessage()
          $this->lastError = $err->getMessage();
         return false;
      }
      // Select the current_conditions node ($cNode)
      $cNode = $weather->weather[0]->current_conditions;

      // ========= Set up our current conditions array ====================

      // Tempreature - temp_f Fahrenheit, temp_c celsius - set as floats.
      $this->_wData['current']['temp_f'] = (float)$cNode->temp_f->attributes()->data;
      $this->_wData['current']['temp_c'] = weather::to_celsius($this->_wData['current']['temp_f']);

      // Condition
      $this->_wData['current']['condition'] = (string)$cNode->condition->attributes()->data;

      // Condition Icon - icon url is not absolute, append google.com
      $this->_wData['current']['icon'] = (string)"http://www.google.com" . $cNode->icon->attributes()->data;

      // Wind Condition
      $this->_wData['current']['wind'] = (string)$cNode->wind_condition->attributes()->data;

      // ============= Set up our forecast array =============
      $fNode = $weather->weather[0]->forecast_conditions;

      // Iterate through each day of the week and create an assoc array.
      foreach ($fNode as $forecast) {
          // Get the day.
          $day = (string)$forecast->day_of_week->attributes()->data;

          // Insert an array of info for that day
          $this->_wData['forecast'][$day] = array (
              "high" => (float)$forecast->high->attributes()->data,
              "low" => (float)$forecast->low->attributes()->data,
              "icon" => (string)"http://www.google.com" . $forecast->icon->attributes()->data,
              "condition" => (string)$forecast->condition->attributes()->data
            );
      } //foreach ($fNode as $forecast)
      // Let the class know wData is ready for use.
      $this->_isParsed = true;
  } //private function parse_xml($xData)

}
?>


3471
7
задан 13 августа 2011 в 01:08 Источник Поделиться
Комментарии
3 ответа

Использовать методы для получения данных, это своего рода зависимость впрыска и позволит вам проверить код с ВНЕ того, чтобы поразить Google на сервер каждый раз. Это позволит также избежать , Если($этом->_isParsed) на всех своих функций.

Кроме того, перейти на 'разбор' - это просто перемещение по структуре XML - функций, которые возвращают данные. Это удаляет ваш parse_xml функции (которые сейчас бы просто функцию, которая создает при помощи SimpleXML объект), и позволяет генерировать исключения только тогда, когда запрошенные данные отсутствуют/непредвиденные (или просто возвращать false, если вы хотите, чтобы вашему клиенту).

Вот некоторые примеры кода.

Я предпочитаю использовать верблюжьего, я не пытаюсь изменить свой стиль, это просто вторая натура.

<?php
class GoogleWeather{
protected $api = 'http://www.google.com/ig/api?weather=';
protected $xml;
protected $response;
protected $location;

public function __construct( $location) {
// Set location
$this->location = $location;
}

public function setResponse($response)
{
$this->response = $response;
}

public function getResponse()
{
//if the xml hasn't been fetched, then fetch it
if(empty($this->response)){
$this->setResponse($this->fetchData());
}
return $this->response;
}

//was get_xml renamed to avoid confusion
public function fetchData()
{
// Download raw XML to be parsed.
$ch = curl_init($this->api . urlencode($this->location));

// I don't know why I altered the useragent. It must have been for a good reason. Oh well.
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; rv:5.0.1) Gecko/20100101 Firefox/5.0.1');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$rawXML = curl_exec($ch);

if (!$rawXML){
//check the curl error for a better message
throw new Exception('could not fetch data');
}
curl_close($ch);
return $rawXML;
}

public function getXml()
{
if(empty($this->xml)){
try{
$this->xml = new SimpleXMLElement($this->getResponse());
} catch (Exception $e) {
//there's no real recovery here, except maybe to retry fetching the data
throw new Exception('bad response from from API');
}

//check for 'problem_cause' element
if(isset($this->xml->weather->problem_cause)){
throw new Exception('API responded with error');
}
}
return $this->xml;
}

public function getCondition()
{
//make sure there's data
if(!isset($this->getXml()->weather->current_conditions)){
//you could throw an exception and assume any code using this is
//calling it in a try block
throw new Exception('could not find conditions');
}

return $this->getXml()->weather->current_conditions;
}

public function getTemp($type = 'f')
{
//validate type
if(!in_array($type, array('f','c'))){
throw Exception('invalid temp type: ' . $type);
}

$element = 'temp_' . $type;
//make sure there's data
if(!isset($this->getCondition()->{$element}['data'])){
throw new Exception('could not find temp');
}

//cast as float and return
return (float) $this->getCondition()->{$element}['data'];
}
}

Вы можете избежать навигация по помощи SimpleXML объект несколько раз для одних и тех же данных, используя ту же базовую концепцию другой отложенной загрузки функции использовать (getXML(), метод GetResponse()).

Вместо того, чтобы использовать свойства объекта, я просто ставлю статическую переменную в методе - т. к. не могу изменить, Нет не нужно сбросить все данные.

Однако, если местоположение может измениться, то же самое может быть сделано с $этом->данные[$собственность] - очевидно, сброс $этом->данные в массив() каждый раз, когда положение изменилось.

Вот улучшенная getTemp():

  public function getTemp($type = 'f')
{
static $temp = array();

//validate type
if(!in_array($type, array('f','c'))){
throw Exception('invalid temp type: ' . $type);
}

if(isset($temp[$type])){
return $temp[$type];
}

$element = 'temp_' . $type;
//make sure there's data
if(!isset($this->getCondition()->{$element}['data'])){
throw new Exception('could not find temp');
}

//cast as float and return
$temp[$type] = $this->getCondition()->{$element}['data'];
return $temp[$type];
}

Мне было бы интересно увидеть, если есть какие-либо значительные показатели, полученные за переход в помощи SimpleXML объект каждый раз.

3
ответ дан 17 августа 2011 в 02:08 Источник Поделиться

Я разработчика на C# сам, но я вообще такой, очень чистый и легкий для чтения и понимания, хотя это не язык, где я работал.

Макет класса сканируется с членами и методов красиво заказать и понятна их цель.

Только предложения у меня такие:
разделить его на 2 занятия, то, что получает, и тот, кто парсинга. Принять GoogleWeatherResponseParser член вашей GoogleWeatherDataAccess и вы можете либо построить синтаксический анализатор на работ, или более проверяемым подхода является то, что он передал в конструктор.

Если это передал конструктору, потребителю доступ к данным будет построить синтаксический анализатор и быть в состоянии проверить, если он был выполнен успешно или нет перед сдачей его доступа к данным. Тогда доступ к данным будет иметь только для проверки при строительстве, исключение, никогда не проверяя в отдельные методы, делая их чище.

Также, вы могли потом писать юнит-тесты, что силы в различных модификациях GoogleWeatherResponseParser на GoogleWeatherDataAccess при строительстве и убедитесь, что данные открыть руки, является, как вы ожидали. Не знаете, как общий блок тестов на PHP, но они очень полезны, так как позволяет изменять код, зная, что вы будете уведомлены, если вас что-то сломалось.

Редактировать: Ох, и ты абсолютно права насчет делать расчет по Цельсию в отличие от синтаксического анализа XML шаг.

2
ответ дан 13 августа 2011 в 05:08 Источник Поделиться

Если я мог бы сделать несколько предложений, как для удобства чтения и для избежания проблем в будущем.


  1. Отступ от названия класса.

Вместо

<?php
class weather {
private $_location;
private $_url = 'http://www.google.com/ig/api?weather=';
private $_isParsed = false;
private $_wData;

писать

<?php
class weather {
private $_location;
private $_url = 'http://www.google.com/ig/api?weather=';
private $_isParsed = false;
private $_wData;

2 Всегда используйте скобки в if заявление

вместо

public function get_cond_assoc() {
if (!$this->_isParsed)
return false;
return $this->_wData['current'];
}

использовать

public function get_cond_assoc() {
if (!$this->_isParsed)
{
return false;
}
return $this->_wData['current'];
}

Это может показаться ненужным, так как ваше строительство абсолютно законно, но в первый раз вы потратите 2 часов охоты вниз ошибка, вызванная не указав брекетов, вы будете благодарить меня :)

3 не относиться излишне

В (строку) здесь является излишним и вводящим в заблуждение.

 // Condition Icon - icon url is not absolute, append google.com
$this->_wData['current']['icon'] = (string)"http://www.google.com" .
$cNode->icon->attributes()->data;

Это лишь несколько советов, чтобы сделать ваш код немного более читаемым и менее вероятно, чтобы вызвать головную боль в будущем.

1
ответ дан 28 августа 2011 в 08:08 Источник Поделиться