recherche
Maisondéveloppement back-endtutoriel phpPHP Exception 异常处理和 exit/die

一直很难理解异常处理,比如我的程序底层使用了 mysql 数据库连接,而且我的上层所有程序都建立在此基础上(不考虑缓存等其他),比如一个页面要取出当前 url 中 id 指定的 post 内容,当调用底层数据库连接时,结果 mysql_connect 无法连接,那建立在此基础上的应用也再没有执行的必要了,我的 mysql_connect 处不应该直接 exit/die 终止程序吗?即使说要友好的错误提示,那我可以自定义一个函数比如 MyError($code),在此函数中来美化我的输出再在里面决定要不要 exit/die 啊。

如果使用异常处理,那在我觉得所有可能出现不正确的地方,我都必须加上 try/catch 了?那我的一段程序下来岂不是一堆 try/catch ... 这和我直接用 die/exit 或者调用自定义 MyError() 有何分别?如果说 Exception 可以往上传递,但我很多时候就应该当即处理啊,就比如数据库连不上,或者我 include 系统配置的时候文件不存在,这个时候难道不应该当即做出处理吗?

比如我做了单入口,Router -> Controllers -> Services/Models -> ModelBase -> DbFactory -> MySQL -> Driver,是不是我在 Router 外面加个 try/catch 就可以了,里面全都 throw?比如我的 MySQL 中 mysql_connect 出现问题了,我的 Controller 里面在 get 取 id 时,url 中的 id 在数据库中不存在,那这两处我都要 try/catch/throw,然后在 Router 外面的 catch 中再处理吗?

实在是很混乱,求解答,手册都是教怎么用,没教应用场景,还有为什么要用?(那个为什么真心看不出为什么),求指点!能指出具体的应用场景最好了,谢谢~

2015-06-19

很感谢各位的详细回答,谢谢!还有一些问题想麻烦各位,写到评论里不太好,就拿来写到这里了。

比如配置文件丢失这个问题,处理的方法:

1、最原始的直接 require,这样配置文件不存在就直接报错了(报错打开),这样显然不合适,不友好而且会暴露物理路径。

2、我已经预先意识到了 require 可能会出现问题,所以决定在 require 之前先 is_file/file_exists 判断文件是否存在,那么:

<code>$file = '/a/b/c.php';
is_file($file) or die('config file not found');
require($file);
</code>

或者

<code>$file = '/a/b/c.php';
try{
    is_file($file) or throw new Exception('config file not found');
}catch(Exception $e){
    //todo
}
require($file);
</code>

第一个代码可能简陋了点,不多那个 die 可以换成自定义错误提示函数,也可以输出友好的错误信息。

那第二个代码有什么好处呢?是不是我在 //todo 处依旧抛出这个 $e,或者干脆这里不要 try/catch 了?假设我是单入口,最后整个系统的 Exception 都交给最上一层处理?

1、那依照分层处理的概念,现在就假设 config 这段代码为“config层”,首先可以肯定的是我的“Dispatcher层”、“Controller层”、“DB层”、“Model层”统统依赖于它,难道说我要这些层自己各自去处理这个异常吗?还是说这些层都各自再 throw 出去?或者这些层统统不管(我才不管呢,谁最后谁管)?这种“config层”一对多为其它层服务,那“config层”在配置文件丢失的时候不应该自己就处理掉吗?这不也符合异常尽量不扩散吗?

2、由“config层”自己处理的话,那 //todo 处理的时候不也应该 exit/die 吗?否则岂不是又去执行 require 了?

3、那如果它自己 exit/die 掉了,这个时候异常的好处不就仅仅是比我自定义的 MyError 多了 trace 信息吗?

回复内容:

一直很难理解异常处理,比如我的程序底层使用了 mysql 数据库连接,而且我的上层所有程序都建立在此基础上(不考虑缓存等其他),比如一个页面要取出当前 url 中 id 指定的 post 内容,当调用底层数据库连接时,结果 mysql_connect 无法连接,那建立在此基础上的应用也再没有执行的必要了,我的 mysql_connect 处不应该直接 exit/die 终止程序吗?即使说要友好的错误提示,那我可以自定义一个函数比如 MyError($code),在此函数中来美化我的输出再在里面决定要不要 exit/die 啊。

