is_file_handle()函数可准确判断变量是否为文件句柄:先用is_resource()确认是resource,再用@get_resource_type()获取类型并检查是否为"stream"或"file"。

怎么用 is_resource() 判断变量是文件句柄
PHP 中文件句柄(如 fopen() 返回值)本质是 resource 类型,但不是所有 resource 都是文件句柄——比如 cURL 句柄、MySQL 连接、GD 图像资源也都是 resource。所以不能只靠 is_resource() 就断定是“文件”句柄。
正确做法是两步:先确认是 resource,再用 get_resource_type() 检查类型名是否为 "stream"(PHP 7.4+)或更具体地匹配 "file"(旧版常见,但不绝对可靠)。
-
is_resource($var)必须为true,否则直接排除 -
get_resource_type($var)返回字符串,典型文件句柄返回"stream";部分系统或扩展下可能返回"file"或"stream-wrapper" - 注意:
get_resource_type()对已关闭的句柄会触发警告并返回false,务必先用is_resource()安全兜底
为什么 gettype() 不够用
gettype() 对所有 resource 都只返回 "resource",完全无法区分文件、socket、curl 等类型,属于“信息过载不足”——知道是资源,但不知道是什么资源。
例如:
立即学习“PHP免费学习笔记(深入)”;
$fp = fopen('/tmp/test.txt', 'r');
$ch = curl_init();
var_dump(gettype($fp), gettype($ch)); // 都输出 string(8) "resource"
这时候必须依赖 get_resource_type() 才能进一步识别。
实际判断逻辑该怎么写(带容错)
生产环境要防关闭句柄、空值、非 resource 输入。推荐封装成小函数:
function is_file_handle($var): bool {
if (!is_resource($var)) {
return false;
}
$type = @get_resource_type($var); // @ 抑制关闭句柄时的 warning
return in_array($type, ['stream', 'file'], true);
}
- 用
@抑制get_resource_type()对已关闭句柄抛出的 Warning(PHP 8.0+ 该 warning 已转为ValueError,需 try/catch) - 检查
"stream"是最通用方式(PHP 7.4+ 默认文件句柄类型),兼容性比只认"file"更好 - 不要依赖
ftell()或fstat()做判断——它们对非文件 resource(如php://memory)也可能成功,且会改变内部状态
容易被忽略的边界情况
有些“看起来像文件”的东西其实不是标准文件句柄:
-
php://input、php://memory、php://temp打开的流,get_resource_type()返回"stream",应视为合法文件句柄(符合流抽象) -
STDIN/STDOUT是预定义常量,类型也是"stream",同样适用上述判断 - 通过
stream_socket_client()创建的 socket,类型是"stream_socket",不属于文件句柄,需排除 - PHP 8.1+ 引入了
is_file_path()(仅限路径字符串),和句柄判断无关,别混淆
真正难的是区分“可读写的流”和“严格意义上的磁盘文件”,PHP 层面没有银弹——stream_get_meta_data() 的 uri 字段可辅助判断,但得自己解析协议和路径。











