Maison  >  Article  >  développement back-end  >  Introduction à la gestion des erreurs et à la localisation des problèmes sous PHP5 (exemple de code)

Introduction à la gestion des erreurs et à la localisation des problèmes sous PHP5 (exemple de code)

不言
不言avant
2019-01-09 10:38:102585parcourir

Le contenu de cet article est une introduction à la gestion des erreurs et à la localisation des problèmes sous PHP5 (exemples de code). Les amis dans le besoin peuvent s'y référer.

Parlons de la façon de localiser le problème lorsque PHP rencontre une erreur d'exécution fatale de niveau E_ERROR. Par exemple, Fatal error: Allowed memory size of débordement de mémoire. Lorsque ce type d'erreur se produit, le programme se fermera directement. Un journal des erreurs sera enregistré dans le journal des erreurs de PHP indiquant le fichier spécifique et le nombre de lignes de code où l'erreur a été signalée, et aucune autre information ne sera perdue. S'il s'agit de PHP7, vous pouvez détecter des erreurs telles que des exceptions, mais pas avec PHP5.

La méthode généralement envisagée consiste à examiner le code spécifique du rapport d'erreur. Si le fichier de rapport d'erreur est CommonReturn.class.php, il ressemblera à ce qui suit.

<?php

/**
 * 公共返回封装
 * Class CommonReturn
 */
class CommonReturn
{