如果使用异常处理,那在我觉得所有可能出现不正确的地方,我都必须加上 try/catch 了?那我的一段程序下来岂不是一堆 try/catch ... 这和我直接用 die/exit 或者调用自定义 MyError() 有何分别?如果说 Exception 可以往上传递,但我很多时候就应该当即处理啊,就比如数据库连不上,或者我 include 系统配置的时候文件不存在,这个时候难道不应该当即做出处理吗?

比如我做了单入口,Router -> Controllers -> Services/Models -> ModelBase -> DbFactory -> MySQL -> Driver,是不是我在 Router 外面加个 try/catch 就可以了,里面全都 throw?比如我的 MySQL 中 mysql_connect 出现问题了,我的 Controller 里面在 get 取 id 时,url 中的 id 在数据库中不存在,那这两处我都要 try/catch/throw,然后在 Router 外面的 catch 中再处理吗?

实在是很混乱,求解答,手册都是教怎么用,没教应用场景,还有为什么要用?(那个为什么真心看不出为什么),求指点!能指出具体的应用场景最好了,谢谢~

2015-06-19

很感谢各位的详细回答,谢谢!还有一些问题想麻烦各位,写到评论里不太好,就拿来写到这里了。

比如配置文件丢失这个问题,处理的方法:

1、最原始的直接 require,这样配置文件不存在就直接报错了(报错打开),这样显然不合适,不友好而且会暴露物理路径。

2、我已经预先意识到了 require 可能会出现问题,所以决定在 require 之前先 is_file/file_exists 判断文件是否存在,那么:

<code>$file = '/a/b/c.php';
is_file($file) or die('config file not found');
require($file);
</code>

或者

<code>$file = '/a/b/c.php';
try{
    is_file($file) or throw new Exception('config file not found');
}catch(Exception $e){
    //todo
}
require($file);
</code>

第一个代码可能简陋了点,不多那个 die 可以换成自定义错误提示函数,也可以输出友好的错误信息。

那第二个代码有什么好处呢?是不是我在 //todo 处依旧抛出这个 $e,或者干脆这里不要 try/catch 了?假设我是单入口,最后整个系统的 Exception 都交给最上一层处理?

1、那依照分层处理的概念,现在就假设 config 这段代码为“config层”,首先可以肯定的是我的“Dispatcher层”、“Controller层”、“DB层”、“Model层”统统依赖于它,难道说我要这些层自己各自去处理这个异常吗?还是说这些层都各自再 throw 出去?或者这些层统统不管(我才不管呢,谁最后谁管)?这种“config层”一对多为其它层服务,那“config层”在配置文件丢失的时候不应该自己就处理掉吗?这不也符合异常尽量不扩散吗?

2、由“config层”自己处理的话,那 //todo 处理的时候不也应该 exit/die 吗?否则岂不是又去执行 require 了?

3、那如果它自己 exit/die 掉了,这个时候异常的好处不就仅仅是比我自定义的 MyError 多了 trace 信息吗?

基于你的这个问题来说,你需要有一定的抽象能力,要有封装的概念,其实我更喜欢称之为分层,也就是我们要建立类似下列概念:

<code>上层角色 Upper Role
------------------层分界线------------
当前层角色 Current Role
------------------层分界线------------
下层角色 Lower Role
</code>

基于上述概念来说,无论exit/die还是Exception可以分为2种情况:

<code> a. Upper Role作为接受方,Current Role作为行为方
 b. Current Role作为接受方,Lower Role作为行为方
</code>

对于a来说,你要考虑的做出的行为的接受方Upper Role是谁?如果Upper Role是Top Role(顶层角色,一般基于我们的应用来说,顶层角色指的是使用浏览器的人),那么就应该用exit/die,这个是要Top Role做出处理的,也就是除了Top Role以外的所有Upper Role无权干涉,而当Upper Role非Top Role,那么就应该用Exception,这样除了Top Role以外的所有Upper Role才有权利去进行一些额外处理。

基于a来说mysql_connect连接的事情,(按照我的设计)在使用mysql_connect时,Current Role指的是DB处理连接mysql相关逻辑,而Upper Role是调用DB的未知逻辑(想想这里我为什么要用“未知”这个概念),Current Role仅仅知道mysql_connect连接失败了,而并不知道Upper Role是否还有其他DB或额外选择,那么Current Role为了让Upper Role有一定选择权,这里(我)选择使用Exception,让Upper Role决定是交给Top Role处理还是更上层的Upper Role处理。

