{"id":351,"date":"2010-11-25T03:40:50","date_gmt":"2010-11-25T02:40:50","guid":{"rendered":"https:\/\/d-mueller.de\/blog\/?p=351"},"modified":"2012-10-10T21:00:19","modified_gmt":"2012-10-10T19:00:19","slug":"php-errors-zu-exceptions-konvertieren","status":"publish","type":"post","link":"https:\/\/d-mueller.de\/blog\/php-errors-zu-exceptions-konvertieren\/","title":{"rendered":"PHP-Errors zu Exceptions konvertieren"},"content":{"rendered":"<p>Wie wir ja alle wissen, ist der <i>@<\/i>-Fehlerunterdr\u00fcckungs-Operator gemeinhin b\u00f6se. Was aber nun, wenn wir mit PHP-eigenen Funktionen arbeiten m\u00fcssen, die im Fehlerfall eine Warning produzieren?<br \/>\nWas ich meine ist z.B. <b>file_get_contents<\/b>. Wenn die aufzurufende URL nicht erreichbar ist, hei\u00dft es<\/p>\n<pre data-enlighter-language=\"enlighter\" class=\"EnlighterJSRAW\">\r\nWarning: file_get_contents() [function.file-get-contents]: php_network_getaddresses: getaddrinfo failed: Der angegebene Host ist unbekannt\r\n<\/pre>\n<p>Unsch\u00f6n. Gl\u00fccklicherweise kann man mittels eines eigenen Errorhandlers einen Workaround basteln, indem der Fehler zu einer Exception konvertiert wird:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nfunction errorhandler($code, $error, $file, $line)\r\n{\r\n\tthrow new ErrorException($error, $code, 0, $file, $line);\r\n}\r\n\r\nset_error_handler(&quot;errorhandler&quot;);\r\n\r\ntry\r\n{\r\n\techo file_get_contents(&quot;http:\/\/www.this-is-not-a-real-url.org&quot;);\r\n}\r\ncatch (ErrorException $ex)\r\n{\r\n\techo &quot;Die Webseite ist gerade nicht erreichbar&quot;;\r\n}\r\n<\/pre>\n<p>Im Produktivbetrieb sollten die Fehler bekanntlich ohnehin nur geloggt und nicht angezeigt werden, trotz allem f\u00fchle ich mich wohler mit solch einer L\u00f6sung. Leider greift diese &#8222;Konvertierung&#8220; nicht bei <i>fatal errors<\/i> und <i>parser errors<\/i> &#8211; Aber die sind ja ohnehin auszumerzen.<\/p>\n<h2>Edit 10.10.2012<\/h2>\n<p>Basierend auf PHP 5.3 (Closures) und <a href=\"http:\/\/jeremycook.ca\/2012\/10\/02\/turbocharging-your-logs\/\">diesem Blogpost<\/a> hier ein recht vollst\u00e4ndiges Error-Handling-Konzept, welches testweise die Funktion <a href=\"http:\/\/php.net\/manual\/de\/function.error-log.php\">error_log<\/a> verwendet:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\n&lt;?php\r\nclass Logger\r\n{\r\n\tpublic static function addError($message, $content = array())\r\n\t{\r\n\t\terror_log(&quot;Error: &quot; . $message . &quot; - &quot; . print_r($content, true), 3, &quot;D:\/xampp\/htdocs\/error.log&quot;);\r\n\t}\r\n\t\r\n\tpublic static function addAlert($message, $content = array())\r\n\t{\r\n\t\terror_log(&quot;Warning: &quot; . $message . &quot; - &quot; . print_r($content, true), 3, &quot;D:\/xampp\/htdocs\/error.log&quot;);\r\n\t}\r\n}\r\n\r\n\/**\r\n * Create a closure to handle uncaught exceptions\r\n *\/\r\nset_exception_handler($handler = function(Exception $e) use (&amp;$handler) {\r\n    $message = sprintf(\r\n        &#039;Uncaught exception of type %s thrown in file %s at line %s%s.&#039;,\r\n        get_class($e),\r\n        $e-&gt;getFile(),\r\n        $e-&gt;getLine(),\r\n        $e-&gt;getMessage() ? sprintf(&#039; with message &quot;%s&quot;&#039;, $e-&gt;getMessage()) : &#039;&#039;\r\n    );\r\n    Logger::addError($message, array(\r\n        &#039;Exception file&#039;  =&gt; $e-&gt;getFile(),\r\n        &#039;Exception line&#039;  =&gt; $e-&gt;getLine(),\r\n        &#039;Exception trace&#039; =&gt; $e-&gt;getTraceAsString()\r\n    ));\r\n    \/**\r\n     * If there was a previous nested exception call this function recursively\r\n     * to log that too.\r\n     *\/\r\n    if ($prev = $e-&gt;getPrevious()) {\r\n        $handler($prev);\r\n    }\r\n});\r\n\r\n\/**\r\n * Set a custom error handler to make sure that errors are logged to Graylog.\r\n * Allows any non-fatal errors to be logged to the Graylog2 server.\r\n *\/\r\nset_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext){\r\n\t$message = &#039;Error of level &#039;;\r\n\tswitch ($errno) {\r\n\t\tcase E_USER_ERROR:\r\n\t\t\t$message .= &#039;E_USER_ERROR&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_USER_WARNING:\r\n\t\t\t$message .= &#039;E_USER_WARNING&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_USER_NOTICE:\r\n\t\t\t$message .= &#039;E_USER_NOTICE&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_STRICT:\r\n\t\t\t$message .= &#039;E_STRICT&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_RECOVERABLE_ERROR:\r\n\t\t\t$message .= &#039;E_RECOVERABLE_ERROR&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_DEPRECATED:\r\n\t\t\t$message .= &#039;E_DEPRECATED&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_USER_DEPRECATED:\r\n\t\t\t$message .= &#039;E_USER_DEPRECATED&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_NOTICE:\r\n\t\t\t$message .= &#039;E_NOTICE&#039;;\r\n\t\t\tbreak;\r\n\t\tcase E_WARNING:\r\n\t\t\t$message .= &#039;E_WARNING&#039;;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\t$message .= sprintf(&#039;Unknown error level, code of %d passed&#039;, $errno);\r\n\t}\r\n\t$message .= sprintf(\r\n\t\t&#039;. Error message was &quot;%s&quot; in file %s at line %d.&#039;,\r\n\t\t$errstr,\r\n\t\t$errfile,\r\n\t\t$errline\r\n\t);\r\n\tLogger::addError($message, $errcontext);\r\n\r\n\treturn false;\/\/Returning false will mean that PHP&#039;s error handling mechanism will not be bypassed.\r\n});\r\n\r\n\/**\r\n * This function will be called before the script exits.\r\n * This allows us to catch and log any fatal errors in the Graylog2 server.\r\n * This is needed as the set_error_handler function cannot be used to handle\r\n * any of the errors in the array below.\r\n *\/\r\nregister_shutdown_function(function(){\r\n    $codes = array(\r\n        1   =&gt; &#039;E_ERROR&#039;,\r\n        4   =&gt; &#039;E_PARSE&#039;,\r\n        16  =&gt; &#039;E_CORE_ERROR&#039;,\r\n        32  =&gt; &#039;E_CORE_WARNING&#039;,\r\n        64  =&gt; &#039;E_COMPILE_ERROR&#039;,\r\n        128 =&gt; &#039;E_COMPILE_WARNING&#039;\r\n    );\r\n    $error = error_get_last();\r\n    if (is_array($error) &amp;&amp; array_key_exists($error[&#039;type&#039;], $codes)) {\r\n        $message = sprintf(\r\n            &#039;Error of type %s raised in file %s at line %d with message &quot;%s&quot;&#039;,\r\n            $codes[$error[&#039;type&#039;]],\r\n            $error[&#039;file&#039;],\r\n            $error[&#039;line&#039;],\r\n            $error[&#039;message&#039;]\r\n        );\r\n\r\n        if (in_array($error[&#039;type&#039;], array(32, 128))) {\r\n            \/\/These errors are warnings and should be logged at a lower level.\r\n            Logger::addError($message);\r\n        } else {\r\n           Logger::addAlert($message);\r\n        }\r\n    }\r\n});\r\n\r\n\/\/throw new Exception(&quot;foobar&quot;);\r\n\/\/echo 1\/0;\r\nasd::Xxx();\r\n<\/pre>\n<p>Macht mir einen sehr vern\u00fcnftigen Eindruck, ein eigener Errorhandler, ein eigener Exception-Handler und eine Shutdown-Funktion. So entwischt kein Fehler mehr ;).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wie wir ja alle wissen, ist der @-Fehlerunterdr\u00fcckungs-Operator gemeinhin b\u00f6se. Was aber nun, wenn wir mit PHP-eigenen Funktionen arbeiten m\u00fcssen, die im Fehlerfall eine Warning produzieren? Was ich meine ist z.B. file_get_contents. Wenn die aufzurufende URL nicht erreichbar ist, hei\u00dft &hellip; <a href=\"https:\/\/d-mueller.de\/blog\/php-errors-zu-exceptions-konvertieren\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,8,3],"tags":[],"class_list":["post-351","post","type-post","status-publish","format-standard","hentry","category-php","category-quicktips","category-webdev"],"_links":{"self":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/351","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/comments?post=351"}],"version-history":[{"count":0,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/351\/revisions"}],"wp:attachment":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/media?parent=351"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/categories?post=351"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/tags?post=351"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}