is_resource
Checks whether a variable is an open resource handle such as a stream or context.
is_resource(mixed $value): bool- Added in PHP 4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$value | mixed | The variable being evaluated. |
Return value
booltrue if $value is an open resource, false otherwise — including for resources that have been closed.
It checks open-ness, not just type
The name suggests a type check, but is_resource() returns false for a resource that has already been closed. That is deliberate and usually what you want: the honest reading is "is this a usable handle right now?" If you need to distinguish a closed resource from a value that was never a resource, check gettype($value), which returns "resource (closed)" for the former.
Guard your teardown
The most common real use is defending fclose(), fwrite() and friends against double-close or against a failed fopen() that returned false. Wrapping the call in if (is_resource($h)) turns a warning-generating crash path into a no-op, which matters in destructors and finally blocks that may run twice.
The PHP 8 migration trap
Many extensions that historically returned resources now return objects: cURL handles, GD images, XML parsers, finfo, sockets and more became classes in PHP 8.0 and 8.1. Legacy code guarded by is_resource($curl) silently stopped matching and started skipping its own error handling. When you touch old code, check what the extension actually returns today and switch to instanceof where it has moved to objects. Streams from fopen(), tmpfile(), popen() and stream_context_create() are still genuine resources.
Example
When to use it
- Guard fclose() in a destructor or finally block so a second teardown pass does not warn.
- Verify that fopen() actually returned a handle before writing to it.
- Audit legacy PHP 7 code where cURL or GD checks broke after those extensions started returning objects.
Frequently asked questions
Why does is_resource return false after fclose?
By design — it reports whether the resource is currently open, not merely whether the variable was ever a resource. Use gettype($v) === 'resource (closed)' if you need to detect a closed handle specifically.
Does is_resource work with cURL or GD handles in PHP 8?
No. cURL, GD, XML and several other extensions return objects rather than resources since PHP 8.0 and 8.1, so is_resource() returns false for them. Use instanceof CurlHandle, instanceof GdImage, and so on.
How do I check what kind of resource I have?
Call get_resource_type(), which returns a string such as "stream", "stream-context" or "persistent stream". Check is_resource() first, since get_resource_type() on a closed resource returns "Unknown".
More examples
Safe teardown that can run twice
The first call closes the stream; the second sees a closed resource and does nothing instead of raising "supplied resource is not a valid stream resource". Passing false — what a failed fopen() returns — is handled by the same guard.
<?php
function closeQuietly(mixed $handle): string {
if (!is_resource($handle)) {
return 'nothing to close';
}
fclose($handle);
return 'closed';
}
$fh = fopen('php://memory', 'r+');
echo closeQuietly($fh), "\n";
echo closeQuietly($fh), "\n";
echo closeQuietly(false), "\n";Not everything with a handle is a resource
Streams and stream contexts are true resources. ArrayIterator is an object, and get_debug_type() names it precisely — that is the check to use for the many extensions whose handles became objects in PHP 8.
<?php
$stream = fopen('php://memory', 'r+');
$context = stream_context_create(['http' => ['timeout' => 1]]);
$object = new ArrayIterator([1, 2]);
foreach (['stream' => $stream, 'context' => $context, 'object' => $object] as $label => $v) {
printf("%-8s is_resource=%s type=%s\n",
$label, var_export(is_resource($v), true), get_debug_type($v));
}
fclose($stream);Distinguishing closed from never-a-resource
gettype() keeps reporting "resource (closed)" after fclose(), while is_resource() has already flipped to false. Combining the two gives you a three-way answer, which is what you need when a stale handle and a null both need different error messages.
<?php
function describe(mixed $v): string {
return match (true) {
is_resource($v) => 'open resource',
gettype($v) === 'resource (closed)' => 'closed resource',
default => 'not a resource (' . get_debug_type($v) . ')',
};
}
$fh = fopen('php://memory', 'r+');
echo describe($fh), "\n";
fclose($fh);
echo describe($fh), "\n";
echo describe(null), "\n";
Discussion