许多 posix 函数在发生错误时在 errno 代码中提供非常有用的信息。例如,stream_select() 在生成错误时,根据手册页 (man 2 select) 可能会返回以下四个不同错误之一:EBADF、EINTR、EINVAL、ENOMEM。有关这些错误的更详细的信息,请参见手册页。在此示例中,当 stream_select() 函数返回 false 时,posix_get_last_error() 将返回一个非零值,该值将被设置为这些常量之一。例如,如果 stream_select() == false 且 posix_get_last_error() == EBADF,则传递给 select() 函数的文件描述符之一可能已关闭。另一方面,如果 posix_get_last_error() 返回 EINTR,则 stream_select() 返回 FALSE,不是因为任何真正的错误情况,而仅仅是因为进程处理了一个信号。当信号到达时,stream_select() 正在阻塞,它将始终停止阻塞并立即返回 false。这种行为是有道理的,尽管它看起来可能不方便。您只需要正确处理它。(在 php 中,很少有人这样做。)
从这个例子中,您应该清楚地了解,人们至少应该考虑以不同的方式处理不同的错误类型。例如,应该忽略 EINTER,除非您的程序使用信号来打开或关闭文件句柄或套接字。
这些在相关 POSIX 手册页中列出的错误常量不是 PHP 接口的一部分。当您调用 posix_get_last_error() 时,它将返回一个整数。获取未命名的整数返回值的问题在于,这些整数在不同的系统上可能具有不同的含义。您可以(并且可能应该)将结果整数传递给 posix_strerror() 函数,该函数将返回对错误的准确人类可读描述。这当然很有用,但主要用于记录。(错误的字符串描述比实际的整数值代码更容易改变。)实际上,当使用 posix_errno() 的结果时,最好将值与一组可能的常量进行比较。您将它们比较的常量是系统特定的,如前所述,因此您需要在该系统上查找它们。以下是一种简单可靠的方法。
查看 errno 手册页($ man errno)并将所有常量名称复制到一个非常基本的 C 文件中。如下所示。
===================================
#include <errno.h>
#include <stdio.h>
int main(){
printf("define('E2BIG', %d);\n", E2BIG);
printf("define('EACCES', %d);\n", EACCES);
printf("define('EADDRINUSE', %d);\n", EADDRINUSE);
printf("define('EADDRNOTAVAIL', %d);\n", EADDRNOTAVAIL);
// ... 等等等等
}
===================================
现在,如果您只是通过 C 预处理器运行此代码(即 'gcc -E cfile.c'),那么这些常量名称将被替换为您系统上使用的数字。(警告:运行 C 编译器/预处理器需要在 PHP 代码运行的系统上进行。跟踪 nfs 是否在使用或其他类似内容,这些内容可能会将您的编码环境与运行时环境分开。)除了运行 C 预处理器之外,您还可以简单地编译并运行上面的程序(即 'gcc cfile.c && ./a.out')。运行它将生成一个 PHP 兼容的 define() 调用列表,这些调用将在目标系统上的 PHP 程序中正确定义这些常量,因此可以使用。只需将这些定义复制到一个 php 文件中即可。
要完成示例,您可能需要像这样使用这些常量
$selret = stream_select( $r, $w, $e, $to );
if( $selret === false )
{
switch( posix_get_last_error() )
{
case EBADF: /* 其中一个句柄无效。修复它。 */ break;
case EINVAL: /* $to 为负?哎呀。 */ break;
case ENOMEM
throw new exception("可能的内存泄漏。重启。");
break;
case EINTR
break; // 通常在 select() 后忽略 EINTR 就可以了。
}
}