对于b的情况来说,Current Role要判断Lower Role是不是会有一些非Current Role期望的情况出现(即:Exception),则有以下选择

<code>是否有非Current Role期望的情况
如果没有,Current Role不需要try/catch,
如果有,Current Role需要处理么?
    Current Role需要处理,try/catch
       Current Role可以处理?
           可以处理,处理
           Upper Role需要处理Current Role的非期望,throw          
    Current Role不需要处理,无视         
</code>

基于b来说mysql_connect连接的事情,Current Role指的是需要用到DB的相关逻辑,而Lower Role是DB处理连接mysql相关逻辑,在Current Role使用的时候,Current Role期望mysql可以正常连接,但是额外情形也会出现,那么Current Role就要考虑自身的情况来选择,比如说Current Role是一个select操作,那么Current Role就是可以返回为空,那么对于msyql连接失败或者数据表真的为空,性质一样,Current Role就可以将非期望舍弃掉(捕获不处理)返回为空,而对于一个update来说,可以选择处理或者不处理都可以,而对于一个可以选择n个mysql 连接的逻辑来说,就必须处理,等等

总之,啰嗦了一堆,就是说你要用好异常,那么你要有上下层的概念,并且在上下层逻辑处理中,要分清Current Role是可以终止程序执行(exit)还是交由Upper Role处理(throw Excepton)

最后,throw是Current Role反馈给Upper Role,try/catch是Current Role处理Lower Role反馈,希望你能更好的使用Exception

楼主应该没有理解好 异常的执行机制,先读读PHP官方手册对异常的描述 点这里。

先不说异常该怎样使用,我们先看看 Exception 执行过程

<code>try {

    throw new Exception('This is first exception.');

    echo 'AAA';

} catch (Exception $e) {

    echo 'BBB';

}

//这里会输出
echo 'CCC';

throw new Exception('This is second exception.');

</code>

你觉得上面的输出结果是什么呢? 下面是答案

<code>BBBCCC

Fatal error: Uncaught exception 'Exception' with message 'This is second exception.' ...
</code>

从以上的执行结果,我们可以看出Exception的一些特点:

  1. try 与 catch 一定是成对出现的,try{ } 中包含可能会抛出异常的代码。
  2. try { } 中的代码一旦发生异常,那么异常后面的代码将停止执行。(这里特指try{ }里面的代码)
  3. 使用 catch(){ } 捕捉并处理完异常后,try{ }和catch(){} 后面的代码(比如这里的 echo 'CCC')会继续执行
  4. 如果异常没有被捕捉,那么将抛出一个致命错误 Fatal error。

结合以上的特点,那么贴主提出来的疑问,就比较容易解决了。


问题1:是不是每个有异常的地方都要try catch 一下?

我的答案:这样做太麻烦了,而且一般没必要,你可以在所有可能抛出异常的地方,用一个 try catch 包含即可。catch 到异常后,对谁处理,怎么样处理都可以。这个也满足单一入口,单一出口的开发理念


问题2:遇到错误,是抛 Exception 还是使用 die()/exit()

我的答案:异常你可以随便抛,但最终你必须有个地方处理。处理完后(比如记录日志等等),最终你要把错误告诉前端用户,告诉这个过程就是输出。一旦发生错误时,我推荐使用异常 Exception,因为它符合单一出口开发理念,这样你可以监控所有页面输出。 如果到处使用 die()/exit()来直接输出,那就无法控制输出了

再者,Exception 实际上本来就包含更丰富的信息,比如行数line、错误代码code、错误堆栈信息trace等等。所以不是更好吗?


问题3:应用场景问题,该什么时候用?

我的答案:异常在任何情况下用都可以,关键你想Exception起到什么作用了。比如自己在写API服务程序时,任何错误(包括程序异常、业务逻辑错误、字段类型错误等等),一律抛异常,一律由一个地方处理。实际上,我感觉这种开发体验是非常棒的,因为第一次写的时候,我不是使用Exception的,囧~。但这里有一个疑问:API 它是没有界面的,它只负责返回一些数据,而且返回的数据格式要求一般是统一的规范的

如果你在写一个前端程序,我一边写一边想,可不可以这样使用 Exception任何程序错误抛异常,任何业务上的验证出错时使用比如 return/echo/die 返回这样子。 因为毕竟异常能表达的东西自然是有限的,如果有些错误(一般业务错误)返回非常复杂,而且前端应用非API 自由度会比较大,用异常或许不太方便。

