This small project aims to provide improved user/developer experience for PHP developers working with native PHP exceptions (thrown by the PHP interpreter itself in various situations).
Better PHP Exceptions can be created from native exceptions via unified interface:
use \Smuuf\BetterExceptions\BetterException;
try {
...
} catch (\Throwable $ex) {
$better = BetterException::from($ex);
...
}
As an example scenario, both PHP 7.*
and PHP 8.0
throw TypeError
exceptions in three distinct scenarios:
There are three scenarios where a TypeError may be thrown. The first is where the argument type being passed to a function does not match its corresponding declared parameter type. The second is where a value being returned from a function does not match the declared function return type. The third is where an invalid number of arguments are passed to a built-in PHP function (strict mode only).
~ https://www.php.net/manual/en/class.typeerror.php
Sadly, PHP or the TypeError
itself does not provide any additional information about the types expected, types passed/returned, or at which position the passed wrong type was present during invocation.
Was it an argument type error? A return type error? What was it...!?
This information is present only in the exception message and it takes an extra parsing effort to get it. Not to mention the fact that the format of these messages changed from PHP 7
to PHP 8
and thus need different parsing rules...
This is where Better PHP Exceptions come in.
<?php
declare(strict_types=1);
include __DIR__ . '/vendor/autoload.php';
use \Smuuf\BetterExceptions\BetterException;
// Yes, it has a wrong return type.
function join_strings(string $a, ?string $b): ?int {
return "{$a} - {$b}";
}
try {
// Argument type error.
join_strings('first', 123);
} catch (\TypeError $ex) {
// Convert the generic TypeError to something more usable.
$better = BetterException::from($ex);
// Now we know that it was an argument type error.
var_dump($better);
// object(Smuuf\BetterExceptions\Types\ArgumentTypeError) ...
// We know that 'string' or 'null' was expected.
var_dump($better->getExpected());
// array(2) {
// [0]=>
// string(6) "string"
// [1]=>
// string(4) "null"
// }
// We know that 'int' was actually passed.
var_dump($better->getActual());
// string(3) "int"
// And it was the second argument that was wrong.
var_dump($better->getArgumentIndex());
// int(2)
}
try {
// Return type error.
join_strings('first', 'second');
} catch (\TypeError $ex) {
// Convert the generic TypeError to something more usable.
$better = BetterException::from($ex);
// Now we know that it was a return type error.
var_dump($better);
// object(Smuuf\BetterExceptions\Types\ReturnTypeError) ...
// We know that 'int' or 'null' was expected.
var_dump($better->getExpected());
// array(2) {
// [0]=>
// string(3) "int"
// [1]=>
// string(4) "null"
// }
// We know that 'string' was actually passed.
var_dump($better->getActual());
// string(6) "string"
}
Even though PHP 8.0
was released near the end of 2020, PHP 7 is still used extensively and Better PHP Exceptions aim to provide better exceptions for both current major PHP versions (at least for now).
Currently only a handful (in the beginning it was just a single one, since I needed that for my other project: Primi language: A scripting language written in PHP
). But the system is built to support easy addition of more better exceptions.
-
\TypeError
can be converted into:\Smuuf\BetterExceptions\Types\ArgumentTypeError
- Provides methods:
getExpected()
: Returns a list of strings of expected argument types.getActual()
: Returns actual argument type as string.
- Provides methods:
\Smuuf\BetterExceptions\Types\ReturnTypeError
- Same as
\Smuuf\BetterExceptions\Types\ArgumentTypeError
.
- Same as
-
\Error
can be converted into:\Smuuf\BetterExceptions\Types\UnknownNamedParameterError
- Provides methods:
getParameterName()
: Returns the name of unknown parameter as string.
- Provides methods:
-
\ArgumentCountError
can be converted into:\Smuuf\BetterExceptions\Types\ArgumentCountError
- Provides methods:
getExpected()
: Returns expected number of arguments.getActual()
: Returns the actual number of arguments.
- Provides methods: