175 lines
5.2 KiB
PHP
175 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace KTXF\Exception;
|
|
|
|
use Throwable;
|
|
|
|
/**
|
|
* Exception is the base class for
|
|
* all Exceptions.
|
|
* @link https://php.net/manual/en/class.exception.php
|
|
*/
|
|
class BaseException implements Throwable
|
|
{
|
|
/** The error message */
|
|
protected string $message = '';
|
|
|
|
/** The error code */
|
|
protected int $code = 0;
|
|
|
|
/** The filename where the error happened */
|
|
protected string $file = '';
|
|
|
|
/** The line where the error happened */
|
|
protected int $line = 0;
|
|
|
|
/** Previous throwable in chain */
|
|
protected ?Throwable $previous = null;
|
|
|
|
/** Captured stack trace frames (excluding constructor frame) */
|
|
protected array $trace = [];
|
|
|
|
/**
|
|
* Construct the exception. Note: The message is NOT binary safe.
|
|
* @link https://php.net/manual/en/exception.construct.php
|
|
* @param string $message [optional] The Exception message to throw.
|
|
* @param int $code [optional] The Exception code.
|
|
* @param null|Throwable $previous [optional] The previous throwable used for the exception chaining.
|
|
*/
|
|
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
|
{
|
|
$this->message = $message;
|
|
$this->code = $code;
|
|
$this->previous = $previous;
|
|
|
|
// Capture backtrace; first element is this constructor call site
|
|
$bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
|
if (!empty($bt)) {
|
|
$first = $bt[0];
|
|
$this->file = $first['file'] ?? 'unknown';
|
|
$this->line = $first['line'] ?? 0;
|
|
}
|
|
// Exclude current frame for readability
|
|
$this->trace = array_slice($bt, 1);
|
|
}
|
|
|
|
/**
|
|
* Clone the exception
|
|
* Tries to clone the Exception, which results in Fatal error.
|
|
* @link https://php.net/manual/en/exception.clone.php
|
|
* @return void
|
|
*/
|
|
public function __clone(): void
|
|
{
|
|
// Mimic internal Exception behavior: cloning not allowed.
|
|
trigger_error('Trying to clone an uncloneable object of class ' . static::class, E_USER_ERROR);
|
|
}
|
|
|
|
/**
|
|
* String representation of the exception
|
|
* @link https://php.net/manual/en/exception.tostring.php
|
|
* @return string the string representation of the exception.
|
|
*/
|
|
public function __toString(): string
|
|
{
|
|
return sprintf(
|
|
"%s: %s in %s:%d\nStack trace:\n%s",
|
|
static::class,
|
|
$this->getMessage(),
|
|
$this->getFile(),
|
|
$this->getLine(),
|
|
$this->getTraceAsString()
|
|
);
|
|
}
|
|
|
|
public function __wakeup(): void
|
|
{
|
|
// On wakeup we don't have original trace; reset trace to empty
|
|
$this->trace = [];
|
|
}
|
|
|
|
/**
|
|
* Gets the Exception message
|
|
* @link https://php.net/manual/en/exception.getmessage.php
|
|
* @return string the Exception message as a string.
|
|
*/
|
|
final public function getMessage(): string
|
|
{
|
|
return $this->message;
|
|
}
|
|
|
|
/**
|
|
* Gets the Exception code
|
|
* @link https://php.net/manual/en/exception.getcode.php
|
|
* @return mixed|int the exception code as integer in
|
|
* <b>Exception</b> but possibly as other type in
|
|
* <b>Exception</b> descendants (for example as
|
|
* string in <b>PDOException</b>).
|
|
*/
|
|
final public function getCode(): int
|
|
{
|
|
return $this->code;
|
|
}
|
|
|
|
/**
|
|
* Gets the file in which the exception occurred
|
|
* @link https://php.net/manual/en/exception.getfile.php
|
|
* @return string the filename in which the exception was created.
|
|
*/
|
|
final public function getFile(): string
|
|
{
|
|
return $this->file;
|
|
}
|
|
|
|
/**
|
|
* Gets the line in which the exception occurred
|
|
* @link https://php.net/manual/en/exception.getline.php
|
|
* @return int the line number where the exception was created.
|
|
*/
|
|
final public function getLine(): int
|
|
{
|
|
return $this->line;
|
|
}
|
|
|
|
/**
|
|
* Gets the stack trace
|
|
* @link https://php.net/manual/en/exception.gettrace.php
|
|
* @return array the Exception stack trace as an array.
|
|
*/
|
|
final public function getTrace(): array
|
|
{
|
|
return $this->trace;
|
|
}
|
|
|
|
/**
|
|
* Returns previous Exception
|
|
* @link https://php.net/manual/en/exception.getprevious.php
|
|
* @return null|Throwable Returns the previous {@see Throwable} if available, or <b>NULL</b> otherwise.
|
|
* or null otherwise.
|
|
*/
|
|
final public function getPrevious(): ?Throwable
|
|
{
|
|
return $this->previous;
|
|
}
|
|
|
|
/**
|
|
* Gets the stack trace as a string
|
|
* @link https://php.net/manual/en/exception.gettraceasstring.php
|
|
* @return string the Exception stack trace as a string.
|
|
*/
|
|
final public function getTraceAsString(): string
|
|
{
|
|
$lines = [];
|
|
foreach ($this->trace as $i => $frame) {
|
|
$file = $frame['file'] ?? '[internal function]';
|
|
$line = $frame['line'] ?? 0;
|
|
$func = $frame['function'] ?? '';
|
|
$class = $frame['class'] ?? '';
|
|
$type = $frame['type'] ?? '';
|
|
$lines[] = sprintf('#%d %s(%s): %s%s%s()', $i, $file, $line, $class, $type, $func);
|
|
}
|
|
$lines[] = sprintf('#%d {main}', count($lines));
|
|
return implode("\n", $lines);
|
|
}
|
|
|
|
} |