Проверить, существует ли поле / свойство в переменной типа object

#php #object #zend-search-lucene

#php #объект #zend-поиск-lucene

Вопрос:

Я использую Zend_Search_Lucene для индексации моего веб-сайта. Индексы моего сайта не совсем похожи. У некоторых есть несколько полей, а у некоторых — много полей. Я пытаюсь создать аналогичный индекс с помощью разных типов таблиц, вот почему я сталкиваюсь с такого рода ошибкой.

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

 foreach ($hits as $hit) {
    $content .= '<div class="searchResult">';
      $content .= '<h2>';           
        $title = array();
        if(isset($hit -> name)) $title[] = $hit -> name;
        if(isset($hit -> title)) $title[] = $hit -> title;
            // This is the part where i get fatal error.
        $content .= implode(" amp;raquo; ",$title);
      $content .= '</h2>';
      $content .= '<p>'.$this->content.'</p>';
    $content .= '</div>';
}
  

Как проверить, присутствует ли что-либо подобное $hit -> name в $hit

Комментарии:

1. Пропускает ли это строку или вы получаете ошибку PHP? Вы кажетесь нерешительным.

2. Конечно, ошибка Fatal error: Uncaught exception 'Zend_Search_Lucene_Exception' with message 'Field name "name" not found in document

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

Ответ №1:

Проблема, с которой вы столкнулись, очень специфична и связана с Zend_Lucene_Search реализацией, а не с проверкой существования поля / свойства в целом.

В вашем цикле $hit это объект класса Zend_Search_Lucene_Search_QueryHit . Когда вы пишете выражение $hit->name , объект вызывает волшебную __get функцию, чтобы предоставить вам «виртуальное свойство» с именем name . Именно эта волшебная функция выдает исключение, если значение, которое должно быть предоставлено, не существует.

Обычно, когда класс реализует __get для удобства, он также должен реализовывать __isset для удобства (в противном случае вы не сможете реально использовать isset такие виртуальные свойства, как вы выяснили на собственном горьком опыте). Поскольку этот конкретный класс реализуется не __isset так, как ИМХО следовало бы, вы никогда не сможете получить name «свойство» вслепую, не вызывая исключения, если соответствующие данные не существуют.

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

Правильный способ решить эту проблему — небольшой обходной путь:

 $title = array();
$names = $hit->getDocument()->getFieldNames();
if(in_array('name', $names)) $title[] = $hit -> name;
if(in_array('title',$names)) $title[] = $hit -> title;
  

В целом, я бы счел это ошибкой в ZF и, вероятно, отправил отчет с просьбой, чтобы __isset волшебный метод был реализован соответствующим образом для типов, которыми он должен быть.

Комментарии:

1. getFieldNames не возвращать ассоциативный массив. Я исправил ваш ответ.

2. Спасибо, Джон. @Starx, я не знал, что ты тоже знаком с Zend Framework.

3. @mrN, я тоже новичок в этом. Но, попробуйте меня, прежде чем публиковать в SO. 😛

Ответ №2:

Вы можете попробовать property_exists.

 foreach ($hits as $hit) {
    $content .= '<div class="searchResult">';
      $content .= '<h2>';           
        $title = array();
        if(property_exists($hit, 'name')) $title[] = $hit -> name;
        if(property_exists($hit, 'title')) $title[] = $hit -> title;
            // This is the part where i get fatal error.
        $content .= implode(" amp;raquo; ",$title);
      $content .= '</h2>';
      $content .= '<p>'.$this->content.'</p>';
    $content .= '</div>';
}
  

Комментарии:

1. $hit, это не класс, это просто переменная типа Object

2. Я не знаком с Zend, но он должен работать с любым объектом из stdClass PHP. Я тестировал с: $hit = new stdClass(); $hit->name = 'foo'; echo property_exists($hit, 'name') ? 't' : 'f'; > t

3. Это не будет работать корректно, если свойство не существует изначально, но вместо этого оно реализовано с помощью __get .

4. @Джон, я вижу. Спасибо за понимание этого класса Zend.

Ответ №3:

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

 $reflector = new ReflectionClass( get_class( $hit ) );
foreach( $reflector->getProperties() as $property  ) {
    if( in_array( $property->getName(), $SEARCH_FIELDS )
        $title[] = $property->getValue( $hit );
}
  

дополнительная информация здесь: http://php.net/manual/en/book.reflection.php

Ответ №4:

 # Verify if exists
$hits = $index->find('id_field:100');
if (isset($hits[0])) { echo 'true'; } else { echo 'false'; }
  

Ответ №5:

isset будет работать, если вы сначала просто преобразуете свой объект в массив.

 <?php
class Obj {
    public function GetArr() {
        return (array)$this;
    }
    static public function GetObj() {
        $obj = new Obj();
        $obj->{'a'} = 1;
        return $obj;
    }
}

$o = Obj::GetObj();
$a = $o->GetArr();
echo 'is_array: ' . (is_array($a) ? 1 : 0) . '<br />';
if (is_array($a)) {
    echo '<pre>' . print_r($a, TRUE) . '</pre><br />';
}
echo '<pre>' . serialize($o) . '</pre>';
?>