PHP para iniciantes. Tratamento de erros

imagem

Somente quem não faz nada não comete erros, e somos um exemplo disso - sentamos e trabalhamos incansavelmente, lemos o Habr :)

Neste artigo, contarei minha história sobre erros no PHP e como controlá-los.

Erros


Variedades na família de erros


Antes de domar erros, eu recomendaria estudar cada espécie e prestar atenção separadamente aos representantes mais importantes.

Para impedir que um único erro passe despercebido, é necessário ativar o rastreamento de todos os erros usando a função error_reporting () e a diretiva display_errors para ativar a exibição:

<?php error_reporting(E_ALL); ini_set('display_errors', 1); 

Erros fatais


O tipo de erro mais formidável é fatal, pode ocorrer durante a compilação e durante o trabalho do analisador ou do script PHP, enquanto o script é interrompido.

E_PARSE

Este erro aparece quando você comete um erro grave de sintaxe e o intérprete PHP não entende o que você deseja dele, por exemplo, se você não fechou o cacheado ou o parêntese:

 <?php /** * Parse error: syntax error, unexpected end of file */ { 

Ou eles escreveram em uma linguagem incompreensível:

 <?php /** * Parse error: syntax error, unexpected '...' (T_STRING) */     

Suportes extras também ocorrem, e não são tão importantes redondos ou encaracolados:

 <?php /** * Parse error: syntax error, unexpected '}' */ } 

Observo um ponto importante - o código do arquivo no qual você cometeu o erro de análise não será executado; portanto, se você tentar ativar a exibição de erros no mesmo arquivo em que ocorreu o erro do analisador, isso não funcionará:

 <?php //     error_reporting(E_ALL); ini_set('display_errors', 1); // ..     

E_ERROR

Este erro aparece quando o PHP entendeu o que você deseja, mas isso não funcionou por vários motivos. Este erro também interrompe a execução do script e o código funcionará antes que o erro apareça:

O plug-in não foi encontrado:

 /** * Fatal error: require_once(): Failed opening required 'not-exists.php' * (include_path='.:/usr/share/php:/usr/share/pear') */ require_once 'not-exists.php'; 

Uma exceção foi lançada (que tipo de animal, eu vou te contar um pouco mais tarde), mas não foi processada:

 /** * Fatal error: Uncaught exception 'Exception' */ throw new Exception(); 

Ao tentar chamar um método de classe inexistente:

 /** * Fatal error: Call to undefined method stdClass::notExists() */ $stdClass = new stdClass(); $stdClass->notExists(); 

Falta de memória livre (mais do que o prescrito na diretiva memory_limit ) ou algo semelhante:

 /** * Fatal Error: Allowed Memory Size */ $arr = array(); while (true) { $arr[] = str_pad(' ', 1024); } 

É muito comum ao ler ou baixar arquivos grandes, portanto, tenha cuidado com a questão do consumo de memória
Chamada de função recursiva. Neste exemplo, ele terminou na 256ª iteração, porque está escrito nas configurações do xdebug (sim, esse erro pode aparecer neste formulário somente quando a extensão xdebug está ativada):

 /** * Fatal error: Maximum function nesting level of '256' reached, aborting! */ function deep() { deep(); } deep(); 

Não fatal


Essa visualização não interrompe a execução do script, mas é o testador que normalmente os encontra. São esses erros que causam mais problemas para desenvolvedores iniciantes.

E_WARNING

Geralmente ocorre quando você conecta um arquivo usando o include , mas ele não aparece no servidor ou você cometeu um erro ao indicar o caminho para o arquivo:

 /** * Warning: include_once(): Failed opening 'not-exists.php' for inclusion */ include_once 'not-exists.php'; 

Isso acontece se você usar o tipo errado de argumentos ao chamar funções:

 /** * Warning: join(): Invalid arguments passed */ join('string', 'string'); 

Existem muitos deles, e listar tudo não faz sentido ...

E_NOTICE

Esses são os erros mais comuns. Além disso, existem ventiladores para desativar a saída de erros e rebitá-los o dia todo. Há vários erros triviais.

