线路的例外

例外 配置有抛出的文件和行。这是经典情况:立即抛出异常在检测到问题的地方。 

<?php

if (storeInDatabase($values) === NOT_STORED) {
    throw new StorageFailedException('Could not store in the database');
}

?>

错误的行

在代码中抛出异常并不总是方便。特别是,当添加新的代码层以处理常用操作时。毕竟,这是函数和课程所在。

<?php

if (validateData($values)) {
    storeInDatabase($values);
}

function validateData($values) {
    if (validateValues($values) === MISSING_ID) {
        throw new \Exception('Id is missing id for '.$values->name);
    }

    if (validateValues($values) === MISSING_NAME) {
        throw new \Exception('Id is missing name for '.$values->id);
    }
    ...
}

?>

这里,验证将导出到单独的函数,以避免重复(并忘记)各种例外。这种情况的一个显着缺点是validateata()现在集中了所有例外。每个检测到的异常都从此特定的功能抛出。

Fatal error: Uncaught Exception: Id is missing id for Smith in /tmp/test.php:9
Stack trace:
#0 /tmp/test.php(3): validateData(...)
#1 {main}
  thrown in /tmp/test.php on line 9

留言

解决此问题的解决方案:创建自定义异常。例外和所有本国树,是基本例外的好来源。大多数时候,它们都使用新消息进行自定义: 

<?php

class myException extends \Exception {
    function __construct($message) {
        parent::__construct($message);
    }
}

?>

然而,异常类包括大量属性,包括文件和行号。 

<?php
class Exception extends Throwable
{
    protected $message = 'Unknown exception';   // exception message
    private   $string;                          // __toString cache
    protected $code = 0;                        // user defined exception code
    protected $file;                            // source filename of exception
    protected $line;                            // source line of exception
    private   $trace;                           // backtrace
    private   $previous;                        // previous exception if nested exception

    public function __construct($message = null, $code = 0, Exception $previous = null);


?>

这样,异常可以在代码中设计另一个位置,而不是抛出异常的地方: 

<?php

class myException extends \Exception {
    function __construct($message) {
        parent::__construct($message);
        
        $this->file = "myfile.php";
        $this->line = 1000;
    }
}

?>

结果如下所示: 

Fatal error: Uncaught Exception: Id is missing id for Smith in myfile.php:1000
Stack trace:
#0 /tmp/test.php(3): validateData(...)
#1 {main}
  thrown in /tmp/test.php on line 9

正确的地方正确的例外

您可能会注意到我们只使用硬编码值更改了文件和行号。这不是真正的帮助,因为它没有’t指定任何实际代码。使用 魔术常数 __FILE__和 __LINE__ 导致同样的问题:它指定当前代码,而不是调用代码。

调用代码及其前辈们可以调用debug_backtrace()。此本机函数构建导致当前执行的调用堆栈。它返回一系列数组:每个数组包含文件,行,函数或方法,类和呼叫类型。 

这是阵列,何时 调试_backtrace() is called with the DEBUG_BACKTRACE_IGNORE_ARGS.

Array
(
    [0] => Array
        (
            [file] => /tmp/test.php
            [line] => 9
            [function] => __construct
            [class] => myException
            [type] => ->
        )

    [1] => Array
        (
            [file] => /tmp/test.php
            [line] => 3
            [function] => validateData
        )

)

我们现在可以访问文件和行我们’d like to display : 

<?php

class myException extends \Exception {
    function __construct($message) {
        parent::__construct($message);
        
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        $this->file = $trace[1]['file'];
        $this->line = $trace[1]['line'];
    }
}

?>

生成的默认错误消息现在指向有用的坐标。它可能是个性化的进一步 __tostring() or a GetMessage() 在尝试/捕获中致电。

Fatal error: Uncaught Exception: Id is missing id for Smith in /tmp/test.php:3
Stack trace:
#0 /tmp/test.php(3): validateData(...)
#1 {main}
  thrown in /tmp/test.php on line 9

包起来

可以超出简单消息配置异常:可以自定义文件和行号,并在异常与Echo一起使用时显示的消息。这比默认行为更方便。 

大学教师’t forget to 链例外 :始终将以前的例外中继到新创建的一个例外,以便最后一个接收者可用整个例外链。