НаслСдованиС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ

ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ класс ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ ΠΏΡƒΡ‚Ρ‘ΠΌ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ встроСнного класса 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(); // Массив Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ backtrace()
final public function getPrevious(); // ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅
final public function getTraceAsString(); // ΠžΡ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Π°Ρ строка трассировки

// ΠŸΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌΡ‹ΠΉ
public function __toString(); // ΠžΡ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Π°Ρ строка для отобраТСния
}

Π’ конструкторС класса-наслСдника Π½ΡƒΠΆΠ½ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ конструктор Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ класса β€” parent::__construct(), ΠΊΠΎΠ³Π΄Π° класс Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ класс Exception ΠΈ пСрСопрСдСляСт конструктор, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ класс ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ присвоил значСния доступным Π΄Π°Π½Π½Ρ‹ΠΌ. ΠœΠ΅Ρ‚ΠΎΠ΄ __toString() допустимо ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Ρ‹Π²ΠΎΠ΄, ΠΊΠΎΠ³Π΄Π° с ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΊΠ°ΠΊ со строкой.

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅:

Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ нСльзя ΠΊΠ»ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. ΠŸΠΎΠΏΡ‹Ρ‚ΠΊΠ° ΠΊΠ»ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Ρ‚ ΠΊ Ρ„Π°Ρ‚Π°Π»ΡŒΠ½ΠΎΠΉ ошибкС E_ERROR.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #2 НаслСдованиС класса Exception

<?php

/**
* ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ класс ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
*/
class MyException extends Exception
{
// ΠŸΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ message станСт ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ
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:
// Π‘Π΅Π· ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ, PHP создаст ΠΎΠ±ΡŠΠ΅ΠΊΡ‚
$this->var = $avalue;
break;
}
}
}

echo
"# ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 1\n";
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
MyException $e) { // ΠŸΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΡ‚ΡΡ
echo "Π‘Π»ΠΎΠΊ catch ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΠ» ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ΅ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅\n", $e;
$e->customFunction();
} catch (
Exception $e) { // ΠŸΡ€ΠΎΠΏΡƒΡΠΊΠ°Π΅Ρ‚ΡΡ
echo "Поймано встроСнноС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅\n", $e;
}

// ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅
var_dump($o); // Null


echo "\n\n# ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 2\n";
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (
MyException $e) { // Π’ΠΈΠΏ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Π½Π΅ совпадёт
echo "Π‘Π»ΠΎΠΊ catch ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΠ» ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ΅ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅\n", $e;
$e->customFunction();
} catch (
Exception $e) { // ΠŸΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΡ‚ΡΡ
echo "Π‘Π»ΠΎΠΊ catch ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΠ» встроСнноС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅\n", $e;
}

// ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅
var_dump($o); // Null


echo "\n\n# ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 3\n";
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
Exception $e) { // ΠŸΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΡ‚ΡΡ
echo "Π‘Π»ΠΎΠΊ catch ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΠ» встроСнноС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅\n", $e;
}

// ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅
var_dump($o); // Null


echo "\n\n# ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 4\n";
try {
$o = new TestException();
} catch (
Exception $e) { // ΠŸΡ€ΠΎΠΏΡƒΡΠΊΠ°Π΅Ρ‚ΡΡ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π½Π΅ выбрасываСтся
echo "Π‘Π»ΠΎΠΊ catch ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΠ» встроСнноС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅\n", $e;
}

// ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅
var_dump($o); // TestException
οΌ‹Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ 5 notes

up
15
iamhiddensomewhere at gmail dot com ΒΆ
16 years ago
As previously noted exception linking was recently added (and what a god-send it is, it certainly makes layer abstraction (and, by association, exception tracking) easier).

Since <5.3 was lacking this useful feature I took some initiative and creating a custom exception class that all of my exceptions inherit from:

<?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;
    }
}

?>

Hope you find it useful.
up
8
Hayley Watson ΒΆ
7 years ago
Check the other SPL Exception classes and extend one of those if your intended exception is a subclass of one of those. This allows more finesse when catching.
up
4
sapphirepaw.org ΒΆ
16 years ago
Support for exception linking was added in PHP 5.3.0. The getPrevious() method and the $previous argument to the constructor are not available on any built-in exceptions in older versions of PHP.
up
4
michaelrfairhurst at gmail dot com ΒΆ
13 years ago
Custom exception classes can allow you to write tests that prove your exceptions
are meaningful. Usually testing exceptions, you either assert the message equals
something in which case you can't change the message format without refactoring,
or not make any assertions at all in which case you can get misleading messages
later down the line. Especially if your $e->getMessage is something complicated
like a var_dump'ed context array.

The solution is to abstract the error information from the Exception class into
properties that can be tested everywhere except the one test for your formatting.

<?php

class TestableException extends Exception {

        private $property;

        function __construct($property) {

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

        }

        function format($property) {
                return "I have formatted: " . $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')
        );
}

?>
up
1
Dor ΒΆ
14 years ago
It's important to note that subclasses of the Exception class will be caught by the default Exception handler

<?php
    
    /**
     * NewException
     * Extends the Exception class so that the $message parameter is now mendatory.
     * 
     */
    class NewException extends Exception {
        //$message is now not optional, just for the extension.
        public function __construct($message, $code = 0, Exception $previous = null) {
            parent::__construct($message, $code, $previous);
        }
    }
    
    /**
     * TestException
     * Tests and throws Exceptions.
     */
    class TestException {
        const NONE = 0;
        const NORMAL = 1;
        const CUSTOM = 2;
        public function __construct($type = self::NONE) {
            switch ($type) {
                case 1: 
                    throw new Exception('Normal Exception');
                    break;
                case 2:
                    throw new NewException('Custom Exception');
                    break;
                default:
                    return 0; //No exception is thrown.
            }
        }
    }
    
    try {
        $t = new TestException(TestException::CUSTOM);
    }
    catch (Exception $e) {
        print_r($e); //Exception Caught
    }
    
?>

Note that if an Exception is caught once, it won't be caught again (even for a more specific handler).