资讯专栏INFORMATION COLUMN

PHP回顾之IO

happen / 2949人阅读

摘要:命令行时返回值为,标准输入输出均指向终端可用进程号查看。会在脚本执行完毕后关闭三个流,无需用户手动关闭。与远程网址交互是一个请求和响应的过程,其中细节可参考本人之前的文章回顾之请求和回顾之响应,也可参考协议的权威文档。

转载请注明文章出处: https://tlanyan.me/php-review...
PHP回顾系列目录

PHP基础

web请求

cookie

web响应

session

数据库操作

加解密

Composer

创建自己的Composer包

发送邮件

无论哪种编程语言,IO操作都值得好好学习和理解。由于PHP简单的特性,不少人对此毫无概念也能写出可用的代码。本文总结PHP开发中几个常见的IO场景并介绍对应的操作,希望能帮助PHP开发人员加深对IO的理解。后续文章中将介绍隐藏在简单之下的本质:流。

本文介绍的场景包括:读写文件、命令行输入输出、与远程网址交互。废话少说,直接开始吧!

读写文件

文件的读写是最常规的IO操作。打开文件、读写内容、关闭文件,一气呵成,没什么尿点。一个典型的读取文件内容例子:

function getFileContent(string $filename) : ?string
{
    if (!is_file($filename)) {
        return null;
    }

    $fd = fopen($filename, "rb");
    $content = fread($fd, filesize($filename);
    fclose($fd);
    return $content;
}

读写文件So easy! 要想对文件操作玩得更高端点,至少需要熟练使用这些API:

file_exists/is_file/filesize/fileperms等获取文件信息的辅助函数;

fopen:打开文件,获取文件句柄,第二个参数(arwcbx)的含义要弄清楚;

flock:获取文件锁,可用其实现进程互斥锁;

fread/fgets/fscanf等获取文件内容的函数;

fwrite/fputs/fputcsv/ftruncate等写入内容函数;

feof/ftell/fseek/rewind等操作文件指针位置的函数;

fclose: 关闭文件,释放资源。

注意本节中的文件指是 本地文件,对于远程文件,上述函数是否起作用取决于协议是否提供支持。例如fread/fwrite可以操作http://协议的资源,但stat/filesize等函数不能正常工作。可参考官网的“协议和包装器” 查看非本地普通文件时可用的函数信息。

命令行输入和输出

PHP主要用于web开发,命令行应用也比较常见,比如定时任务的脚本。命令行模式下,有不少与web开发不同的地方,比如可以使用多进程/线程(web中的curl_multiple不算),没有运行时间限制等。

命令行时php_sapi_name返回值为cli,标准输入输出均指向终端(可用ll /proc/进程号/fd查看)。PHP定义了三个句柄常量:

STDIN: 标准输入,只读,等同于用fopen打开"php://stdin";

STDOUT: 标准输出,只写,等同于用fopen打开"php://stdout";

STDERR: 标准错误输出,只写,等同于fopen打开"php://stderr"。

注意标准输入对应"php://stdin"而非"php://input",虽然这两者行为在命令行模式下几乎一致(区别可参考本人之前的文章php://output和php://stdout的区别)。

操作三个读写通道,对应的函数是fread/fgetc/fscanf/fwrite/fputc/fputs等。PHP会在脚本执行完毕后关闭三个流,无需用户手动关闭。下面用代码简要展示用法:

function prompt(string $message) : string
{
    fwrite(STDOUT, $message);
    // fgets会把换行符也读入,可用rtrim过滤掉
    return rtrim(fgets(STDIN));
}

function println(string $message) : void
{
    fputs(STDOUT, $message . PHP_EOL);
}

function error(string $message) : void
{
    fputs(STDERR, $message . PHP_EOL);
}

$value = prompt("input your value:");
if ($value !== "") {
    println("your input: $value");
} else {
    error("invalid value!");
}

命令行模式时"php://output"链接到标准输出,所以echo/print/var_dump等输出函数可正常使用。要交互式的从命令行获取输入,则需要用到fread/fgets等文件读取函数。

常量PHP_EOL是预定义的跨平台换行符,EOL是end of line的缩写,不是end of life~

与远程网址交互

从网页获取内容,cURL拓展绝对值得大提特提。如果你熟悉curl命令,对其功能的强大应该有所了解,那么应该对使用PHP中的CURL系列函数会得心应手。

与远程网址交互是一个请求和响应的过程,其中细节可参考本人之前的文章:PHP回顾之web请求和PHP回顾之web响应,也可参考HTTP协议的权威文档。使用CURL与远程web服务器的交互流程如下:

初始化CURL句柄

设置请求信息:请求URL、头部信息、cookie、正文等;

发送请求

获取执行结果

关闭CURL句柄,释放资源

CURL简单好用,缺点是请求的设置参数繁杂难记。

实践中推荐以类Java的HttpClient库形式与远程服务器交互。HttpClient类库将请求、响应、传输等概念抽出来,完全面向对象,更语义化,使用其能更好促进对HTTP协议的理解,缺点是代码相对繁琐。PHP有不少类似的HTTP请求库,以下使用Yii2中的yii2-httpclient类库展示使用示例:

use yiihttpclientClient;
use yiihttpclientResponse;

$url = "https://tlanyan.me";
$data = [
    "key1" => "value1",
    "key2" => "value2",
];
$response = (new Client())->createRequest()
    ->setMethod("POST")
    ->setFormat(Client::FORMAT_JSON)
    ->setUrl($url)
    ->setData($data)
    ->send();

if ($response->isOk) {
    $response->setFormat(Client::FORMAT_JSON);
    // 获取解析后的数据
    $data = $response->data;
   ....
}

使用fopen/fsocketopen等函数也能实现与远程服务器的交互,这部分内容放在后续的流中阐述。

file_get_contents

上文废话了半天,还没说到PHP中获取内容的神器:file_get_contents函数。该函数是PHP读取内容当之无愧的神器,不管是常规文件、php://、http://、还是标准输入等,file_get_contents一句话搞定。相较于Java等语言中的client/connection/stream等一堆代码,file_get_contents体现了PHP简单实用的设计哲学。

想必PHP开发常用该函数,就用几个简单的示例结束本文(注意代码中POST请求网页已经涉及到了流的内容)。

// 读取普通文件
file_get_contents("/etc/passwd");

// 获取web请求的原始正文,可获取json/xml等数据格式的原始内容,也可获得上传文件的内容,注意该返回可能唯二进制
// 以json/xml数据格式交互时,推荐使用此方法而非通过$GLOBALS["HTTP_RAW_POST_DATA"]获取,$HTTP_RAW_POST_DATA在PHP 7.2中已被移除
file_get_contents("php://input");

// 获取网址内容,可取代curl
file_get_contents("https://tlanyan.me");


// 传入context对象,可实现post请求
$contextOptions = [
    "http" => [
        "method" => "POST",
        "ignore_errors" => true,
        "content" => "username=tlanyan",
        "header" => "Content-type: application/x-www-form-urlencoded",
        "user_agent" => "MySpider/1.0",
    ],
    "ssl" => [
    "verify_peer" => false,
    ],
];
$context = stream_context_create($contextOptions);
file_get_contents("https://tlanyan.me", false, $context);

// cli模式下从标准输入读取数据,此时换行符也被当做输入的一部分,要以ctrl+d作为结束输入的标志
file_get_contents(STDIN);

// 写入文件内容
file_put_contents("foo.txt", "Test function call
", FILE_APPEND);
参考

http://php.net/manual/en/ref....

http://php.net/manual/en/feat...

http://php.net/manual/en/book...

https://github.com/yiisoft/yi...

感谢阅读,感谢指正!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30726.html

相关文章

  • PHP回顾协程

    摘要:本文先回顾生成器,然后过渡到协程编程。其作用主要体现在三个方面数据生成生产者,通过返回数据数据消费消费者,消费传来的数据实现协程。解决回调地狱的方式主要有两种和协程。重点应当关注控制权转让的时机,以及协程的运作方式。 转载请注明文章出处: https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie web响应 sess...

    Java3y 评论0 收藏0
  • PHP回顾执行流程及相关概念

    摘要:通过,脚本层无需过多考虑执行的具体环境,而本身则可以让针对自己的特点给出特有实现。模式下,也只执行一次。这几个概念的关系如下网关协议,与语言无关,所以与关系也不大。总结本文简要回顾了程序的架构和执行流程,并对几个容易混淆概念做了介绍。 转载请注明文章出处:https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie we...

    jsdt 评论0 收藏0
  • PHP回顾socket编程

    摘要:如果你想体验原味编程,用开头的比较适合否则建议使用流函数。有关流的知识,请参考本人之前的博文回顾之流。接下来我们用流函数实现一个简单的客户端和服务端。流函数中的和两个函数是我们想要的。本文目的是简要介绍中的编程,行文到此已经达到目的。 转载请注明文章出处: https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie w...

    tomorrowwu 评论0 收藏0
  • PHP回顾

    摘要:本文先简要跟踪底层流的原理,再回到用户态中流的使用。底层流我们知道中的函数可以打开本地文件等并返回一个句柄,函数能对资源句柄进行读写,用于关闭资源。更多关于底层流的操作可参考官方文档中开发者的流章节,本文不再深入。 转载请注明文章出处: https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie web响应 sessi...

    gself 评论0 收藏0
  • PHP回顾多进程编程

    摘要:多进程中与多进程相关的两个重要拓展是和。函数执行期间,主进程除了等待无法处理其他任务,所以一般不认为这是多进程编程。回收子进程有两种方式,一种是主进程调用函数等待子进程结束另外一种是处理信号。 转载请注明文章出处: https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie web响应 session 数据库操作 加解...

    lifesimple 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<