#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>';
?>