PHP 日本大会 2024

扩展异常

可以通过扩展内置的 Exception 类来定义用户自定义的异常类。下面的成员和属性显示了从内置 Exception 类派生的子类中可访问的内容。

示例 #1 内置 Exception 类

<?php
class Exception implements Throwable
{
protected
$message = 'Unknown exception'; // 异常消息
private $string; // __toString 缓存
protected $code = 0; // 用户定义的异常代码
protected $file; // 异常的源文件名
protected $line; // 异常的源行号
private $trace; // 回溯
private $previous; // 如果是嵌套异常,则为之前的异常

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

final private function
__clone(); // 禁止克隆异常。

final public function getMessage(); // 异常的消息
final public function getCode(); // 异常的代码
final public function getFile(); // 源文件名
final public function getLine(); // 源行号
final public function getTrace(); // 回溯数组
final public function getPrevious(); // 之前的异常
final public function getTraceAsString(); // 格式化的回溯字符串

// 可重写
public function __toString(); // 用于显示的格式化字符串
?>

如果一个类扩展了内置的 Exception 类并重新定义了构造函数,强烈建议它也调用parent::__construct()以确保所有可用数据都已正确赋值。__toString()方法可以被重写以在对象作为字符串显示时提供自定义输出。

注意:

异常不能被克隆。尝试克隆一个异常将导致致命的E_ERROR错误。

示例 #2 扩展 Exception 类

<?php
/**
* 定义一个自定义异常类
*/
class MyException extends Exception
{
// 重新定义异常,使消息不再可选
public function __construct($message, $code = 0, Throwable $previous = null) {
// 部分代码

// 确保所有内容都正确赋值
parent::__construct($message, $code, $previous);
}

// 对象的自定义字符串表示
public function __toString() {
return
__CLASS__ . ": [{$this->code}]: {$this->message}\n";
}

public function
customFunction() {
echo
"此类型异常的自定义函数\n";
}
}


/**
* 创建一个类来测试异常
*/
class TestException
{
public
$var;

const
THROW_NONE = 0;
const
THROW_CUSTOM = 1;
const
THROW_DEFAULT = 2;

function
__construct($avalue = self::THROW_NONE) {

switch (
$avalue) {
case
self::THROW_CUSTOM:
// 抛出自定义异常
throw new MyException('1 是无效参数', 5);
break;

case
self::THROW_DEFAULT:
// 抛出默认异常
throw new Exception('2 不允许作为参数', 6);
break;

default:
// 没有异常,对象将被创建
$this->var = $avalue;
break;
}
}
}


// 示例 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
MyException $e) { // 将被捕获
echo "捕获到我的异常\n", $e;
$e->customFunction();
} catch (
Exception $e) { // 跳过
echo "捕获到默认异常\n", $e;
}

// 继续执行
var_dump($o); // Null
echo "\n\n";


// 示例 2
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (
MyException $e) { // 不匹配此类型
echo "捕获到我的异常\n", $e;
$e->customFunction();
} catch (
Exception $e) { // 将被捕获
echo "捕获到默认异常\n", $e;
}

// 继续执行
var_dump($o); // Null
echo "\n\n";


// 示例 3
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
Exception $e) { // 将被捕获
echo "捕获到默认异常\n", $e;
}

// 继续执行
var_dump($o); // Null
echo "\n\n";


// 示例 4
try {
$o = new TestException();
} catch (
Exception $e) { // 跳过,没有异常
echo "捕获到默认异常\n", $e;
}

// 继续执行
var_dump($o); // TestException
echo "\n\n";
?>
添加注释

用户贡献的注释 6 条注释

iamhiddensomewhere at gmail dot com
14 年前
如前所述,异常链接最近已添加(这是一个多么好的功能,它确实使层抽象(以及相关的异常跟踪)更容易)。

由于<5.3 缺少此有用功能,因此我采取了一些主动措施并创建了一个自定义异常类,我的所有异常都继承自该类

<?php

class SystemException extends Exception
{
private
$previous;

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

if (!
is_null($previous))
{
$this -> previous = $previous;
}
}

public function
getPrevious()
{
return
$this -> previous;
}
}

?>

希望您觉得有用。
Hayley Watson
5年前
检查其他 SPL 异常类,如果您的预期异常是这些异常类中的一个的子类,则扩展其中一个。这允许在捕获时进行更精细的处理。
michaelrfairhurst at gmail dot com
12 年前
自定义异常类允许您编写测试来证明您的异常
是有意义的。通常测试异常时,您要么断言消息等于
某些内容,在这种情况下,您无法更改消息格式而无需重构,
或者根本不进行任何断言,在这种情况下,你可能会得到误导性的消息。
以后可能会出现问题。尤其是在你的 `$e->getMessage` 很复杂的情况下
例如,一个 `var_dump` 输出的上下文数组。

解决方案是将错误信息从 Exception 类抽象到
可以在任何地方测试的属性中,除了用于格式化的那一个测试。

<?php

class TestableException extends Exception {

private
$property;

function
__construct($property) {

$this->property = $property;
parent::__construct($this->format($property));

}

function
format($property) {
return
"我已经格式化: " . $property . "!!";
}

function
getProperty() {
return
$this->property;
}

}

function
testSomethingThrowsTestableException() {
try {
throw new
TestableException('Property');
} Catch (
TestableException $e) {
$this->assertEquals('Property', $e->getProperty());
}
}

function
testExceptionFormattingOnlyOnce() {
$e = new TestableException;
$this->assertEquals('I have formatted: properly for the only required test!!',
$e->format('properly for the only required test')
);
}

?>
sapphirepaw.org
15年前
PHP 5.3.0 中添加了对异常链接的支持。`getPrevious()` 方法和构造函数中的 `$previous` 参数在旧版本的 PHP 中的任何内置异常中都不可用。
Dor
13年前
需要注意的是,Exception 类的子类将被默认的 Exception 处理程序捕获。

<?php

/**
* NewException
* 扩展 Exception 类,使 $message 参数现在是必须的。
*
*/
class NewException extends Exception {
//$message 现在不是可选的,只是为了扩展。
public function __construct($message, $code = 0, Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
}

/**
* TestException
* 测试并抛出异常。
*/
class TestException {
const
NONE = 0;
const
NORMAL = 1;
const
CUSTOM = 2;
public function
__construct($type = self::NONE) {
switch (
$type) {
case
1:
throw new
Exception('普通异常');
break;
case
2:
throw new
NewException('自定义异常');
break;
default:
return
0; //不抛出异常。
}
}
}

try {
$t = new TestException(TestException::CUSTOM);
}
catch (
Exception $e) {
print_r($e); //捕获异常
}

?>

请注意,如果一个异常被捕获一次,它将不会再次被捕获(即使是更具体的处理程序)。
shaman_master at list dot ru
9年前
使用此示例处理非数字代码
<code>
<?php
class MyException extends Exception
{
/**
* 创建一个新的异常。
*
* @param string $message 错误消息
* @param mixed $code 异常代码
* @param Exception $previous 前一个异常
* @return void
*/
public function __construct($message = '', $code = 0, Exception $previous = null)
{
// 将消息和整数代码传递给父类
parent::__construct((string)$message, (int)$code, $previous);

// @link http://bugs.php.net/39615 保存未修改的代码
$this->code = $code;
}
}
</
code>
To Top