Libxml error handler with OOP

I need catch libxml errors. But I want to use my class for this. I know about libxml_get_errors and other functions. But I need something like libxml_set_erroc_class("myclass") , and in all cases the error will call my class. I do not want in each case after using $dom->load(...) create some construct, for example foreach(libxml_get_errors as $error) {....} . Can you help me?

+2
source share
3 answers

libxml errors are mainly generated when reading or writing an xml document, as it automatically checks.

So, here is where you should focus, and you don't need to overwrite set_error_handler . Here is the proof of concept

Use internal errors

 libxml_use_internal_errors ( true ); 

XML example

 $xmlstr = <<< XML <?xml version='1.0' standalone='yes'?> <movies> <movie> <titles>PHP: Behind the Parser</title> </movie> </movies> XML; echo "<pre>" ; 

I think this is an example of what you want to achieve.

 try { $loader = new XmlLoader ( $xmlstr ); } catch ( XmlException $e ) { echo $e->getMessage(); } 

XMLLoader Class

 class XmlLoader { private $xml; private $doc; function __construct($xmlstr) { $doc = simplexml_load_string ( $xmlstr ); if (! $doc) { throw new XmlException ( libxml_get_errors () ); } } } 

Class xmlexception

 class XmlException extends Exception { private $errorMessage = ""; function __construct(Array $errors) { $x = 0; foreach ( $errors as $error ) { if ($error instanceof LibXMLError) { $this->parseError ( $error ); $x ++; } } if ($x > 0) { parent::__construct ( $this->errorMessage ); } else { parent::__construct ( "Unknown Error XmlException" ); } } function parseError(LibXMLError $error) { switch ($error->level) { case LIBXML_ERR_WARNING : $this->errorMessage .= "Warning $error->code: "; break; case LIBXML_ERR_ERROR : $this->errorMessage .= "Error $error->code: "; break; case LIBXML_ERR_FATAL : $this->errorMessage .= "Fatal Error $error->code: "; break; } $this->errorMessage .= trim ( $error->message ) . "\n Line: $error->line" . "\n Column: $error->column"; if ($error->file) { $this->errorMessage .= "\n File: $error->file"; } } } 

Output example

 Fatal Error 76: Opening and ending tag mismatch: titles line 4 and title Line: 4 Column: 46 

I hope this helps

thanks

+7
source

edit (confusing exceptions with errors):

  • Use set_exception_handler to catch global exceptions.
  • Enter the code for these exceptions in cases such as $dom->load() . Since libxml does not seem to throw exceptions on its own, another option is to create a wrapper around it, use the wrapper in your code and check for libxml errors and throw them if necessary.
  • Handle exceptions inside "myclass".

Be careful though set_exception_handler will catch all your exceptions.

Here is an example of what you could do:

 //inheritance example (composition, though, would be better) class MyDOMWrapper extends DOMDocument{ public function load($filename, $options = 0){ $bool = parent::load($filename, $options); if (!$bool){ throw new MyDOMException('Shit happens. Feeling lucky.', 777); } } } class MyDOMException extends DOMException{ public $libxml; public function __construct($message, $code){ parent::__construct($message, $code); $this->libxml = libxml_get_errors(); } } class MyDOMExceptionHandler{ public static function handle($e){ //handle exception globally } } libxml_use_internal_errors(true); set_exception_handler(array('MyDOMErrorHandler', 'handle')); //global exception handler $myDom = new MyDOMWrapper(); $myDom->load('main.xml'); //when special handling is necessary try { $myDom = new MyDOMWrapper(); $myDom->load('main.xml'); } catch (MyDOMException $e) { //handle or throw $e; //rethrow } 
+1
source

We have no way to do this directly. Your options:

  • extend the PHP class that libxml uses and wrap your error handling logic around a stock implementation (not so good) or
  • write your own class that combines an instance of this PHP class and creates its own open interface around it (it is better because you control the open interface and do not risk problems if the PHP class is extended in the future), or
  • replacing the global error handler for the duration of your parsing and restoring it later (not so much, it can be problematic if your code calls another code, how would it be easier to do this)

Solutions 1 and 2 have the advantage that they do not change the behavior of any other code in the application no matter what.

+1
source

Source: https://habr.com/ru/post/1204709/


All Articles