我正在尝试将Simple HTML DOM Parser find()链接到遍历HTML,但是当其中一个孩子缺席时,它似乎崩溃了。例如:
$obj = $page->find('#headings', 0)->find('h4', 0)->nodes[0];
如果find('#headings',0)或find('h4',0)返回null(即如果元素不在HTML中),将导致PHP死亡(),但如果所有元素存在。
有没有办法让上面的链只返回null而不是崩溃PHP?我考虑过修改simplehtmldom但不确定如何。 find()函数如下所示:
// find dom node by css selector
// Paperg - allow us to specify that we want case insensitive testing of the value of the selector.
function find($selector, $idx=null, $lowercase=false)
{
return $this->root->find($selector, $idx, $lowercase);
}
编辑:(解决方案)
按照user1508519的建议,我创建了另一个nfind()函数。使用这种方法,如果null属性(与方法相反 - find()方法在链接时返回一个空节点),PHP仍然会标记通知,但在链条的下方引用但不会在没有解释时崩溃,因为它在使用find时会发生( )。
// modified version of simple_html_dom->find() that will return an empty node instead of null when chained if an element is not found. simple_html_dom_node->nfind() must also be created for this to work.
function nfind($selector, $idx=null, $lowercase=false)
{
$this->root->nfind($selector, $idx, $lowercase);
}
执行查找操作的实际代码可以在simple_html_dom_node-> find()中找到,并且以下函数应放在simple_html_dom_node中,以使整个包正常工作(最后一行只修改 - 由于某种原因包装原始find()函数和检查is_null似乎仍然崩溃PHP
//modifed version of simple_html_dom_node->find()
function nfind($selector, $idx=null, $lowercase=false)
{
$selectors = $this->parse_selector($selector);
if (($count=count($selectors))===0) return array();
$found_keys = array();
// find each selector
for ($c=0; $c<$count; ++$c)
{
// The change on the below line was documented on the sourceforge code tracker id 2788009
// used to be: if (($levle=count($selectors[0]))===0) return array();
if (($levle=count($selectors[$c]))===0) return array();
if (!isset($this->_[HDOM_INFO_BEGIN])) return array();
$head = array($this->_[HDOM_INFO_BEGIN]=>1);
// handle descendant selectors, no recursive!
for ($l=0; $l<$levle; ++$l)
{
$ret = array();
foreach ($head as $k=>$v)
{
$n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k];
//PaperG - Pass this optional parameter on to the seek function.
$n->seek($selectors[$c][$l], $ret, $lowercase);
}
$head = $ret;
}
foreach ($head as $k=>$v)
{
if (!isset($found_keys[$k]))
$found_keys[$k] = 1;
}
}
// sort keys
ksort($found_keys);
$found = array();
foreach ($found_keys as $k=>$v)
$found[] = $this->dom->nodes[$k];
// return nth-element or array
if (is_null($idx)) return $found;
else if ($idx<0) $idx = count($found) + $idx;
return (isset($found[$idx])) ? $found[$idx] : new simple_html_dom_node('');
}
再次感谢user1508519帮助我找到所需的解决方案,同时提供一系列同样有效的替代方案!欢迎评论解决方案/潜在副作用的有效性,或者如果有更优雅的方式来实现这一点,任何人都应该有进一步的意见。
答案 0 :(得分:1)
你为什么要在连锁店里做?为什么不检查后续检查每个调用是否为空?就像评论所说,你不能操作null对象。如果你正在进行foreach循环,那么就不需要进行空检查。
$obj = $page->find('#headings', 0);
if (!is_null($obj)) {
$obj = $page->find('h4', 0);
if (!is_null($obj))
// ...continue...
}
修改强>
function find($selector, $idx=null, $lowercase=false)
{
if (is_null($this->root->find($selector, $idx, $lowercase)))
{
die("error");
// throw exception?
} else // whatever
}
OR
编写自己的包装函数,在内部调用simple的find。
像
function wrapper($selector, $idx=null, $lowercase=false) {
// yep
}
答案 1 :(得分:0)
您可以执行以下操作:
$obj = ($h4 = $page->find('#headings h4', 0)) ? $h4->nodes[0] : null;