errors = $errors; } /** * Create an instance with the provided information * * @param string $message * @param LibXMLError[] $errors * @return LibXmlException * @throws InvalidArgumentException when an error item is not a LibXmlError */ public static function create(string $message, array $errors): self { /** @var mixed $error psalm found this validation contradictory since $errors is defined as LibXMLError[] */ foreach ($errors as $index => $error) { if (! $error instanceof LibXMLError) { throw new InvalidArgumentException("Error index $index is not a LibXmlError"); } } return new self($message, $errors); } /** * List of libxml errors * * @return LibXMLError[] */ public function getErrors(): array { return $this->errors; } /** * Create a LibXmlException based on errors in libxml. * If found, clear the errors and chain all the error messages. * * @return LibXmlException|null */ public static function createFromLibXml(): ?self { $errors = libxml_get_errors(); if (! count($errors)) { return null; } libxml_clear_errors(); $error = end($errors); return self::create($error->message, $errors); } /** * Execute a callable ensuring that the execution will occur inside an environment * where libxml use internal errors is true. * * After executing the callable the value of libxml use internal errors is set to * previous value. * * @param callable $callable * @return mixed * * @throws LibXmlException if some error inside libxml was found */ public static function useInternalErrors(callable $callable) { // capture current error reporting level and set to no-errors $previousErrorReporting = error_reporting(self::ERROR_LEVEL_SUPPRESS_ALL); // capture current libxml use internal errors and set to true $previousLibXmlUseInternalErrors = libxml_use_internal_errors(true); if ($previousLibXmlUseInternalErrors) { libxml_clear_errors(); } // run callable and throw libxml error as exception and always restore previous status try { /** @psalm-var mixed $return */ $return = $callable(); $exception = static::createFromLibXml(); if (null !== $exception) { throw $exception; } return $return; } finally { // restore error reporting level and libxml use internal errors error_reporting($previousErrorReporting); libxml_use_internal_errors($previousLibXmlUseInternalErrors); } } }