上面就是自己的愚见吧,有不对的地方,希望指出,共同进步吧!下班了,走人。。。

如果你希望全局捕获错误,或者异常,请看
http://cn2.php.net/manual/zh/function.set-error-handler.php
http://cn2.php.net/manual/zh/function.set-exception-handler.php

都允许用一个callable对象捕获错误或者异常

PHP调用exit退出脚本执行不会导致PHP服务退出,这个跟其他语言有本质区别,所以其他语言只好用try/catch捕获异常或判断返回值来进一步处理,对PHP则不是必须的。

看了这个帖子:http://bbs.phpchina.com/thread-212378-1-1.html,我的问题里可能没有理解异常,像数据库连不上或者配置文件丢失这种或许 halt 更安全直接虽然有点粗暴。

Déclaration
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Comment fonctionne la résistance au type PHP, y compris les types scalaires, les types de retour, les types d'union et les types nullables?Comment fonctionne la résistance au type PHP, y compris les types scalaires, les types de retour, les types d'union et les types nullables?Apr 17, 2025 am 12:25 AM

Le type PHP invite à améliorer la qualité et la lisibilité du code. 1) Conseils de type scalaire: Depuis PHP7.0, les types de données de base sont autorisés à être spécifiés dans les paramètres de fonction, tels que INT, Float, etc. 2) Invite de type de retour: Assurez la cohérence du type de valeur de retour de fonction. 3) Invite de type d'union: Depuis PHP8.0, plusieurs types peuvent être spécifiés dans les paramètres de fonction ou les valeurs de retour. 4) Invite de type nullable: permet d'inclure des valeurs nulles et de gérer les fonctions qui peuvent renvoyer les valeurs nulles.

Comment PHP gère le clonage des objets (mot-clé de clone) et la méthode de magie __clone?Comment PHP gère le clonage des objets (mot-clé de clone) et la méthode de magie __clone?Apr 17, 2025 am 12:24 AM

Dans PHP, utilisez le mot-clé Clone pour créer une copie de l'objet et personnalisez le comportement de clonage via la méthode de magie du clone \ _ \ _. 1. Utilisez le mot-clé Clone pour faire une copie peu profonde, en clonant les propriétés de l'objet mais pas aux propriétés de l'objet. 2. La méthode du clone \ _ \ _ peut copier profondément les objets imbriqués pour éviter les problèmes de copie superficiels. 3. Faites attention pour éviter les références circulaires et les problèmes de performance dans le clonage et optimiser les opérations de clonage pour améliorer l'efficacité.

PHP vs Python: cas d'utilisation et applicationsPHP vs Python: cas d'utilisation et applicationsApr 17, 2025 am 12:23 AM

PHP convient aux systèmes de développement Web et de gestion de contenu, et Python convient aux scripts de science des données, d'apprentissage automatique et d'automatisation. 1.Php fonctionne bien dans la création de sites Web et d'applications rapides et évolutifs et est couramment utilisé dans CMS tel que WordPress. 2. Python a permis de manière remarquable dans les domaines de la science des données et de l'apprentissage automatique, avec des bibliothèques riches telles que Numpy et Tensorflow.

Décrivez différents en-têtes de mise en cache HTTP (par exemple, contrôle du cache, ETAG, dernier modifié).Décrivez différents en-têtes de mise en cache HTTP (par exemple, contrôle du cache, ETAG, dernier modifié).Apr 17, 2025 am 12:22 AM

Les acteurs clés des en-têtes de cache HTTP incluent le contrôle du cache, l'ETAG et la dernière modification. 1.CACHE-Control est utilisé pour contrôler les politiques de mise en cache. Exemple: Cache-Control: Max-Age = 3600, public. 2. Etag vérifie les changements de ressources par le biais d'identifiants uniques, exemple: ETAG: "686897696A7C876B7E". 3.Last-modifié indique le dernier temps de modification de la ressource, exemple: dernier modifié: mer, 21oct201507: 28: 00gmt.

Expliquez le hachage de mot de passe sécurisé dans PHP (par exemple, Password_Hash, Password_verify). Pourquoi ne pas utiliser MD5 ou SHA1?Expliquez le hachage de mot de passe sécurisé dans PHP (par exemple, Password_Hash, Password_verify). Pourquoi ne pas utiliser MD5 ou SHA1?Apr 17, 2025 am 12:06 AM

