Zend Framework 中的 Php 编码标准 (五) - 错误与异常

Zend Framework 中的 Php 编码标准 (五) - 错误与异常

原文 :  http://kbs.kimbs.cn/blog/list/post/27/title/zend-framework-coding-standards-for-php-errors-and-exceptions


1. Zend Framework 的代码应该不存在 E_STRICT 兼容问题。在开启错误报告 error_reporting 级别为 E_ALL | E_STRICT 时,Zend Framework 的代码不应该抛出任何警告(E_WARNING, E_USER_WARNING),任何通知(E_NOTICE, E_USER_NOTICE)以及任何兼容问题(E_STRICT)。

这就是说,Zend Framework 尽量避免代码写法上的错误。而如果真的发生程序中断,也只能是逻辑错误。


2. Zend Framework 不应该存在 Php 错误,如果我们不得不遇到错误的话,请用异常来处理。Zend Framework 中有专门的异常类来为用户提供友好的异常处理。

例如 :

class  Zend_Exception  extends  Exception

{

}



class 
Zend_Db_Exception  extends  Zend_Exception

{

}



class 
Zend_Db

{

    public static function 
factory ( $adapter $config  = array())

    {

        
// ...

        
if (! is_array ( $config )) {

            
/**

             * @see Zend_Db_Exception

             */

            
require_once  'Zend/Db/Exception.php' ;

            throw new 
Zend_Db_Exception ( 'Adapter parameters must be in'

                                      
'an array or a Zend_Config object' );

        }

    }

}


复制代码
3. 在框架模块内的异常统一用 new 关键字构造是公认的良好习惯。

例如 :
require_once  'Zend_Component_SpecificException.php' ;

class 
Zend_Component

{

    public function 
foo ( $condition )

    {

        if (
$condition ) {

            throw new 
Zend_Component_SpecificException (

                
'一些友好的信息' );

        }

    }

}


复制代码
4. 异常必须延迟加载。

例如 :
// 正确

if ( $condition ) {

    require_once 
'Zend_Component_SpecificException.php' ;

    throw new 
Zend_Component_SpecificException (

        
'一些友好信息' );

} else {

    
// ...

}



// 错误

require_once  'Zend_Component_SpecificException.php' ;

if (
$condition ) {

    throw new 
Zend_Component_SpecificException (

        
'一些友好信息' );

} else {

    
// ...

}

复制代码
5. 通俗地讲,如果用户希望 Zend Framework 模块做出一些超出其能力范围的工作时,那么抛出异常则是明智而正确的选择。相反,假如该模块能够处理用户的需求,但用户却给出各种意想不到的输入,这个时候,模块就不应该抛出异常,而应该正常运行下去。

例如 :
if ( $canNotPerformThisAction ) {

    require_once 
'Zend/Exception.php' ;

    throw new 
Zend_Exception ( '不能执行此动作 !' );

}



$foo  'bar' ;

if (
$foo  ==  'foo' ) {

    echo 
'对的' ;

} else {

    
// 没必要抛出异常

}

复制代码
6. 避免抛出 Exception 基类异常,而应该尽量使用派生异常类,这可以让人清楚知道问题所在。

例如 :
class  Zend_Db

{

    public static function 
factory ( $adapter $config  = array())

    {

        if (!
is_array ( $config )) {

            throw new 
Exception ( '我们根本不知问题发生在哪儿。' );

        }

        if (!
is_array ( $config )) {

            require_once 
'Zend/Db/Exception.php' ;

            throw new 
Zend_Db_Exception ( "我们都知道问题出在 Zend_Db 这儿。" );

        }

    }

}


复制代码
7. 尽量避免去捕捉 Exception 基类异常。如果在 try 语句里面可能抛出多种异常的话,那么我们应该为各种异常准备各自独立的 catch 块,而不是仅用一个 catch 块去捕捉 Exception 基类异常。

例如 :
// index.php

try {

    
$app -> run ();

} catch (
Zend_Db_Exception $e ) {

    die(
'数据库异常 !' );

} catch (
Zend_Acl_Exception $e ) {

    die(
'权限分配异常 !' );

} catch (
Zend_Auth_Exception $e ) {

    die(
'身份认证异常 !' );

} catch (
Zend_Exception $e ) {

    
// 所有其它异常

}

复制代码
8. 我们通常需要在类中通过拓展多个异常类来区分各种不同的情况。例如,我们需要创建两个异常类来区分 "参数错误" 和 "用户缺乏权限" 两种情况。

