I recently ran into a frustrating error while working on a small PHP project where I wanted to scrape parcel tracking information from TNT’s tracking website using Simple HTML DOM. Instead of getting the latest status, I was greeted with this nasty fatal error:
Fatal error: Call to a member function find() on a non-object
At first, I was scratching my head. But once I dug in, I realized the issue wasn’t actually in Simple HTML DOM itself — it was in the way I was calling it.
The Error Explain
Here’s the snippet I first wrote:
<?php
include("simple_html_dom.php");
$html = file_get_html('http://www.tnt.com/webtracker/tracking.do?&cons=323626321');
$e = $html->find('table.appTable', 1)->find('tr[valign=top]', 0)->find('td', 3);
echo $e;
?>
The error occurs because one of the find()
calls is returning null
. When $html
or any intermediate result is null
, PHP throws a fatal error if I try to call ->find()
on it.
This usually happens when:
- The URL is not reachable (blocked, timeout, or
allow_url_fopen
disabled). - The HTML structure is different than I expect (for example, no
table.appTable
).
How I Fixed It
The solution was simple but powerful: always check if the object exists before calling find()
.
Here’s the updated version:
<?php
include("simple_html_dom.php");
$html = file_get_html('http://www.tnt.com/webtracker/tracking.do?&cons=323626321');
if (!$html) {
die("Error: Could not fetch HTML. Check your URL or network settings.");
}
$table = $html->find('table.appTable', 1);
if ($table) {
$row = $table->find('tr[valign=top]', 0);
if ($row) {
$cell = $row->find('td', 3);
if ($cell) {
echo $cell->plaintext;
} else {
echo "Error: Could not find the required <td> element.";
}
} else {
echo "Error: Could not find the required row.";
}
} else {
echo "Error: Could not find table.appTable.";
}
?>
Now, instead of crashing, the script gracefully tells me what went wrong.
Extra Practice Functionality
After fixing the fatal error, I decided to extend the project to practice more with Simple HTML DOM. Here are some enhancements I added:
Extract All Tracking Updates
Instead of just grabbing a single cell, I looped through the whole table:
<?php
foreach ($html->find('table.appTable tr[valign=top]') as $row) {
$cells = $row->find('td');
if (count($cells) > 3) {
echo "Status: " . $cells[3]->plaintext . "<br>";
}
}
?>
Save Results to a Log File
This way, I could keep a history of my parcel statuses.
<?php
$logfile = "tracking_log.txt";
file_put_contents($logfile, "Latest update: " . $cell->plaintext . "\n", FILE_APPEND);
echo "Status logged to $logfile";
?>
Parse Another Website
For fun, I tested the library with Google to pull all image sources:
<?php
$html = file_get_html('https://www.google.com/');
foreach ($html->find('img') as $element) {
echo "Image: " . $element->src . "<br>";
}
?
Pro Tips I Learn
- If
file_get_contents
is disabled on your server, switch to cURL:
<?php
function curl_get_html($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
return str_get_html($data);
}
$html = curl_get_html('http://www.tnt.com/webtracker/tracking.do?&cons=323626321');
?>
- Always check for null before chaining
find()
. - Use
->plaintext
if you only need clean text without HTML tags.
Final Thought
When I first hit the find() on a non-object
error, I thought Simple HTML DOM was broken. In reality, the issue was my assumption that the structure would always be there. By adding defensive checks and experimenting with new features like logging and looping through all updates, I not only fixed the error but also turned it into a learning project.