Catch a fatal exception and continue

xbonez picture xbonez · Jan 12, 2012 · Viewed 8.5k times · Source

I know, that by its very definition, a fatal exception is supposed to kill the execution, and should not be suppressed, but here's the issue.

I'm running a script that scrapes, parses and stores in a DB about 10,000 pages. This takes a couple of hours, and in rare cases (1 in 1000) a page fails parsing and throws a fatal exception.

Currently, I'm doing this:

for ($i=0;$i<$count;$i++)   
        {
            $classObject = $classObjects[$i];           

            echo $i . "   :   " . memory_get_usage(true) . "\n";

            $classDOM = $scraper->scrapeClassInfo($classObject,$termMap,$subjectMap);           
            $class = $parser->parseClassInfo($classDOM);                    
            $dbmanager->storeClassInfo($class);         

            unset($classDOM,$class,$classObject);           
        }        

Can I do something like

for ($i=0;$i<$count;$i++)   
{
   $classObject = $classObjects[$i];            
   echo $i . "   :   " . memory_get_usage(true) . "\n";

   try
   {
      $classDOM = $scraper->scrapeClassInfo($classObject,$termMap,$subjectMap);         
      $class = $parser->parseClassInfo($classDOM);                  
      $dbmanager->storeClassInfo($class);           
      unset($classDOM,$class,$classObject);         
    }
    catch (Exception $e)
    {
       //log the error here
       continue;
    }
}

The code above doesn't work for fatal exceptions.

Would it be possible to do something like this: If I moved the main loop into a method, and then call the method from register_shutdown_function ?

Like this:

function do($start)
{
   for($i=$start;$i<$count;$i++)
   {
      //do stuff here
   }
}

register_shutdown_function('shutdown');

function shutdown()
{ 
   do();
}

This is the message that is output when execution stops:

Fatal error:  Call to a member function find() on a non-object in ...

I expect this above message when a page isn't parse-able by the method I am using. I'm fine with just skipping that page and moving on to the next iteration of the loop.

Answer

mfonda picture mfonda · Jan 12, 2012

Fatal errors are fatal and terminate execution. There is no way around this if a fatal error occurs. However, your error:

Fatal error: Call to a member function find() on a non-object in ...

is entirely preventable. Just add a check to make sure you have an instance of the correct object, and if not, handle the error:

if ($foo instanceof SomeObject) {
    $foo->find(...);
} else {
    // something went wrong
}