例如 :
class  Zend_Db_Exception  extends  Zend_Exception

{

    
// 数据库异常基类

}



class 
Zend_Db_Select_Exception  extends  Zend_Db_Exception

{

    
// 用于处理 select 类异常

}



class 
Zend_Db_Table_Exception  extends  Zend_Db_Exception

{

    
// 用于处理数据库表的异常

}

复制代码
9. 不要把所有诊断信息都放在异常的 message 里,我们可以在任何需要的时候创建自己的异常类的成员和方法,来为 catch 语句提供帮助。我们需要做的就是在 constructor 构建异常类时,传入正确的参数信息。

例如 :
class  Zend_Exception  extends  Exception

{

}



class 
My_Exception  extends  Zend_Exception

{

    private 
$_importantDiagnostic ;

    public function 
setImportantDiagnostic ( $value )

    {

        
$this -> _importantDiagnostic  $value ;

    }

    public function 
getImportantDiagnostic ()

    {

        return 
$this -> _importantDiagnostic ;

    }

    public function 
__construct ( $message  null $code  0 $value )

    {

        
parent :: __construct ( $message $code );

        
$this -> setImportantDiagnostic ( $value );

    }

}



try {

    if (
$isMyFault ) {

        throw new 
My_Exception ( '没有信息' 0 '信息在这儿' );

    }

} catch (
My_Exception $e ) {

    echo 
$e -> getImportantDiagnostic ();

}


复制代码
10. 在错误发生的时候,程序不应该保持沉默,甚至对异常置之不理。而是应该要么修正它,要么抛出新的异常来代替它。

例如 :
try {

} catch (
My_Exception $e ) {

    
tryToCorrectIt ( $e );

} catch (
My_Exception $e ) {

    throw new 
My_Exception ( $e -> getMessage (),  '110' );

} catch (
My_Exception $e ) {

    
// 不作为是愚蠢的行为!

}

复制代码
11. 我们应该为我们程序的不同层面准备不同的异常处理。例如,我们不应该把数据逻辑层的错误(即俗称 SQLException)搬到业务逻辑层。

例如 :
class  My_Dao_User_Exception  extends  Zend_Db_Table_Exception

{

    
// 数据层 User 异常类

}



class 
My_Dao_User  extends  Zend_Db_Table_Abstract

{

    
// 数据层 User 对象

}



class 
My_Bis_User_Exception  extends  Zend_Exception

{

    
// 业务层 User 异常类

}



/**

 * 业务层 User 对象

 */

class  My_Bis_User

{

    private 
$_daoUser  null ;



    public function 
setDaoUser ( $user )

    {

        
$this -> _daoUser  $user ;

    }



    public function 
getDaoUser ()

    {

        return 
$this -> _daoUser ;

    }



    public function 
throwSomething ()

    {

        try {

            if (
$wrong ) {

                throw new 
My_Dao_User_Exception ( '你不应该把数据层的异常搬到这里!' );

            } else if (
$right ) {

                throw new 
My_Bis_User_Exception ( '这才是正确的。' );

            }

        } catch (
Zend_Exception $e ) {

            
// ...

        
}

    }

}


复制代码
12. 不要把异常处理机制当成控制流程,或者仅仅是返回某些值。

例如 :
function  itIsWrong ()

{

    try {

        
// 做些小动作

    
} catch ( Exception_One $e ) {

        
doSomething ( $e );

    } catch (
Exception_Two $e ) {

        
doSomething ( $e );

    } catch (
Exception_Three $e ) {

        return 
true ;

    }

}



function 
isRight ()

{

    try {

        
// 做些小动作

    
} catch ( Exception_One $e ) {

        
correctIt ( $e );

    } catch (
Exception_Two $e ) {

        
correctIt ( $e );

    } catch (
Exception_Three $e ) {

        
// 从不 return;

        
throw new  Exception ( '我们抛出它,而不是返回什么东西!' );

    }

}


复制代码
13. 在用 catch 语句块处理异常的时候,我们应该首先释放多余的内存资源,如数据库连接,网络资源连接等。Php 并不提供类似 finally 之类的语句来进行垃圾处理。

例如 :
try {

    
$db  getDbConnection ();

    throw new 
Exception ( '发生了错误。' );

} catch (
Exception $e ) {

    unset(
$db );

    
handleExceptionAndGoOn ( $e );

}


复制代码
14. 当然,其它语言的关于异常处理的规范也是可以借鉴的。当中有很多东西都是相通而不存在语言界限的。

你可能感兴趣的:(PHP)