Dans PHP, Password_Hash et Password_verify Les fonctions doivent être utilisées pour implémenter le hachage de mot de passe sécurisé, et MD5 ou SHA1 ne doit pas être utilisé. 1) Password_hash génère un hachage contenant des valeurs de sel pour améliorer la sécurité. 2) Password_verify Vérifiez le mot de passe et assurez-vous la sécurité en comparant les valeurs de hachage. 3) MD5 et SHA1 sont vulnérables et manquent de valeurs de sel, et ne conviennent pas à la sécurité de mot de passe moderne.

PHP: une introduction au langage des scripts côté serveurPHP: une introduction au langage des scripts côté serveurApr 16, 2025 am 12:18 AM

PHP est un langage de script côté serveur utilisé pour le développement Web dynamique et les applications côté serveur. 1.Php est un langage interprété qui ne nécessite pas de compilation et convient au développement rapide. 2. Le code PHP est intégré à HTML, ce qui facilite le développement de pages Web. 3. PHP traite la logique côté serveur, génère une sortie HTML et prend en charge l'interaction utilisateur et le traitement des données. 4. PHP peut interagir avec la base de données, traiter la soumission du formulaire et exécuter les tâches côté serveur.

PHP et le Web: explorer son impact à long termePHP et le Web: explorer son impact à long termeApr 16, 2025 am 12:17 AM

PHP a façonné le réseau au cours des dernières décennies et continuera de jouer un rôle important dans le développement Web. 1) PHP est originaire de 1994 et est devenu le premier choix pour les développeurs en raison de sa facilité d'utilisation et de son intégration transparente avec MySQL. 2) Ses fonctions principales incluent la génération de contenu dynamique et l'intégration à la base de données, ce qui permet au site Web d'être mis à jour en temps réel et affiché de manière personnalisée. 3) La large application et l'écosystème de PHP ont motivé son impact à long terme, mais il fait également face à des mises à jour de version et à des défis de sécurité. 4) Les améliorations des performances ces dernières années, telles que la sortie de PHP7, lui permettent de rivaliser avec les langues modernes. 5) À l'avenir, PHP doit faire face à de nouveaux défis tels que la conteneurisation et les microservices, mais sa flexibilité et sa communauté active le rendent adaptable.

Pourquoi utiliser PHP? Avantages et avantages expliquésPourquoi utiliser PHP? Avantages et avantages expliquésApr 16, 2025 am 12:16 AM

Les principaux avantages du PHP comprennent la facilité d'apprentissage, un soutien solide sur le développement Web, les bibliothèques et les cadres riches, les performances élevées et l'évolutivité, la compatibilité multiplateforme et la rentabilité. 1) Facile à apprendre et à utiliser, adapté aux débutants; 2) une bonne intégration avec les serveurs Web et prend en charge plusieurs bases de données; 3) ont des cadres puissants tels que Laravel; 4) Des performances élevées peuvent être obtenues grâce à l'optimisation; 5) prendre en charge plusieurs systèmes d'exploitation; 6) Open source pour réduire les coûts de développement.

See all articles

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
1 Il y a quelques moisBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
1 Il y a quelques moisBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
1 Il y a quelques moisBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Commandes de chat et comment les utiliser
1 Il y a quelques moisBy尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

Télécharger la version Mac de l'éditeur Atom

Télécharger la version Mac de l'éditeur Atom

L'éditeur open source le plus populaire

Adaptateur de serveur SAP NetWeaver pour Eclipse

Adaptateur de serveur SAP NetWeaver pour Eclipse

Intégrez Eclipse au serveur d'applications SAP NetWeaver.

Listes Sec

Listes Sec

SecLists est le compagnon ultime du testeur de sécurité. Il s'agit d'une collection de différents types de listes fréquemment utilisées lors des évaluations de sécurité, le tout en un seul endroit. SecLists contribue à rendre les tests de sécurité plus efficaces et productifs en fournissant facilement toutes les listes dont un testeur de sécurité pourrait avoir besoin. Les types de listes incluent les noms d'utilisateur, les mots de passe, les URL, les charges utiles floues, les modèles de données sensibles, les shells Web, etc. Le testeur peut simplement extraire ce référentiel sur une nouvelle machine de test et il aura accès à tous les types de listes dont il a besoin.

VSCode Windows 64 bits Télécharger

VSCode Windows 64 bits Télécharger

Un éditeur IDE gratuit et puissant lancé par Microsoft