应先用is_resource($var)确认是资源,再用get_resource_type($var)区分"socket"或"stream"类型,因socket_create()返回"socket"而fsockopen()返回"stream",二者不兼容且需匹配对应操作函数。
is_resource() 判断变量是否为 Socket 资源PHP 中 Socket 操作返回的是资源(resource)类型,不是对象也不是标量,所以不能用 is_object() 或 is_int() 来判断。最直接可靠的方式是先确认它是不是资源,再进一步确认资源类型:
is_resource($var) 返回 true 仅说明它是某种资源,但不保证是 socketget_resource_type($var) 二次验证,因为文件句柄、cURL 句柄、MySQL 连接等也都是 resource"stream"(如 fsockopen() 创建的),但 socket_create() 创建的是 "socket" —— 注意这个关键区别

socket_create() 和 fsockopen() 的资源类型不同
这是最容易混淆的点:两种常见创建方式产生的资源类型不一致,导致检测逻辑不能一概而论:
socket_create(AF_INET, SOCK_STREAM, SOL_TCP) → get_resource_type() 返回 "socket"
fsockopen("127.0.0.1", 80) → get_resource_type() 返回 "stream"(哪怕你后续用 stream_socket_enable_crypto())get_resource_type() === "socket" 会漏掉大量实际可用的 socket-like 流资源is_resource($var) && gettype($var) === "resource" && (get_resource_type($var) === "socket" || get_resource_type($var) === "stream"),再加 stream_get_meta_data($var) 看 timed_out/eof 等状态佐证gettype() 直接判断gettype($var) 对所有资源都返回 "resource",完全无法区分 socket、file、curl 等类型,纯属无效判断:
gettype(fopen("/tmp/a", "r")) 和 gettype(socket_create(...)) 都返回 "resource"
gettype() + 类型字符串匹配来识别 socket 是徒劳的get_resource_type(),且必须结合创建上下文理解其含义已关闭的 socket 资源在 PHP 8+ 中仍可能通过 is_resource() 检测(表现为“伪有效”),但后续调用 socket_write() 或 fwrite() 会失败:
get_resource_type() 可能触发警告或返回空字符串,行为不稳定is_resource($var) && !feof($var)(对 stream)或 socket_get_option($var, SOL_SOCKET, SO_ERROR) !== false(对 socket)做存活验证function is_valid_socket($var): bool {
if (!is_resource($var)) return false;
$type = get_resource_type($var);
if ($type === "socket") return socket_get_option($var, SOL_SOCKET, SO_ERROR) !== false;
if ($type === "stream") return !feof($var) && @stream_get_meta_data($var)['unread_bytes'] !== null;
return false;
}fsockopen() 返回值当成严格意义上的 “socket resource” 去调用 socket_*() 函数——它们根本不兼容。类型检测只是第一步,后续操作必须和创建方式严格对应。