Ita*_*vka 15 php exception-handling try-catch
我的项目中没有多种异常.
现在,(我们使用MVC)我有try catch包含我的整个代码:
try{
fronController::dispatch($somthing...);
}catch(Exception $E){
//handle errors
}
Run Code Online (Sandbox Code Playgroud)
我想知道是否有充分的理由以尽可能具体的方式使用try-catch块,或者只是保持它现在的一般性?
eri*_*sco 57
异常的想法是,函数可以报告失败而不必返回特殊值.在旧的PHP中,函数可以说它有问题的唯一方法是返回一些特殊值,如false或-1.这不愉快.例如,假设我正在编写file_get_contents()的变体.
典型的返回值是句柄 - 由正整数表示.但是,我遇到两个基本问题:找不到您指定的文件,或者您指定的文件不可读.为了表明错误,我可能会返回一个负数 - 因为句柄是正的 - 它与特定的错误原因相关联.假设-1表示文件不存在,-2表示文件不可读.
现在我们遇到一个问题,即-1和-2 对读取代码的人本身并不具有任何意义.为了纠正这个问题,我们引入了全局常量FILE_NOT_FOUND和FILE_NOT_READABLE.让我们看看一些结果代码.
<?php
define('FILE_NOT_FOUND', -1);
define('FILE_NOT_READABLE', -2);
function my_file_get_contents($file) {
// blah blah blah
}
$friendListFile = getDefaultFriendListFile();
$result = my_file_get_contents($friendListFile);
if ($result == FILE_NOT_FOUND) {
deleteFriendListFromMenu();
} elseif ($result == FILE_NOT_READABLE) {
alertUserAboutPermissionProblem();
} else {
useFriendList($result);
}
Run Code Online (Sandbox Code Playgroud)
通过使用不同的错误代码,我们可以根据问题的真实情况采取相应措施.这个功能很好.问题纯粹在于代码的读取方式.
$result是一个可怕的变量名称.变量名称应该是描述性的和明显的,比如$friendListFile.对于真实姓名$result是$fileContentsOrErrorCode这不仅是太长,examplifies我们如何重载一个变量有两个含义.你永远不会希望拥有相同的数据意味着两件事.我们希望有一个独立的$errorCode和$fileContents!
那么我们如何解决这个问题呢?一些PHP库使用的一个非实际解决方案是,如果遇到问题,my_file_get_contents()可以返回false类似函数.为了消除实际问题的歧义,我们反而致电my_file_get_contents_getError().这几乎可行.
define('FILE_OKAY', 0);
define('FILE_NOT_FOUND', -1);
define('FILE_NOT_READABLE', -2);
$my_file_get_contents_error = FILE_OKAY;
function my_file_get_contents_getError() {
// blah blah blah
}
function my_file_get_contents($file) {
global $my_file_get_contents_error;
// blah blah blah
// whoa, an error? return false and store the error code in
// $my_file_get_contents_error
// no error? set $my_file_get_contents_error to FILE_OKAY
}
$friendListFile = getDefaultFriendListFile();
$result = my_file_get_contents($friendListFile);
if (my_file_get_contents_getError() == FILE_NOT_FOUND) {
deleteFriendListFromMenu();
} elseif (my_file_get_contents_getError() == FILE_NOT_READABLE) {
alertUserAboutPermissionProblem();
} elseif (my_file_get_contents_getError() == FILE_OKAY) {
useFriendList($result);
} else {
die('I have no idea what happened. my_file_get_contents_getError() returns '
. my_file_get_contents_getError()
);
}
Run Code Online (Sandbox Code Playgroud)
作为一个注释,是的,我们可以通过避免全局变量和其他这样的小位来做得更好.考虑一下这个螺母和螺栓的演示.
我们仍然不能称之为$result更好$fileContentsOrFalseIfError.这个问题尚未得到解决.
我现在纠正了你在前面的例子中可能已经注意到的一个问题.如果我们没有涵盖所有错误代码怎么办?如果程序员决定需要一个-3代码,我们最初没有检测到它!我们可以检查是否$result是一个字符串,以确保它不是一个错误代码,但我们不应该真正关心PHP中的类型,对吧?现在我们可以利用它的第二个返回值my_file_get_contents_getError()包含成功代码是没有问题的.
现在出现了一个全新的问题.修一个又找三个呃?新问题是只能保留最新的错误代码.这非常脆弱!如果my_file_get_contents()在处理错误代码之前还有其他任何调用,他们的代码将覆盖您的代码!
Gah,现在我们需要在处理my_file_get_contents_getError()的返回值之前保留一个不安全的函数列表.如果你不这样做,你必须保持一个ad-hoc编码约定,你总是my_file_get_contents_getError()立即调用它my_file_get_contents(),以便在神秘覆盖之前保存属于你的错误代码.
等待!为什么我们不直接向呼叫者分发标识符?为了使用my_file_get_contents()你现在必须要求create_my_file_get_contents_handle()一些能够与所有其他呼叫者消除歧义的号码.现在您可以打电话my_file_get_contents($myHandle, $myFile),错误代码可以存储在一个特殊的位置,只为你.现在,当你打电话时,my_file_get_contents_getError($myHandle)你可以访问那个特殊的地方,得到你的错误代码,没有人踩到你的脚趾.
呃,但如果有很多来电者,我们不希望有数以万计的无用错误代码.我们最好让用户在完成后拨打电话destroy_my_file_get_contents_handle($myHandle),这样我们就可以释放一些内存.
我希望老PHP的口头禅对这一切都非常熟悉.
如果语言支持更好的机制来应对错误,这意味着什么?显然,尝试使用现有工具创建一些解决方案令人困惑,讨厌且容易出错.
输入例外!
<?php
class FileNotFoundException extends Exception {}
class FileNotReadableException extends Exception {}
function my_file_get_contents($file) {
if (!is_file($file)) {
throw new FileNotFoundException($file);
} elseif (!is_readable($file)) {
throw new FileNotReadableException($file);
} else {
// blah blah blah
}
}
$friendListFile = getDefaultFriendListFile();
try {
$fileContents = my_file_get_contents($friendListFile);
useFriendList($fileContents);
} catch (FileNotFoundException $e) {
deleteFriendListFromMenu();
} catch (FileNotReadableException $e) {
alertUserAboutPermissionProblem();
}
Run Code Online (Sandbox Code Playgroud)
突然间,我们对特殊返回值和句柄以及编码约定的旧烦恼得到了解决!
我们现在可以真正重命名$result为$fileContents.如果my_file_get_contents()有问题,分配将完全中止,我们跳到适当的catch块.只有在没有错误的情况下,我们才会考虑提供$fileContents价值或致电useFriendList().
我们不再受到多个呼叫者踩到彼此错误代码的困扰!如果出现错误,每次调用my_file_get_contents()都会实例化自己的异常.
没有记忆问题!垃圾收集器将很乐意清理不再使用的异常对象,而不用考虑它.使用旧的手柄系统,我们必须记住手动破坏手柄,以免它永远潜伏在记忆中.
异常还有许多其他好处和特征.我强烈建议您寻求其他来源了解这些.特别有趣的是它们如何冒泡执行堆栈,直到一些调用者可以捕获它们.同样有趣的是如何捕获异常,尝试解决问题,然后重新抛出异常,如果不能.不要忘记异常是对象!由此可以获得很大的灵活性.对于没有人可以捕获的异常,请查看异常处理程序.
我回答这个问题的意图是证明我们为什么需要例外.通过这样做,我希望很容易推断出我们可以用它们解决哪些问题.
通常在本地抛出,全局捕获,除非异常处理程序特定于某个函数,在这种情况下在本地处理。
class fooException extends Exception{}
// DB CLASS
public function Open(){
// open DB connection
...
if ($this->Conn->connect_errno)
throw new fooException("Could not connect: " . $this->Conn->connect_error);
}
// MAIN CLASS
public final function Main(){
try{
// do stuff
}
catch(fooException $ex){
//handle fooExceptions
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8023 次 |
| 最近记录: |