Capturar terminação inesperada em PHP / CodeIgniter

Estou usando o CodeIgniter para hospedar uma API RESTful e eu gostaria de capturar qualquer resposta da API que não retorna um código de status esperado. Isso provavelmente é mais facilmente explicado com um exemplo. Em geral, meu código parece assim:

function post_comment() { $comment = $_POST['comment']; $result = do_something_with_comment($comment); if ($result === true) { return_json_response(200, 'OK!'); } else { return_json_response(400, 'Something terrible happened...'); } } 

Devolver um 200 ou 400 é perfeitamente válido. Meu problema é: como capturar erros quando do_something_with_comment () tem um erro fatal, ou se eu deixar uma debugging de impressão dentro de do_something_with_comment (). No primeiro caso, nunca chegarei a return_json_response (). No último caso, vou alcançá-lo, mas a debugging da canvas irá corromper a resposta do JSON.

Existe alguma maneira de criar um invólucro genérico em torno disso para capturar qualquer saída ou término inesperado?

Em geral você poderia:

Use o controle de exceção / exceção o máximo possível

Registre um manipulador de erros personalizado que transforme erros de PHP em exceções, por exemplo, coloque isso em cima do seu config / config.php

 function my_error_handler($errno, $errstr, $errfile, $errline) { if (!(error_reporting() & $errno)) { // This error code is not included in error_reporting return; } log_message('error', "$errstr @$errfile::$errline($errno)" ); throw new ErrorException( $errstr, $errno, 0, $errfile, $errline ); } set_error_handler("my_error_handler"); 

Registre um manipulador de exceção não detectado, coloque algo assim em seu config / config.php

 function my_exception_handler($exception) { echo '
'; print_r($exception); echo '

'; header( "HTTP/1.0 500 Internal Server Error" ); } set_exception_handler("my_exception_handler");

EDITAR

Definir um manipulador de término:

 function my_fatal_handler() { $errfile = "unknown file"; $errstr = "Fatal error"; $errno = E_CORE_ERROR; $errline = 0; $error = error_get_last(); if ( $error !== NULL ) { echo '
'; print_r($error); echo '

'; header( "HTTP/1.0 500 Internal Server Error" ); } } register_shutdown_function("my_fatal_handler");

Defina um manipulador Assert personalizado que converte as afirmações em exceções, coloque algo como isto em seu config / config.php:

 function my_assert_handler($file, $line, $code) { log_message('debug', "assertion failed @$file::$line($code)" ); throw new Exception( "assertion failed @$file::$line($code)" ); } assert_options(ASSERT_ACTIVE, 1); assert_options(ASSERT_WARNING, 0); assert_options(ASSERT_BAIL, 0); assert_options(ASSERT_QUIET_EVAL, 0); assert_options(ASSERT_CALLBACK, 'my_assert_handler'); 

Então, e esta é a sua resposta , use wrappers como este em seus controladores

 public function controller_method( ) { try { // normal flow } catch( Exception $e ) { log_message( 'error', $e->getMessage( ) . ' in ' . $e->getFile() . ':' . $e->getLine() ); // on error } } 

Você pode sintonizar e personalizar todo o seu gosto!

Espero que isto ajude.

EDITAR

Você também precisará interceptar o método CI show_error. Coloque isso em application / core / MY_exceptions.php:

 class MY_Exceptions extends CI_Exceptions { function show_error($heading, $message, $template = 'error_general', $status_code = 500) { log_message( 'debug', print_r( $message, TRUE ) ); throw new Exception(is_array($message) ? $message[1] : $message, $status_code ); } } 

E deixe em application / config / database.php esta configuração em FALSE para ter erros de database convertidos em exceções.

 $db['default']['db_debug'] = TRUE; 

A CI tem alguns (muito) pontos fracos, como o tratamento de exceções, mas isso irá corrigir de maneira longa isso.

Há uma function register_shutdown_function () dentro da qual você pode configurar seu próprio manipulador de fechamento para cada script. Apenas faça o que você precisa lá.

BTW: Faça seus scripts à prova de bala como você pode. Seus scripts não devem ter erros fatais, segaults ou erros de tempo de execução. Qualquer resposta, mesmo inválida para o cliente, é válida no contexto do tratamento de pedidos. Gostaria de encorajá-lo a dar uma olhada na estrutura do Symfony2 ou simplesmente nos seus componentes HttpKernel / HttpFoundation, pois eles muito bem envolver esse processo em uma interface amigável.