Ao acessar uma variável indefinida:

 /** * Notice: Undefined variable: a */ echo $a; 

Ao acessar um elemento de matriz inexistente:

 /** * Notice: Undefined index: a */ $b = []; $b['a']; 

Ao acessar uma constante inexistente:

 /** * Notice: Use of undefined constant UNKNOWN_CONSTANT - assumed 'UNKNOWN_CONSTANT' */ echo UNKNOWN_CONSTANT; 

Quando os tipos de dados não são convertidos:

 /** * Notice: Array to string conversion */ echo array(); 

Para evitar esses erros - tenha cuidado e, se o IDE informar algo, não o ignore:

PHP E_NOTICE no PHPStorm

E_STRICT

São erros que ensinam a escrever o código corretamente, para que você não tenha vergonha, principalmente porque o IDE mostra imediatamente esses erros. Por exemplo, se você chamou um método não estático como estático, o código funcionará, mas de alguma forma está errado, e poderão ocorrer erros graves se o método de classe for alterado no futuro, e um apelo a $this exibido:

 /** * Strict standards: Non-static method Strict::test() should not be called statically */ class Strict { public function test() { echo "Test"; } } Strict::test(); 


Este tipo de erro é relevante para o PHP versão 5.6 e quase todos foram cortados
7 correspondências. Leia mais na RFC relevante . Se alguém souber onde mais esses erros permaneceram, escreva nos comentários


E_DEPRECATED

Portanto, o PHP jurará se você usar funções obsoletas (ou seja, aquelas marcadas como obsoletas e que não estarão no próximo grande lançamento):

 /** * Deprecated: Function split() is deprecated */ //  ,   PHP 7.0 //    PHP 5.3 split(',', 'a,b'); 

No meu editor, funções semelhantes serão riscadas:

PHP E_DEPRECATED sem PHPStorm

Custom


Esse tipo, que o próprio desenvolvedor de código “cria”, não os vejo há muito tempo e não recomendo que você os abuse:

  • E_USER_ERROR - erro crítico
  • E_USER_WARNING - não é um erro crítico
  • E_USER_NOTICE - mensagens que não são erros

