Skip to content
Snippets Groups Projects
Commit 3343ecf9 authored by Jan Kuchař's avatar Jan Kuchař
Browse files

assertion errors are now errors not exceptions

parent 6520cf00
No related branches found
No related tags found
No related merge requests found
......@@ -3,35 +3,54 @@ namespace Grifart\AssertFunction;
use Throwable;
final class AssertFunctionException extends \LogicException {
final class AssertFunctionError extends \AssertionError {
const PATH_DEPTH = 3;
/** @internal use named constructors instead */
public function __construct($message, \Throwable $previous = NULL)
public function __construct(\ReflectionFunction $reflection, string $message, \Throwable $previous = NULL)
{
parent::__construct($message, 0, $previous);
parent::__construct(
self::location($reflection) . ' ' . $message,
0,
$previous
);
}
private static function location(\ReflectionFunction $reflection): string
{
return $reflection->getFileName() . ':' . $reflection->getStartLine() . '-' . $reflection->getEndLine() . ' ';
$startLine = (string) $reflection->getStartLine();
$endLine = (string) $reflection->getEndLine();
$linePosition = ($startLine === $endLine) ? $startLine
: ($startLine . '-' . $endLine);
return self::shortenPath($reflection->getFileName()) . ':' . $linePosition;
}
public static function cannotStartReflection(\ReflectionException $exception): self
public static function wrongNumberOrArguments(\ReflectionFunction $reflection, int $numberOfParameters, int $actualCount): self
{
return new self('Cannot start reflection for given function.', 0, $exception);
return new self($reflection, "Given wrong number of parameters. Expected $numberOfParameters, $actualCount given.");
}
public static function wrongNumberOrArguments(\ReflectionFunction $reflection, int $numberOfParameters, int $actualCount): self
public static function missingReturnType(\ReflectionFunction $reflection, string $type): self
{
return new self(self::location($reflection) . "Given wrong number of parameters. Expected $numberOfParameters, $actualCount given.");
return new self($reflection, "Function is required to have return type of type $type.");
}
public static function missingReturnType(\ReflectionFunction $reflection, string $type): self
private static function shortenPath(string $path): string
{
return new self(self::location($reflection) . "Function is required to have return type of type $type.");
$pathArr = explode(DIRECTORY_SEPARATOR, $path);
$pathNumParts = count($pathArr);
$pathParts = array_filter($pathArr, function ($val, $idx) use ($pathNumParts) { // only last x parts
return $idx >= $pathNumParts - self::PATH_DEPTH;
}, ARRAY_FILTER_USE_BOTH);
return implode('/', $pathParts); // normalized shortened readable path
}
};
......
......@@ -5,7 +5,7 @@
// todo: use only assert( ... ) instead of exceptions; to be compatible without configuration with PHP env
// todo: [performance] separate code itself into autoloaded class
// todo: better assertion messages
// todo: better assertion messages + throw AssertFunctionError
// todo: covariance and contra-variance
namespace Grifart\AssertFunction;
......@@ -22,18 +22,21 @@ function optional(string $classType): string
function assertFunction(callable $function, array $parameters, ?string $expectedReturnType): void
{
try {
$reflection = new \ReflectionFunction($function);
} catch (\ReflectionException $exception) {
throw AssertFunctionException::cannotStartReflection($exception);
}
// todo: call assert(__impl());
$reflection = new \ReflectionFunction($function);
// PARAMETERS CHECK:
// NUMBER PARAMETERS CHECK:
$numberOfParameters = $reflection->getNumberOfParameters();
assert(
$numberOfParameters === count($parameters),
AssertFunctionError::wrongNumberOrArguments($reflection, count($parameters), $numberOfParameters)
);
if ($numberOfParameters !== count($parameters)) {
throw AssertFunctionException::wrongNumberOrArguments($reflection, count($parameters), $numberOfParameters);
return;
}
// PARAMETER TYPES CHECK:
$i = 0;
/** @var string[] $parameters */
foreach($parameters AS $parameter) {
......@@ -48,26 +51,28 @@ function assertFunction(callable $function, array $parameters, ?string $expected
// RETURN TYPE:
if($expectedReturnType !== NULL) {
assert(
$reflection->hasReturnType(),
AssertFunctionError::missingReturnType($reflection, $expectedReturnType)
);
if (!$reflection->hasReturnType()) {
throw AssertFunctionException::missingReturnType($reflection, $expectedReturnType);
}
if ($reflection->hasReturnType()) {
list($_returnType, $_optional) = __parseType($expectedReturnType);
$returnTypeReflection = $reflection->getReturnType();
list($_returnType, $_optional) = __parseType($expectedReturnType);
$returnTypeReflection = $reflection->getReturnType();
assert($_optional === $returnTypeReflection->allowsNull());
assert($_returnType === (string) $reflection->getReturnType());
assert($_optional === $returnTypeReflection->allowsNull());
assert($_returnType === (string) $reflection->getReturnType());
}
}
}
function __parseType(string $type): array
{
$cleanType = $type;
$cleanType = $type; // e.g. ?Namespace\Class
$optional = FALSE;
if ($type[0] === '?') {
$optional = TRUE;
$cleanType = substr($type, 1); // without leading ?
$cleanType = substr($type, 1); // without leading '?'
}
return [$cleanType, $optional];
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment