'Invalid error code', 101 => 'Unknown error; escaping', 102 => 'Incorrect number of parameters for Exception message; %s expected', 103 => 'Unreachable code', 201 => 'Property %s does not exist', 202 => 'Cannot write readonly property %s', 203 => 'Argument #%s ($%s) must be of type %s, %s given', 204 => 'Call to undefined method %s::%s()', 205 => 'Function should return type %s, %s given' ]; public function __construct(int $code, ...$args) { if (!isset(self::$messages[$code])) { throw new Exception(Exception::INVALID_CODE); } $message = self::$messages[$code]; $previous = null; // @codeCoverageIgnoreStart if ($args) { // Grab a previous exception if there is one. if ($args[0] instanceof \Throwable) { $previous = array_shift($args); } elseif (end($args) instanceof \Throwable) { $previous = array_pop($args); } } // @codeCoverageIgnoreEnd // Count the number of replacements needed in the message. preg_match_all('/(\%(?:\d+\$)?s)/', $message, $matches); $count = count($matches[1]); // If the number of replacements don't match the arguments then oops. if (count($args) !== $count) { throw new Exception(Exception::INCORRECT_PARAMETERS_FOR_MESSAGE, $count); } if ($count > 0) { // Go through each of the arguments and run sprintf on the strings. $message = call_user_func_array('sprintf', array_merge([$message], $args)); } parent::__construct($message, $code, $previous); } }