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 等类型,属于“信息过载不足”——知道是资源,但不知道是什么资源。
例如:
$fp = fopen('/tmp/test.txt', 'r');
$ch = curl_init();
var_dump(gettype($fp), gettype($ch)); // 都输出 string(8) "resource"
这时候必须依赖 get_resource_type() 才能进一步识别。
生产环境要防关闭句柄、空值、非

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",不属于文件句柄,需排除is_file_path()(仅限路径字符串),和句柄判断无关,别混淆真正难的是区分“可读写的流”和“严格意义上的磁盘文件”,PHP 层面没有银弹——stream_get_meta_data() 的 uri 字段可辅助判断,但得自己解析协议和路径。