PHP 8.0: New get_debug_type
function
get_debug_type()
function that comes with PHP 8.0 is an attempt to improve gettype()
function which returns inconsistent values and does not expand to reveal the class names of objects.
One of the use cases of this function is to use it as an easy way to explain an unexpected variable in error logs or exception messages because the return type of gettype()
is often not verbose enough to be meaningful.
get_debug_type()
vs gettype()
The following sections will explain the differences between the new get_debug_type()
function and current gettype()
function return values.
Scalar types
Type | Example value | gettype() | get_debug_type() |
---|---|---|---|
String | "Foo" |
string |
string |
Arrays | [1, 2] |
array |
array |
Null | null |
NULL |
null |
Integers | 123 |
integer |
int |
Float | 3.141 |
double |
float |
Boolean | true |
boolean |
bool |
Boolean | false |
boolean |
bool |
Notice how the new get_debug_type()
function returns the exact types that you use in scalar typing.
Class objects and anonymous functions
Type | Example value | gettype() | get_debug_type() |
---|---|---|---|
Class object | new stdClass() |
object |
stdClass |
Class object | new DateTime() |
object |
DateTime |
Class object | new Foo\Bar() |
object |
Foo\Bar |
Closure | function() {} |
object |
Closure |
Anonymous class | new class {} |
object |
class@anonymous |
Anonymous subclass | new class extends Foo{} |
object |
Foo@anonymous |
As you can see, get_debug_type()
is starting to get more helpful here, because it helpfully reports the name of the class, or further details about anonymous classes.
If a closure is passed (which is internally an object), get_debug_type()
returns it as Closure
.
When an anonymous class object is passed, it returns class@anonymous
for classes without a parent/interface, or parent/interface name, followed by @anonymous
.
This is where the get_debug_type()
function gets quite helpful because instead of calling get_class()
and get_parent_class()
, get_debug_type()
directly returns a useful name for the given object. This can help minimize the boilerplate code and code bloat in when exceptions are thrown and errors are logged.
Resources
Type | Example value | gettype() | get_debug_type() |
---|---|---|---|
Streams | tmpfile() |
resource |
resource (stream) |
Curl handler | curl_init() |
resource |
resource (curl) |
Closed Curl handler | curl_close($ch) |
resource (closed) |
resource (closed) |
XML document | xml_parser_create() |
resource |
resource (xml) |
... | ... | resource |
resource (TYPE) |
For all resource types in PHP, get_debug_type()
function will return the type of that resource too.
Use cases
When you want to output a verbose error message on an unexpected type, instead of doing an ugly type lookup, which often overlooks other variable types, you can now easily get the type of a passed variable:
Previously:
if (!($foo instanceof Foo)) {
throw new TypeError(
sprintf(
'Parameter 1 is expected to be of type "%s", got "%s" instead.',
Foo::class,
(is_object($foo) ? get_class($foo) : gettype($foo))
)
);
}
Now:
if (!($foo instanceof Foo)) {
throw new TypeError(
sprintf(
'Parameter 1 is expected to be of type "%s", got "%s" instead.',
Foo::class,
get_debug_type($foo)
)
);
}
Polyfill
if (!function_exists('get_debug_type')) {
function get_debug_type($value): string {
switch (true) {
case null === $value: return 'null';
case \is_bool($value): return 'bool';
case \is_string($value): return 'string';
case \is_array($value): return 'array';
case \is_int($value): return 'int';
case \is_float($value): return 'float';
case \is_object($value): break;
case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
default:
if (null === $type = @get_resource_type($value)) {
return 'unknown';
}
if ('Unknown' === $type) {
$type = 'closed';
}
return "resource ($type)";
}
$class = \get_class($value);
if (false === strpos($class, '@')) {
return $class;
}
return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
}
}
Above is a polyfill that you can use in your code if you want to bring the get_debug_type()
function to your own code that cannot require PHP 8.0 to run. This snippet is from Symfony's PHP 8.0 polyfill.
Backwards compatibility impact
get_debug_type()
is a new function. Unless you have declared a function with an identical name in the global namespace, this should not bring any BC issues.