I am using Zend_Search_Lucene, to index my website. My site indexes are not entirely similar. Some have, few fields, and some have many fields. I am trying to create a similar index through different types of table, that's why i am encountering this kind of error.
Now, when I display the result. I call some fields, which are not present in all the result which generates the error. i tried to check it with isset
but it seems it totally skips the row.
foreach ($hits as $hit开发者_StackOverflow) {
$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(" » ",$title);
$content .= '</h2>';
$content .= '<p>'.$this->content.'</p>';
$content .= '</div>';
}
How to check if there is anything such as $hit -> name
is present in $hit
The problem you are experiencing is very very specific and has to do with the Zend_Lucene_Search
implementation, not the field/property exist check in general.
In your loop, $hit
is an object of class Zend_Search_Lucene_Search_QueryHit
. When you write the expression $hit->name
, the object calls the magic __get
function to give you a "virtual property" named name
. It is this magic function that throws the exception if the value to be supplied does not exist.
Normally, when a class implements __get
as a convenience it should also implement __isset
as a convenience (otherwise you cannot really use isset
on such virtual properties, as you have found out the hard way). Since this particular class does not implement __isset
as IMHO it should, you will never be able to get the name
"property" blindly without triggering an exception if the relevant data does not exist.
property_exists
and all other forms of reflection will also not help since we are not talking about a real property here.
The proper way to solve this is a little roundabout:
$title = array();
$names = $hit->getDocument()->getFieldNames();
if(in_array('name', $names)) $title[] = $hit -> name;
if(in_array('title',$names)) $title[] = $hit -> title;
All said, I 'd consider this a bug in ZF and probably file a report, asking for the __isset
magic method to be implemented appropriately on the types it should be.
You can try 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(" » ",$title);
$content .= '</h2>';
$content .= '<p>'.$this->content.'</p>';
$content .= '</div>';
}
You can also use reflection to query what fields the object has and build your content in a more programmatic way. this is good if you have a ton of fields.
$reflector = new ReflectionClass( get_class( $hit ) );
foreach( $reflector->getProperties() as $property ) {
if( in_array( $property->getName(), $SEARCH_FIELDS )
$title[] = $property->getValue( $hit );
}
more info here : http://php.net/manual/en/book.reflection.php
# Verify if exists
$hits = $index->find('id_field:100');
if (isset($hits[0])) { echo 'true'; } else { echo 'false'; }
isset will work if you simply convert your object to an array first.
<?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>';
?>
精彩评论