Separadamente, vale a pena notar E_USER_DEPRECATED - esse tipo ainda é usado com muita frequência para lembrar ao programador que o método ou função está desatualizado e é hora de reescrever o código sem usá-lo. A função trigger_error () é usada para criar erros semelhantes e semelhantes:

 /** * @deprecated Deprecated since version 1.2, to be removed in 2.0 */ function generateToken() { trigger_error('Function `generateToken` is deprecated, use class `Token` instead', E_USER_DEPRECATED); // ... // code ... // ... } 

Agora que você se familiarizou com a maioria dos tipos e tipos de erros, é hora de dar uma breve explicação sobre a operação da diretiva display_errors :

  • se display_errors = on , em caso de erro, o navegador receberá html com o texto e o código do erro 200
  • se display_errors = off , para erros fatais o código de resposta será 500 e o resultado não será retornado ao usuário, para outros erros - o código não funcionará corretamente, mas não contará a ninguém sobre isso


Domar


Existem 3 funções para trabalhar com erros no PHP:

  • set_error_handler () - define um manipulador para erros que não interrompem o script (ou seja, para erros não fatais)
  • error_get_last () - obtém informações sobre o último erro
  • register_shutdown_function () - registra um manipulador que será iniciado quando o script terminar. Esta função não se aplica diretamente a manipuladores de erros, mas é frequentemente usada para esse fim.

Agora, alguns detalhes sobre o tratamento de erros usando set_error_handler() , como argumentos, essa função aceita o nome da função à qual será atribuída a missão para manipular erros e os tipos de erros que serão monitorados. Um manipulador de erros também pode ser um método de classe ou uma função anônima. O principal é que ele recebe a seguinte lista de argumentos:

  • $errno - o primeiro argumento contém o tipo de erro como um número inteiro
  • $errstr - o segundo argumento contém uma mensagem de erro
  • $errfile - um terceiro argumento opcional contém o nome do arquivo no qual o erro ocorreu
  • $errline - um quarto argumento opcional contém o número da linha na qual o erro ocorreu
  • $errcontext - o quinto argumento opcional contém uma matriz de todas as variáveis ​​existentes no escopo em que ocorreu o erro

Se o manipulador retornou true , o erro será considerado processado e o script continuará sendo executado; caso contrário, será chamado um manipulador padrão que registrará o erro e, dependendo do seu tipo, continuará executando o script ou completá-lo. Aqui está um manipulador de exemplo:

 <?php //    ,  E_NOTICE error_reporting(E_ALL & ~E_NOTICE); ini_set('display_errors', 1); //    function myHandler($level, $message, $file, $line, $context) { //         switch ($level) { case E_WARNING: $type = 'Warning'; break; case E_NOTICE: $type = 'Notice'; break; default; //   E_WARNING   E_NOTICE //      //      PHP return false; } //    echo "<h2>$type: $message</h2>"; echo "<p><strong>File</strong>: $file:$line</p>"; echo "<p><strong>Context</strong>: $". join(', $', array_keys($context))."</p>"; // ,    ,      return true; } //   ,         set_error_handler('myHandler', E_ALL); 

Você não poderá atribuir mais de uma função para manipular erros, embora eu realmente queira registrar meu próprio manipulador para cada tipo de erro, mas não - escreva um manipulador e descreva toda a lógica de exibição de cada tipo diretamente nele
Há um problema significativo com o manipulador que está escrito acima - ele não captura erros fatais e, com esses erros, em vez do site, os usuários verão apenas uma página em branco ou, pior ainda, uma mensagem de erro. Para evitar esse cenário, você deve usar a função register_shutdown_function () e usá-la para registrar uma função que sempre será executada no final do script:

 function shutdown() { echo '    '; } register_shutdown_function('shutdown'); 

Esta função sempre funcionará!

Mas voltando aos erros, para rastrear a aparência do erro no código do erro, usamos a função error_get_last () , com sua ajuda, você pode obter informações sobre o último erro detectado e, como erros fatais interrompem a execução do código, eles sempre desempenharão o papel do "último":

 function shutdown() { $error = error_get_last(); if ( //       is_array($error) && //       in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR]) ) { //    (       ) while (ob_get_level()) { ob_end_clean(); } //    echo "    ,  "; } } register_shutdown_function('shutdown'); 

Gostaria de chamar a atenção para o fato de que esse código ocorre até para tratamento de erros, e você pode até encontrá-lo, mas perdeu relevância desde a 7ª versão do PHP. O que veio substituir, vou contar um pouco mais tarde.
Tarefa
Complemente o manipulador de erros fatais com a saída do código-fonte do arquivo em que o erro foi cometido e também adicione realce de sintaxe do código de saída.

Sobre gula


Vamos fazer um teste simples e descobrir quantos recursos preciosos o erro mais trivial consome:

 /** *      */ //     $time= microtime(true); define('AAA', 'AAA'); $arr = []; for ($i = 0; $i < 10000; $i++) { $arr[AAA] = $i; } printf('%f seconds <br/>', microtime(true) - $time); 

Como resultado da execução desse script, obtive este resultado:

 0.002867 seconds 

Agora adicione o erro no loop:

 /** *     */ //     $time= microtime(true); $arr = []; for ($i = 0; $i < 10000; $i++) { $arr[BBB] = $i; //   ,      } printf('%f seconds <br/>', microtime(true) - $time); 

O resultado é provavelmente pior, e uma ordem de magnitude (mesmo duas ordens de magnitude!):

 0.263645 seconds 

A conclusão é clara - os erros no código levam à excessiva gula de scripts - portanto, ative a exibição de todos os erros durante o desenvolvimento e teste de aplicativos!
Os testes foram realizados em várias versões do PHP e, em todo lugar, a diferença é dezenas de vezes, portanto, esse é outro motivo para corrigir todos os erros no código

Onde está o cachorro enterrado


O PHP possui um símbolo especial “@” - um operador de supressão de erro, que é usado para não gravar a manipulação de erros, mas depende do comportamento correto do PHP; nesse caso:

 <?php echo @UNKNOWN_CONSTANT; 

Nesse caso, o manipulador de erros especificado em set_error_handler() ainda será chamado e o fato de a supressão ter sido aplicada ao erro pode ser rastreado chamando a função error_reporting() dentro do manipulador, caso em que retornará 0 .
Se você suprimir erros dessa maneira, isso reduzirá a carga no processador em comparação com se você simplesmente os oculta (veja o teste comparativo acima), mas, em qualquer caso, suprimir erros é ruim.
Tarefa
Verifique como a supressão de erro com @ afeta o exemplo do loop anterior.

Exceções


Na era do PHP4, não havia exceções, tudo era muito mais complicado, e os desenvolvedores lutaram com os erros da melhor maneira possível: foi uma batalha não pela vida, mas pela morte ... Você pode mergulhar nessa fascinante história do confronto no artigo Código Excepcional. Parte 1 Devo ler agora? Não posso dar uma resposta definitiva. Quero apenas observar que isso ajudará você a entender a evolução do idioma e revelará todo o charme das exceções.
Exceções são eventos excepcionais no PHP, diferentemente dos erros, não apenas indicam um problema, mas requerem ações adicionais do programador para lidar com cada caso específico.

Por exemplo, um script deve salvar alguns dados em um arquivo de cache se algo der errado (sem acesso de gravação, sem espaço em disco), uma exceção do tipo correspondente for gerada e a decisão for tomada no manipulador de exceções - salve em outro local ou informe o usuário sobre o problema.

Uma exceção é um objeto da classe Exception ou de um de seus muitos descendentes, contém o texto do erro, status e também pode conter um link para outra exceção que se tornou a causa raiz disso. O modelo de exceção no PHP é semelhante ao usado em outras linguagens de programação. Uma exceção pode ser lançada (como se diz, "throw") usando o operador throw , e você pode capturar ("catch") a instrução catch . O código que gera a exceção deve estar entre um bloco try para capturar a exceção. Cada bloco try deve ter pelo menos uma catch correspondente ou, finally bloco:

 try { //      if (random_int(0, 1)) { throw new Exception("One"); } echo "Zero" } catch (Exception $e) { //      echo $e->getMessage(); } 

Em quais casos vale a pena usar exceções:

  • se dentro da estrutura de um método / função houver várias operações que podem falhar
  • se sua estrutura ou biblioteca declara seu uso

Para ilustrar o primeiro cenário, tomamos um exemplo já verbalizado de uma função para gravar dados em um arquivo - muitos fatores podem nos impedir, mas para informar o código acima qual era exatamente o problema, você precisa criar e lançar uma exceção:

 $directory = __DIR__ . DIRECTORY_SEPARATOR . 'logs'; //     if (!is_dir($directory)) { throw new Exception('Directory `logs` is not exists'); } //         if (!is_writable($directory)) { throw new Exception('Directory `logs` is not writable'); } //  -   ,      if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Ym-d') . '.log', 'a+')) { throw new Exception('System can\'t create log file'); } fputs($file, date("[H:i:s]") . " done\n"); fclose($file); 

Conseqüentemente, capturaremos essas exceções assim:

 try { //      // ... } catch (Exception $e) { //    echo " : ". $e->getMessage(); } 

Este exemplo mostra um cenário muito simples para lidar com exceções, quando temos alguma exceção tratada de uma maneira. Mas, muitas vezes, várias exceções exigem uma abordagem diferente para o processamento, e você deve usar códigos de exceção e definir a hierarquia de exceções no aplicativo:

 //    class FileSystemException extends Exception {} //     class DirectoryException extends FileSystemException { //   const DIRECTORY_NOT_EXISTS = 1; const DIRECTORY_NOT_WRITABLE = 2; } //     class FileException extends FileSystemException {} 

Agora, se você usar essas exceções, poderá obter o seguinte código:

 try { //      if (!is_dir($directory)) { throw new DirectoryException('Directory `logs` is not exists', DirectoryException::DIRECTORY_NOT_EXISTS); } if (!is_writable($directory)) { throw new DirectoryException('Directory `logs` is not writable', DirectoryException::DIRECTORY_NOT_WRITABLE); } if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Ym-d') . '.log', 'a+')) { throw new FileException('System can\'t open log file'); } fputs($file, date("[H:i:s]") . " done\n"); fclose($file); } catch (DirectoryException $e) { echo "   : ". $e->getMessage(); } catch (FileException $e) { echo "   : ". $e->getMessage(); } catch (FileSystemException $e) { echo "  : ". $e->getMessage(); } catch (Exception $e) { echo " : ". $e->getMessage(); } 

É importante lembrar que a exceção é principalmente um evento excepcional, ou seja, uma exceção à regra. Você não precisa usá-los para lidar com erros óbvios, por exemplo, para validar a entrada do usuário (embora isso não seja tão simples). Nesse caso, o manipulador de exceção deve ser gravado no local em que será capaz de lidar com isso. Por exemplo, o manipulador de exceções causadas pela inacessibilidade de um arquivo para gravação deve estar no método responsável pela seleção do arquivo ou no método que o chama, para que ele possa selecionar outro arquivo ou um diretório diferente.

Então, o que acontecerá se você não capturar a exceção? Você receberá "Erro fatal: exceção não capturada ...". Desagradável.

Para evitar essa situação, você deve usar a função set_exception_handler () e definir o manipulador para exceções que são lançadas fora do bloco try-catch e não foram processadas. Após chamar esse manipulador, a execução do script será interrompida:

 //     //     set_exception_handler(function($exception) { /** @var Exception $exception */ echo $exception->getMessage(), "<br/>\n"; echo $exception->getFile(), ':', $exception->getLine(), "<br/>\n"; echo $exception->getTraceAsString(), "<br/>\n"; }); 

Também vou falar sobre a construção usando o bloco finally - esse bloco será executado independentemente de uma exceção ter sido lançada ou não:

 try { //      } catch (Exception $e) { //      //     } finally { // ,       } 

Para entender o que isso nos dá, darei o seguinte exemplo de uso do bloco finally :

 try { // -    //     $handler = mysqli_connect('localhost', 'root', '', 'test'); try { //        // ... throw new Exception('DB error'); } catch (Exception $e) { //  ,     //     ,    throw new Exception('Catch exception', 0, $e); } finally { // ,      //      finally mysqli_close($handler); } //     ,       echo "Ok"; } catch (Exception $e) { //  ,    echo $e->getMessage(); echo "<br/>"; //      echo $e->getPrevious()->getMessage(); } 

I.e. lembre-se - o bloco finally será executado mesmo se você lançar uma exceção acima no bloco de catch (na verdade, é isso que ele pretendia).

Para um artigo introdutório de informações, que deseja obter mais detalhes, você as encontrará no artigo Código excepcional ;)

Tarefa
Escreva seu manipulador de exceção, com a saída do texto do arquivo em que ocorreu o erro e tudo isso com destaque para a sintaxe, também não se esqueça de exibir o rastreio de forma legível. Para referência, veja como é legal nos gritos .

PHP7 - nem tudo está como antes


Então, agora você aprendeu todas as informações acima e agora carregarei inovações no PHP7, ou seja,Vou falar sobre o que você encontrará ao trabalhar em um projeto PHP moderno. Anteriormente, eu lhe disse e mostrei com exemplos quais muletas você precisa construir para detectar erros críticos, e assim - no PHP7 eles decidiram consertar, mas? como sempre? vinculado à compatibilidade com versões anteriores do código e recebido, embora seja uma solução universal, mas está longe de ser o ideal. E agora sobre os pontos sobre as mudanças:

  1. quando erros fatais do tipo E_ERRORou erros fatais ocorrem com a possibilidade de processar o E_RECOVERABLE_ERRORPHP lança uma exceção
  2. essas exceções não herdam a classe Exception (lembre-se, eu falei sobre compatibilidade com versões anteriores, é tudo por causa dela)
  3. essas exceções herdam a classe Error
  4. as classes Exception e Error implementam a interface Throwable
  5. você não pode implementar a interface jogável no seu código

A interface Throwablenos repete quase completamente Exception:

 interface Throwable { public function getMessage(): string; public function getCode(): int; public function getFile(): string; public function getLine(): int; public function getTrace(): array; public function getTraceAsString(): string; public function getPrevious(): Throwable; public function __toString(): string; } 

Isso é difícil? Agora, para exemplos, considere aqueles que foram mais altos e levemente modernizados:

 try { // ,     include 'e_parse_include.php'; } catch (Error $e) { var_dump($e); } 

Como resultado, captamos o erro e imprimimos:

 object(ParseError)#1 (7) { ["message":protected] => string(48) "syntax error, unexpected '' (T_STRING)" ["string":"Error":private] => string(0) "" ["code":protected] => int(0) ["file":protected] => string(49) "/www/education/error/e_parse_include.php" ["line":protected] => int(4) ["trace":"Error":private] => array(0) { } ["previous":"Error":private] => NULL } 

Como você pode ver, eles capturaram a exceção ParseError , que é a sucessora da exceção Errorque implementa a interface Throwablena casa que Jack construiu. Existem muitas outras exceções, mas não vou atormentar - para maior clareza, darei uma hierarquia de exceções:

 interface Throwable |- Exception implements Throwable | |- ErrorException extends Exception | |- ... extends Exception | `- ... extends Exception `- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- ArithmeticError extends Error | `- DivisionByZeroError extends ArithmeticError `- AssertionError extends Error 

E um pouco mais detalhadamente:

TypeError - para erros quando o tipo de argumento da função não corresponde ao tipo passado:

 try { (function(int $one, int $two) { return; })('one', 'two'); } catch (TypeError $e) { echo $e->getMessage(); } 

ArithmeticError - pode ocorrer durante operações matemáticas, por exemplo, quando o resultado do cálculo excede o limite alocado para um número inteiro:

 try { 1 << -1; } catch (ArithmeticError $e) { echo $e->getMessage(); } 

DivisionByZeroError - divisão por erro zero:

 try { 1 / 0; } catch (ArithmeticError $e) { echo $e->getMessage(); } 

AssertionError - um animal raro que aparece quando a condição especificada em assert () não é satisfeita:

 ini_set('zend.assertions', 1); ini_set('assert.exception', 1); try { assert(1 === 0); } catch (AssertionError $e) { echo $e->getMessage(); } 

Em configurações directiva produção em servidor zend.assertionse assert.exceptioncortado, e com razão
Você encontrará uma lista completa de exceções predefinidas no manual oficial , na mesma hierarquia de exceções de SPL .

Tarefa
Escreva um manipulador de erros universal para o PHP7 que capture todas as exceções possíveis.

Ao escrever esta seção, foram utilizados materiais do artigo Exceções e erros lançáveis ​​no PHP 7 .

Uniformidade


- Existem erros, exceções, mas tudo isso pode ser de alguma forma associado à pilha?

Sim, é fácil, temos set_error_handler()um e ninguém nos proibirá de lançar uma exceção dentro deste manipulador:

 //     function errorHandler($severity, $message, $file = null, $line = null) { //  ,       @ if (error_reporting() === 0) { return false; } throw new \ErrorException($message, 0, $severity, $file, $line); } //   -  set_error_handler('errorHandler', E_ALL); 

Mas essa abordagem com o PHP7 é redundante, agora ele pode lidar com tudo Throwable:

 try { /** ... **/ } catch (\Throwable $e) { //      echo $e->getMessage(); } 

Depuração


Às vezes, para depurar código, é necessário rastrear o que aconteceu com uma variável ou objeto em um determinado estágio; para esses fins, existe uma função debug_backtrace () e debug_print_backtrace () que retornará o histórico de chamadas para funções / métodos na ordem inversa:

 <?php function example() { echo '<pre>'; debug_print_backtrace(); echo '</pre>'; } class ExampleClass { public static function method () { example(); } } ExampleClass::method(); 

Como resultado da execução da função debug_print_backtrace(), uma lista de chamadas que nos levaram a este ponto será exibida:

 #0 example() called at [/www/education/error/backtrace.php:10] #1 ExampleClass::method() called at [/www/education/error/backtrace.php:14] 

Você pode verificar o código quanto a erros de sintaxe usando a função php_check_syntax () ou o comando php -l [ ], mas eu não vi o uso deles.

Afirmar


Eu também gostaria de falar sobre uma fera exótica como assert () em PHP. Na verdade, esta peça pode ser considerada uma imitação para a metodologia de programação de contratos, e depois vou lhe contar como nunca a usei :)
A função assert()mudou seu comportamento durante a transição da versão 5.6 para a 7.0, e tudo mudou ainda mais na versão 7.2, portanto, leia atentamente os registros de alterações e o PHP;)
O primeiro caso é quando você precisa escrever TODO diretamente no código, para não esquecer de implementar a funcionalidade fornecida:

 //  asserts  php.ini // zend.assertions=1 assert(false, "Remove it!"); 

Como resultado da execução desse código, obtemos E_WARNING:

 Warning: assert(): Remove it! failed 

O PHP7 pode ser alternado para o modo de exceção e, em vez de um erro, sempre aparecerá uma exceção AssertionError:

 //    «» ini_set('assert.exception', 1); assert(false, "Remove it!"); 

Como resultado, esperamos uma exceção AssertionError.

Se necessário, você pode lançar uma exceção arbitrária:

 assert(false, new Exception("Remove it!")); 

Eu recomendaria o uso de tags @TODO, os IDEs modernos funcionam bem com eles e você não precisará empregar esforços e recursos extras para trabalhar com eles, embora a tentação de "marcar" com eles seja grande
O segundo caso de uso é criar algum tipo de TDD, mas lembre-se, isso é apenas uma semelhança. Embora, se você se esforçar, pode obter um resultado engraçado que ajudará no teste do seu código:

 // callback-      function backlog($script, $line, $code, $message) { echo $message; } //  callback- assert_options(ASSERT_CALLBACK, 'backlog'); //    assert_options(ASSERT_WARNING, false); //      assert(sqr(4) === 16, 'When I send integer, function should return square of it'); // ,   function sqr($a) { return; //    } 

A terceira opção é um tipo de programação de contrato, quando você descreveu as regras para usar sua biblioteca, mas deseja certificar-se de que é entendido corretamente e, nesse caso, informar imediatamente ao desenvolvedor um erro (nem tenho certeza se o entendi corretamente, mas um exemplo O código está funcionando bem):

 /** *        * * [ * 'host' => 'localhost', * 'port' => 3306, * 'name' => 'dbname', * 'user' => 'root', * 'pass' => '' * ] * * @param $settings */ function setupDb ($settings) { //   assert(isset($settings['host']), 'Db `host` is required'); assert(isset($settings['port']) && is_int($settings['port']), 'Db `port` is required, should be integer'); assert(isset($settings['name']), 'Db `name` is required, should be integer'); //    // ... } setupDb(['host' => 'localhost']); 


Se você está interessado em contratos, especificamente para você, tenho um link para o framework PhpDeal .


Nunca use assert()para verificar os parâmetros de entrada, porque na verdade ele assert()interpreta o primeiro parâmetro (se comporta como eval()), e isso está repleto de injeção de PHP. E sim, esse é o comportamento correto, porque se você desabilitar a declaração, todos os argumentos passados ​​serão ignorados e, se você fizer como no exemplo acima, o código será executado e o resultado booleano da execução será passado dentro da declaração desabilitada. Ah, e isso mudou no PHP 7.2 :)


Se você tiver uma experiência de uso ao vivo assert()- compartilhe comigo, serei grato. E sim, aqui está outra leitura interessante para você sobre este tópico - asserções PHP , com a mesma pergunta no final :)

Em conclusão


Escreverei as conclusões deste artigo para você:

  • Luta contra erros - eles não devem estar no seu código
  • Use exceções - o trabalho com elas precisa ser organizado adequadamente e haverá felicidade
  • Afirmar - aprendeu sobre eles e bem

PS


Este é um repost de uma série de artigos "PHP para iniciantes":


Se você tiver comentários sobre o material do artigo, ou possivelmente em forma, descreva a essência dos comentários, e tornaremos esse material ainda melhor.

Agradecimentos a Maxim Slesarenko pela ajuda na redação do artigo.

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


All Articles