    /**
     * 打包函数
     * @param     $params
     * @param int $status
     *
     * @return mixed
     */
    static public function packData($params, $status = 0)
    {
        $res[&#39;status&#39;] = $status;
        $res[&#39;data&#39;] = json_encode($params);
        return $res;
    }

}

La ligne json_encode a signalé une erreur. Ensuite, vous avez vérifié la méthode packData. Elle est appelée dans de nombreuses classes du projet. Comment localiser le problème ?

Relecture de la scène

D'accord, rejouons d'abord la scène. Si le programme effectivement appelé bug.php est le suivant

<?php

require_once &#39;./CommonReturn.class.php&#39;;

$res = ini_set(&#39;memory_limit&#39;, &#39;1m&#39;);

$res = [];
$char = str_repeat(&#39;x&#39;, 999);
for ($i = 0; $i < 900 ; $i++) {
    $res[] = $char;
}

$get_pack = CommonReturn::packData($res);

// something else

et exécute bug.php, le journal des erreurs PHP enregistrera que

[08-Jan-2019 11:22:52 Asia/Shanghai] PHP Fatal error:  Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes) in /CommonReturn.class.php on line 20

est reproduit avec succès, et le journal des erreurs indique uniquement le fichier qui a signalé l'erreur. Avec quelle ligne de code, nous ne pouvons pas connaître les informations de pile de contexte du programme, et nous ne savons pas quel élément de logique métier a été appelé, nous ne pouvons donc pas localiser et corriger l'erreur. Comment résoudre un problème si cela se produit occasionnellement et qu'il n'y a aucun retour de la part de l'activité front-end.

Idées de solutions

1. Certaines personnes ont pensé à modifier memory_limit pour augmenter l'allocation de mémoire, mais cette méthode traite les symptômes plutôt que la cause profonde. Lors du développement, vous devez trouver la cause première du problème.

2. Activez le core dump. Si le fichier de code est généré, il peut être débogué. Cependant, il s'avère que le code ne sera généré que lorsque le processus se terminera anormalement. Les erreurs au niveau E_ERROR ne génèrent pas nécessairement des fichiers de code. La possibilité de débordement de mémoire est gérée par PHP en interne.

3. Utilisez register_shutdown_function pour enregistrer une fonction de rappel lorsque PHP se termine, puis appelez error_get_last si la dernière erreur survenue est obtenue, utilisez debug_print_backtrace pour obtenir les informations sur la pile du programme.

Modifiez le fichier CommonReturn.class.php comme suit

<?php

/**
 * 公共返回封装
 * Class CommonReturn
 */
class CommonReturn
{

    /**
     * 打包函数
     * @param     $params
     * @param int $status
     *
     * @return mixed
     */
    static public function packData($params, $status = 0)
    {

        register_shutdown_function([&#39;CommonReturn&#39;, &#39;handleFatal&#39;]);

        $res[&#39;status&#39;] = $status;
        $res[&#39;data&#39;] = json_encode($params);
        return $res;
    }

    /**
     * 错误处理
     */
    static protected function handleFatal()
    {
        $err = error_get_last();
        if ($err[&#39;type&#39;]) {
            ob_start();
            debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5);
            $trace = ob_get_clean();
            $log_cont = &#39;time=%s&#39; . PHP_EOL . &#39;error_get_last:%s&#39; . PHP_EOL . &#39;trace:%s&#39; . PHP_EOL;
            @file_put_contents(&#39;/tmp/debug_&#39; . __FUNCTION__ . &#39;.log&#39;, sprintf($log_cont, date(&#39;Y-m-d H:i:s&#39;), var_export($err, 1), $trace), FILE_APPEND);
        }

    }

}

Exécutez à nouveau bug.php, le journal est le suivant.

error_get_last:array (
  &#39;type&#39; => 1,
  'message' => 'Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes)',
  'file' => '/CommonReturn.class.php',
  'line' => 23,
)
trace:#0  CommonReturn::handleFatal()

Les informations de traçabilité n'ont aucune source, ce qui est embarrassant. Je suppose que parce que les informations de trace sont stockées en mémoire et seront effacées lorsqu'une erreur fatale se produit. Il n'y a pas d'autre moyen, essayez de transmettre la trace depuis l'extérieur. Modifiez à nouveau CommonReturn.class.php.

<?php

/**
 * 公共返回封装
 * Class CommonReturn
 */
class CommonReturn
{

    /**
     * 打包函数
     * @param     $params
     * @param int $status
     *
     * @return mixed
     */
    static public function packData($params, $status = 0)
    {

        ob_start();
        debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5);
        $trace = ob_get_clean();
        register_shutdown_function([&#39;CommonReturn&#39;, &#39;handleFatal&#39;], $trace);

        $res[&#39;status&#39;] = $status;
        $res[&#39;data&#39;] = json_encode($params);
        return $res;
    }

    /**
     * 错误处理
     * @param $trace
     */
    static protected function handleFatal($trace)
    {
        $err = error_get_last();
        if ($err[&#39;type&#39;]) {
            $log_cont = &#39;time=%s&#39; . PHP_EOL . &#39;error_get_last:%s&#39; . PHP_EOL . &#39;trace:%s&#39; . PHP_EOL;
            @file_put_contents(&#39;/tmp/debug_&#39; . __FUNCTION__ . &#39;.log&#39;, sprintf($log_cont, date(&#39;Y-m-d H:i:s&#39;), var_export($err, 1), $trace), FILE_APPEND);
        }

    }

}

Exécutez bug.php à nouveau, le journal est le suivant.

error_get_last:array (
  &#39;type&#39; => 1,
  'message' => 'Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes)',
  'file' => '/CommonReturn.class.php',
  'line' => 26,
)
trace:#0  CommonReturn::packData() called at [/bug.php:13]

La source de l'appel a été localisée avec succès à la ligne 13 de bug.php. Publiez le CommonReturn.class.php final dans l'environnement de production et consultez simplement le journal lorsqu'une erreur se reproduit. Mais dans ce cas, tous les programmes qui appellent packData exécuteront la fonction de trace, ce qui affectera certainement les performances.

Résumé

  1. Vous devez faire attention à la fonction register_shutdown_function utilisée. Vous pouvez enregistrer plusieurs rappels différents, mais si une certaine fonction de rappel est utilisée. vous quittez, les fonctions de rappel enregistrées ultérieurement ne seront pas exécutées.

  2. debug_print_backtrace est une fonction qui obtient les informations de backtrace. La première contient les paramètres de requête, et la seconde est le nombre de niveaux d'enregistrement de backtrace. Nous ne renvoyons pas de paramètres de requête ici, ce qui peut être le cas. économisez de la mémoire, et si les paramètres de la requête sont énormes, l'appel de cette fonction peut directement déborder de la mémoire.

  1. Le meilleur moyen est de mettre à niveau PHP7, qui peut détecter des erreurs telles que des exceptions.


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer