因为PHP是专注WEB开发的领域的,所以很大一部分都是CRUD的操作,对于标准输入流,输出流,错误流这一块并不是很熟悉。这也就是很多PHPer的基础不行的所在。

如果想要深入的学习PHP的话,那么这肯定是必须要掌握的。

首先,我们得先了解下,什么是标准输入流,输出流,错误流?它们是干什么的?有什么用?

说一个比较容易理解的解释。

如果我们要执行一个命令 command,如果我们需要给这个命令输入一些自定义的内容该怎么办呢?这个命令是如何获取到我们输入的内容的呢?这里就是用到了标准输入,而在PHP当中,也就是内置的 STDIN,它可以在PHP程序中直接使用。

现在,这个命令在接收到我们输入的内容之后,想要输出结果怎么办呢?如何输出呢?这里就用到了标注输出,而在PHP中也就是 STDOUT

那么现在有个问题了,如何判断一个命令是否执行成功呢?这个简单,通过命令的返回状态是否为0即可判断。

那我们如何读取在命令执行失败后的错误信息呢?有的小伙伴说,从标准输出读取呀?如果从标准输出读取的话,那么有个问题必须得考虑,我们如果仅仅只需要错误的信息怎么办呢?因为一道程序可能输出的内容非常多,如果将所有的输出信息都通过标准输出输出出来的话,那么这些信息就太混乱了。

于是,标准错误流就出现了,在这个标准错误里面,仅输出程序执行的错误信息,而标准输出则输出程序执行的非错误信息。这样的话,就好分辨了。如果我们只需要错误信息,那么直接从标准错误流读取就可以了。

OK,上面做了一个简单的解释。应该不是很难明白吧。

说了这么多,我们来实际操作下,首先,我们执行下这个命令:

~ ls -al
total 80
drwxr-xr-x  12 xiaoteng  staff   384  8  8 15:27 .
drwxr-xr-x  26 xiaoteng  staff   832  8  7 20:03 ..
-rw-r--r--   1 xiaoteng  staff    15  8  8 15:27 std.txt
-rw-r--r--   1 xiaoteng  staff   274  6 11 12:30 test.php

我们执行的 ls -al 命令的输出结果就是通过标准输出展示在命令行界面的。我们也可以通过这样操作将输出的结果写到文件:

~ ls -al > list.txt && cat list.txt
total 80
drwxr-xr-x  13 xiaoteng  staff   416  8  8 15:30 .
drwxr-xr-x  26 xiaoteng  staff   832  8  7 20:03 ..
-rw-r--r--   1 xiaoteng  staff    15  8  8 15:27 std.txt
-rw-r--r--   1 xiaoteng  staff   274  6 11 12:30 test.php

通过 cat 命令,我们看到 ls 命令的执行结果已经写入到 list.txt 这个文件了。这里就涉及到重定向的知识了。在命令行的执行中,我们可以通过 > 符号将标准输出的结果重定向到某个存储中。比如说,这里我们将结果重定向到了 list.txt 文件中。

再来看下这个:

~ ls -al >> list.txt && cat list.txt
total 80
drwxr-xr-x  13 xiaoteng  staff   416  8  8 15:30 .
drwxr-xr-x  26 xiaoteng  staff   832  8  7 20:03 ..
-rw-r--r--   1 xiaoteng  staff    15  8  8 15:27 std.txt
-rw-r--r--   1 xiaoteng  staff   274  6 11 12:30 test.php
total 88
drwxr-xr-x  13 xiaoteng  staff   416  8  8 15:30 .
drwxr-xr-x  26 xiaoteng  staff   832  8  7 20:03 ..
-rw-r--r--   1 xiaoteng  staff    15  8  8 15:27 std.txt
-rw-r--r--   1 xiaoteng  staff   274  6 11 12:30 test.php

我们可以通过 >> 符号将输出的结果追加到某个存储中。也就是如果是 > 的话那么会清空原先的内容,但是 >> 仅仅是追加内容。

我们再来看下标注错误的演示,执行下下面命令:

~ ls /lll
ls: /lll: No such file or directory

因为 /lll 这个目录是不存在的,所以报错了。不过在命令行之中无法直观的看到到底是标准输出还是标准错误。我们可以这样测试下:

~ ls /lll > result.txt
ls: /lll: No such file or directory

我们通过 > 将标准输出的结果重定向到 result.txt 这个文件,这样的话,命令行界面就不会直接输出标准输出的结果了。不过可以看到的是,错误的信息依旧展示出来了,所以,这里的错误信息并不是通过的标准输出,所以它肯定是标准错误流的了。

我们可以利用重定向将标准错误的结果保存到文件中:

~ ls /lll 2>error.txt

然后执行:

~ cat error.txt
ls: /lll: No such file or directory

这样我们就将错误信息转储到文件了。这里我们需要明白的是:

  • stdout是标准输出流 ,它显示来自命令的输出。它拥有文件描述符 1。
  • stderr是标准错误流 ,它显示来自命令的错误输出。它拥有文件描述符 2。
  • stdin是标准输入流 ,它向命令提供输入。它拥有文件描述符 0。

上面的命令 ls /lll 2>error.txt 中的 2 就是代表的标准错误流。

好了,说了这么多基础的,应该有了足够的了解了。现在,我们在PHP中来操作下。

首选,PHP的标准输出,创建个 std.php

<?php

echo 'hello xiaoteng';

执行下:

~ php std.php
hello xiaoteng

默认情况下,在PHP当中通过像 echovar_dump等函数输出的内容,最终都会重定向到这个标准输出。我们也可以直接向标准输出写入内容:

<?php

fwrite(STDIN, 'hello xiaoteng.hello world');

执行:

~ php std.php
hello xiaoteng.hello world

可以看到,也可以在命令行当中看到输出的信息。

再来看下,PHP的标准输入:

<?php

echo fread(STDOUT, 1024);

执行:

~ php std.php
123123
123123

执行后,我们在键盘输入了 123123,回车,然后程序将输入的值打印出来。所以,通过 STDIN 我们可从命令行读取用户的输入。

在来看下标准错误:

<?php

fwrite(STDERR, '我是错误');

执行:

~ php std.php
我是错误

如果抛出一个异常话会怎么样:

<?php

throw new Exception('我是错误');

执行:

php std.php >result 2>error

然后在目录下面,可以看到生成了 resulterror 两个文件,执行:

cat result && cat error

Fatal error: Uncaught Exception: 我是错误 in /Users/xiaoteng/work/test/std.php:3
Stack trace:
#0 {main}
  thrown in /Users/xiaoteng/work/test/std.php on line 3
PHP Fatal error:  Uncaught Exception: 我是错误 in /Users/xiaoteng/work/test/std.php:3
Stack trace:
#0 {main}
  thrown in /Users/xiaoteng/work/test/std.php on line 3

可以看到,两个文件的内容是一样的。也就是PHP的异常在标准输出和标准错误都有输出。

好了,就先写到这里。有不理解的可以留言。

参考资料:

https://www.runoob.com/linux/linux-shell-io-redirections.html
https://developer.ibm.com/zh/tutorials/l-lpic1-103-4/