PHP php://memory、php://temp流用法解析

PHPliuliangsong 发表了文章 • 0 个评论 • 60 次浏览 • 2016-12-06 12:42 • 来自相关话题

一、php://memory流介绍:  php://memory流类似如一个文件,支持读写操作;使用fopen()、fclose()函数打开流,使用fseek()、rewind()函数移动流指针, 使用ftell()、feof() 函数获取流指针当前的位置。
  与普通文件不同的是,php://memory流的数据是写在内存中,速度比普通文件快很多。不过由于直接占用内存,不建议将大数据写入此流。php://memory流适合用于存放需要多次重复、频繁使用,数据量不大的临时内容。
内存填充测试:<?php
echo sprintf("填充前内存占用: %.2fMB\n", memory_get_usage()/1024/1024);
$mem = fopen('php://memory', 'r+');
for($i=0; $i<10000; $i++) {
fwrite($mem, str_repeat('aiezu.com', 1000));
}
echo sprintf("填充后内存占用: %.2fMB\n", memory_get_usage()/1024/1024);
fclose($mem);
echo sprintf("内存释放后占用: %.2fMB\n", memory_get_usage()/1024/1024);测试结果:[root@aiezu.com ~]# php test.php
填充前内存占用: 0.21MB
填充后内存占用: 86.05MB
内存释放后占用: 0.21MB  二、php://temp流介绍:  php://temp流与php://memory流用法和功能基本相同,只是默认当写入的数据达到2MB时,数据将由写入在内存变为写入到临时文件。写入的临时文件名为sys_get_temp_dir()函数获取的目录下以"php"开头的随机文件名;可以使用"php://temp/maxmemory:NN"形式设定超过NN字节时数据才写入到临时文件;php://temp流比较适合用于存放数据量比较大,且需要重复读取的数据。
  下面是通过linux curl上传csv的简单的例子,用于演示php://temp的用法;由于此例未重复使用这些csv数据,只做演示用,实际应用中此例完全可以去掉使用php://temp流。
网站端test.php代码:<?php
//设置编码,不然中文会乱码
setlocale(LC_ALL, array('zh_CN.UTF-8', 'zh_CN.gbk','zh_CN.gb2312','zh_CN.gb18030'));
if ( strtolower($_SERVER['CONTENT_TYPE']) == "application/csv" ) {
$input = fopen("php://input", 'r');
$temp = fopen("php://temp/maxmemory:0", 'r+');
while( $buffer = fread($input, 1024) ) {
fwrite($temp, $buffer);
}
fclose($input);
rewind($temp); //指针移动到文件头

fgetcsv($temp); //跳过标题行
while($data = fgetcsv($temp)) {
print_r($data);
//将数据写入数据库或者其他复杂计算操作
//...
}
}客户端site.csv数据:站点,url,行业
天猫,tmall.com,电子商务
腾讯,qq.com,社交网络
新浪,sina.com.cn,门户
...linux curl上传csv数据命令:[root@aiezu.com ~]# curl -H "Content-Type: application/csv" --data-binary @site.csv http://aiezu.com/test.php
Array
(
[0] => 天猫
[1] => tmall.com
[2] => 电子商务
)
Array
(
[0] => 腾讯
[1] => qq.com
[2] => 社交网络
)
Array
(
[0] => 新浪
[1] => sina.com.cn
[2] => 门户
)
... 三、附录:PHP 输入输出流合集 查看全部

一、php://memory流介绍:

  php://memory流类似如一个文件,支持读写操作;使用fopen()、fclose()函数打开流,使用fseek()、rewind()函数移动流指针, 使用ftell()、feof() 函数获取流指针当前的位置。
  与普通文件不同的是,php://memory流的数据是写在内存中,速度比普通文件快很多。不过由于直接占用内存,不建议将大数据写入此流。php://memory流适合用于存放需要多次重复、频繁使用,数据量不大的临时内容。
内存填充测试:
<?php
echo sprintf("填充前内存占用: %.2fMB\n", memory_get_usage()/1024/1024);
$mem = fopen('php://memory', 'r+');
for($i=0; $i<10000; $i++) {
fwrite($mem, str_repeat('aiezu.com', 1000));
}
echo sprintf("填充后内存占用: %.2fMB\n", memory_get_usage()/1024/1024);
fclose($mem);
echo sprintf("内存释放后占用: %.2fMB\n", memory_get_usage()/1024/1024);
测试结果:
[root@aiezu.com ~]# php test.php
填充前内存占用: 0.21MB
填充后内存占用: 86.05MB
内存释放后占用: 0.21MB
  

二、php://temp流介绍:

  php://temp流与php://memory流用法和功能基本相同,只是默认当写入的数据达到2MB时,数据将由写入在内存变为写入到临时文件。写入的临时文件名为sys_get_temp_dir()函数获取的目录下以"php"开头的随机文件名;可以使用"php://temp/maxmemory:NN"形式设定超过NN字节时数据才写入到临时文件;php://temp流比较适合用于存放数据量比较大,且需要重复读取的数据。
  下面是通过linux curl上传csv的简单的例子,用于演示php://temp的用法;由于此例未重复使用这些csv数据,只做演示用,实际应用中此例完全可以去掉使用php://temp流。
网站端test.php代码:
<?php
//设置编码,不然中文会乱码
setlocale(LC_ALL, array('zh_CN.UTF-8', 'zh_CN.gbk','zh_CN.gb2312','zh_CN.gb18030'));
if ( strtolower($_SERVER['CONTENT_TYPE']) == "application/csv" ) {
$input = fopen("php://input", 'r');
$temp = fopen("php://temp/maxmemory:0", 'r+');
while( $buffer = fread($input, 1024) ) {
fwrite($temp, $buffer);
}
fclose($input);
rewind($temp); //指针移动到文件头

fgetcsv($temp); //跳过标题行
while($data = fgetcsv($temp)) {
print_r($data);
//将数据写入数据库或者其他复杂计算操作
//...
}
}
客户端site.csv数据:
站点,url,行业
天猫,tmall.com,电子商务
腾讯,qq.com,社交网络
新浪,sina.com.cn,门户
...
linux curl上传csv数据命令:
[root@aiezu.com ~]# curl -H "Content-Type: application/csv" --data-binary @site.csv http://aiezu.com/test.php 
Array
(
[0] => 天猫
[1] => tmall.com
[2] => 电子商务
)
Array
(
[0] => 腾讯
[1] => qq.com
[2] => 社交网络
)
Array
(
[0] => 新浪
[1] => sina.com.cn
[2] => 门户
)
...
 

三、附录:

PHP 输入输出流合集

PHPliuliangsong 发表了文章 • 0 个评论 • 72 次浏览 • 2016-12-05 13:58 • 来自相关话题

  PHP 提供了输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。流接口常量介绍php://stdinSTDIN只读,用于CLI模式从命令行读取内容;php://stdoutSTDOUT只写,用于CLI模式向命令行标准输出输出内容;php://stderrSTDERR只写,用于CLI模式向命令行错误输出输出内容;php://input无只读,用于HTTP模式读取客户端以POST方式提交,
HTTP请求头Content-Type值不为multipart/form-data​的数据;php://output无只写,输出内容,近似echo、print的功能;php://memory无读写,类似文件包装器的数据流,用于内存中读写临时数据;php://temp无同上,不过当数据多于2MB会被写入到临时文件;
可以使用"php://temp/maxmemory:NN"形式设定超过NN字节时数据写入到临时文件;
临时文件位置与sys_get_temp_dir()一致;php://fd无允许直接访问指定的文件描述符;
如“php://fd/3”引用了文件描述符“3”;php://filter无是一种元封装器,用于数据流打开时的筛选和过滤应用。这对于一体式的文件函数非常有用,类似readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他。官方介绍文档:http://php.net/manual/zh/wrappers.php.php 查看全部
  PHP 提供了输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。
流接口常量介绍
php://stdinSTDIN只读,用于CLI模式从命令行读取内容;
php://stdoutSTDOUT只写,用于CLI模式向命令行标准输出输出内容;
php://stderrSTDERR只写,用于CLI模式向命令行错误输出输出内容;
php://input只读,用于HTTP模式读取客户端以POST方式提交,
HTTP请求头Content-Type值不为multipart/form-data​的数据;
php://output只写,输出内容,近似echo、print的功能;
php://memory读写,类似文件包装器的数据流,用于内存中读写临时数据;
php://temp同上,不过当数据多于2MB会被写入到临时文件;
可以使用"php://temp/maxmemory:NN"形式设定超过NN字节时数据写入到临时文件;
临时文件位置与sys_get_temp_dir()一致;
php://fd允许直接访问指定的文件描述符;
如“php://fd/3”引用了文件描述符“3”;
php://filter是一种元封装器,用于数据流打开时的筛选和过滤应用。这对于一体式的文件函数非常有用,类似readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他。
官方介绍文档:http://php.net/manual/zh/wrappers.php.php

PHP php://input、php://output用法解析

PHPliuliangsong 发表了文章 • 0 个评论 • 112 次浏览 • 2016-12-05 10:28 • 来自相关话题

一、php://output输出流用法:  php://output是php语言中一个只写的数据流,向“php://input”写入的数据将像 print() 和 echo() 一样的方式 写入到输出缓冲区;“php://input”支持CLI(command-line interface,命令行界面)模式和Http模式;
   1、CLI模式通过php://output向终端输出内容:test.php文件:<?php
$output = fopen("php://output", "w");
fwrite($output, "爱E族");
fclose($output);输出:[root@aiezu.com ~]# php test.php
爱E族 2、Http模式通过php://output导出csv文件:  注意,以UTF8编码导出CSV文件,如果文件头未添加BOM头,使用Excel打开会出现乱码。
test.php页面代码:<?php
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="test.csv"');
$output = fopen('php://output','w') or die("Can't open php://output");
//UTF8 csv文件头前需添加BOM,不然会是乱码
fwrite($output, chr(0xEF).chr(0xBB).chr(0xBF));
// 输出标题行
fputcsv($output, array('站点名', '域名', '行业'));
//数据内容
$rows = array(
array('天猫', 'http://tmall.com', '电子商务')
,array('爱E族', 'http://aiezu.com', '互联网技术')
,array('腾讯', 'http://qq.com', '社交网络')
);
foreach($rows as $row) {
fputcsv($output, $row);
}
fclose($output) or die("Can't close php://output");网页打开效果如下:



   二、php://input输入流用法:  php://input是php语言中一个只读的数据流;通过"php://input",可以读取从Http客户端以POST方式提交、请求头“Content-Type”值非"multipart/form-data​"的所有数据;"php://input"一般用来读取POST上来,除已被处理以外的剩余数据。
 1、PHP使用"php://input"接收XML数据:http test.php页面代码:<?php
/**
* xml文档转为数组元素
* @param obj $xmlobject XML文档对象
* @return array
*/
function xmlToArray($xmlobject) {
$data = array();
foreach ((array)$xmlobject as $key => $value) {
$data[$key] = !is_string($value) ? xmlToArray($value) : $value;
}
return $data;
}

if ( strtolower($_SERVER['CONTENT_TYPE']) == 'application/xml' && $content = file_get_contents("php://input") ) {
$xml = simplexml_load_string($content);//转换post数据为simplexml对象
print_r(xmlToArray($xml));
}待提交xml.xml文件内容:<?xml version='1.0' encoding='UTF-8'?>
<root>
<site>
<name>爱E族</name>
<domain>aiezu.com</domain>
</site>
<site>
<name>天猫</name>
<domain>tmall.com</domain>
</site>
</root>通过linux curl命令提交xml.xml:[root@aiezu.com ~]# curl -H "Content-Type: application/xml" --data-binary @xml.xml http://aiezu.com/test.php
Array
(
[site] => Array
(
[0] => Array
(
[name] => 爱E族
[domain] => aiezu.com
)
[1] => Array
(
[name] => 天猫
[domain] => tmall.com
)
)
)  2、PHP使用"php://input"接收JSON数据:  PHP使用"php://input"接收JSON数据,与接收XML数据十分类似,这里不再做介绍,要查看实例请参考:Linux curl命令get/post提交数据、json和文件全攻略 页面的第“六”节。
 3、PHP使用"php://input"接收文件内容:  下面通过代码演示PHP使用"php://input"接收一个png文件,这里只是用于演示,实际运用中还是建议使用Http请求头"Content-Type"值为"multipart/form-data"的表单方式POST。
接收页面"test.php"代码:<?php
if ( preg_match("#^image/(png|jpe?g|gif)$#i", $_SERVER['CONTENT_TYPE'], $match) && $binary = file_get_contents("php://input") ) {
$file = sprintf("/tmp/pic.%s", strtolower($match[1]));
file_put_contents($file, $binary);
echo sprintf("文件大小: %s\n", filesize($file));
echo sprintf("修改时间: %s\n", date("Y-m-d H:i:s", filemtime($file)));
}提交测试:[root@aiezu.com ~]# curl -H "Content-Type: image/png" --data-binary @logo.png http://aiezu.com/test.php
文件大小: 3706
修改时间: 2016-12-05 13:29:08
 三、附录:Linux curl命令详解PHP 输入、输出流合集 查看全部

一、php://output输出流用法:

  php://output是php语言中一个只写的数据流,向“php://input”写入的数据将像 print() 和 echo() 一样的方式 写入到输出缓冲区;“php://input”支持CLI(command-line interface,命令行界面)模式和Http模式;
   

1、CLI模式通过php://output向终端输出内容:

test.php文件:
<?php
$output = fopen("php://output", "w");
fwrite($output, "爱E族");
fclose($output);
输出:
[root@aiezu.com ~]# php test.php 
爱E族
 

2、Http模式通过php://output导出csv文件:

  注意,以UTF8编码导出CSV文件,如果文件头未添加BOM头,使用Excel打开会出现乱码。
test.php页面代码:
<?php
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="test.csv"');
$output = fopen('php://output','w') or die("Can't open php://output");
//UTF8 csv文件头前需添加BOM,不然会是乱码
fwrite($output, chr(0xEF).chr(0xBB).chr(0xBF));
// 输出标题行
fputcsv($output, array('站点名', '域名', '行业'));
//数据内容
$rows = array(
array('天猫', 'http://tmall.com', '电子商务')
,array('爱E族', 'http://aiezu.com', '互联网技术')
,array('腾讯', 'http://qq.com', '社交网络')
);
foreach($rows as $row) {
fputcsv($output, $row);
}
fclose($output) or die("Can't close php://output");
网页打开效果如下:
php_output流到处CSV文件.png

   

二、php://input输入流用法:

  php://input是php语言中一个只读的数据流;通过"php://input",可以读取从Http客户端以POST方式提交、请求头“Content-Type”值非"multipart/form-data​"的所有数据;"php://input"一般用来读取POST上来,除已被处理以外的剩余数据。
 

1、PHP使用"php://input"接收XML数据:

http test.php页面代码:
<?php
/**
* xml文档转为数组元素
* @param obj $xmlobject XML文档对象
* @return array
*/
function xmlToArray($xmlobject) {
$data = array();
foreach ((array)$xmlobject as $key => $value) {
$data[$key] = !is_string($value) ? xmlToArray($value) : $value;
}
return $data;
}

if ( strtolower($_SERVER['CONTENT_TYPE']) == 'application/xml' && $content = file_get_contents("php://input") ) {
$xml = simplexml_load_string($content);//转换post数据为simplexml对象
print_r(xmlToArray($xml));
}
待提交xml.xml文件内容:
<?xml version='1.0' encoding='UTF-8'?>
<root>
<site>
<name>爱E族</name>
<domain>aiezu.com</domain>
</site>
<site>
<name>天猫</name>
<domain>tmall.com</domain>
</site>
</root>
通过linux curl命令提交xml.xml:
[root@aiezu.com ~]# curl -H "Content-Type: application/xml" --data-binary @xml.xml http://aiezu.com/test.php
Array
(
[site] => Array
(
[0] => Array
(
[name] => 爱E族
[domain] => aiezu.com
)
[1] => Array
(
[name] => 天猫
[domain] => tmall.com
)
)
)
  

2、PHP使用"php://input"接收JSON数据:

  PHP使用"php://input"接收JSON数据,与接收XML数据十分类似,这里不再做介绍,要查看实例请参考:Linux curl命令get/post提交数据、json和文件全攻略 页面的第“”节。
 

3、PHP使用"php://input"接收文件内容:

  下面通过代码演示PHP使用"php://input"接收一个png文件,这里只是用于演示,实际运用中还是建议使用Http请求头"Content-Type"值为"multipart/form-data"的表单方式POST。
接收页面"test.php"代码:
<?php
if ( preg_match("#^image/(png|jpe?g|gif)$#i", $_SERVER['CONTENT_TYPE'], $match) && $binary = file_get_contents("php://input") ) {
$file = sprintf("/tmp/pic.%s", strtolower($match[1]));
file_put_contents($file, $binary);
echo sprintf("文件大小: %s\n", filesize($file));
echo sprintf("修改时间: %s\n", date("Y-m-d H:i:s", filemtime($file)));
}
提交测试:
[root@aiezu.com ~]# curl -H "Content-Type: image/png" --data-binary @logo.png http://aiezu.com/test.php
文件大小: 3706
修改时间: 2016-12-05 13:29:08

 三、附录:

PHP命令行输入输出流STDIN/STDOUT/STDERR用法

PHPliuliangsong 发表了文章 • 0 个评论 • 121 次浏览 • 2016-12-04 21:27 • 来自相关话题

一、PHP STDIN、STDOUT、STDERR简介:  STDIN、STDOUT、STDERR命令输入输出流,用于向控制台(linux shell终端、windows cmd终端)输入、输出内容,它们默认是已经打开的,可以直接对他们进行读写操作;

  它们只能在CLI(command-line interface,命令行界面)模式中使用,在Http模式时,它们是未定义的。而它们的打开副本php://stdin、php://stdout、php://stderr 也无法输出内容到http浏览器,经测试:写入php://stderr的内容将会输入到默认站点的错误日志中,其它两种无任何效果。

STDIN/STDOUT/STDERR简介:原始流流打开副本描述STDINphp://stdin标准输入(standard input),只读,用于从控制台输入内容;STDOUTphp://stdout标准输出(standard output),只写,用于向控制台输出正常信息;STDERRphp://stderr错误输出(standard error),只写,用于向控制台输出错误信息;  官方推荐使用常量 STDIN、 STDOUT 和 STDERR 来代替它们手动打开的副本封装器“php://stdin”、 “php://stdout” 和 “php://stderr”。下面我们代码演示它们的用法。
  二、PHP STDIN用法:  PHP语言中"STDIN"用于从控制台读取内容,遇到此常量或者通过fopen()函数打开“php://stdin”,脚本将会等待用户输入内容,直到用户按下回车键提交。
测试脚本test.php内容:<?php
echo "请输出站点名称: ";
$name = fgets(STDIN);
echo sprintf("输入的站点名称为: %s\n", $name);

$stdin = fopen('php://stdin', 'r');
echo "请输出域名: ";
$domain = fread($stdin, 128); //最多读取128个字符
echo sprintf("输入的域名为: %s\n", $domain);
fclose($stdin);运行结果:[root@aiezu.com ~]# php test.php
请输出站点名称: 爱E族
输入的站点名称为: 爱E族

请输出域名: aiezu.com
输入的域名为: aiezu.com 三、PHP STDOUT用法:  PHP语言中"STDOUT"用于向控制台输出标准信息;向此常量、或者向fopen()函数打开的"php://stdout"写入的内容将直接输出到控制台的标准输出;标准输出的内容可以用过">"或者"1>"重定向到指定地方,比如文件。
测试脚本test.php内容:<?php
fwrite(STDOUT, "我是通过STDOUT写入;\n");

$stdout = fopen("php://stdout", "w");
fwrite($stdout, "我是通过php://stdout写入;");
fclose($stdout);运行结果:[root@aiezu.com ~]# php test.php 1> test.out
[root@aiezu.com ~]# cat test.out
我是通过STDOUT写入;
我是通过php://stdout写入; 四、PHP STDERR用法:  PHP语言中"STDERR"用于向控制台输出错误信息;向此常量、或者向fopen()函数打开的"php://stderr"写入的内容将直接输出到控制台的错误输出;错误输出的内容可以用过"2>"重定向到指定地方,比如文件;也可以使用"2>&1"将错误输出定向到标准输出,与标准输出合并。
测试脚本test.php内容:<?php
fwrite(STDERR, "STDERR写入的错误输出;\n");

fwrite(STDOUT, "STDOUT写入的正常输出;\n");

$stderr = fopen("php://stdout", "w");
fwrite($stderr, "php://stderr写入的错误输出;\n");
fclose($stderr);正常输出和错误输出分别定向到不同文件:[root@aiezu.com ~]# php test.php 1>test.ok 2>test.err
[root@aiezu.com ~]# cat test.ok
STDOUT写入的正常输出;
php://stderr写入的错误输出;
[root@aiezu tmp]# cat test.err
STDERR写入的错误输出;正常输出和错误输出合并定向到统一文件:[root@aiezu.com ~]# php test.php 1>AllInOne 2>&1
[root@aiezu.com ~]# cat AllInOne
STDERR写入的错误输出;
STDOUT写入的正常输出;
php://stderr写入的错误输出;   四、附录:PHP 输入、输出流合集 查看全部

一、PHP STDIN、STDOUT、STDERR简介:

  STDINSTDOUTSTDERR命令输入输出流,用于向控制台(linux shell终端、windows cmd终端)输入、输出内容,它们默认是已经打开的,可以直接对他们进行读写操作;

  它们只能在CLI(command-line interface,命令行界面)模式中使用,在Http模式时,它们是未定义的。而它们的打开副本php://stdinphp://stdoutphp://stderr 也无法输出内容到http浏览器,经测试:写入php://stderr的内容将会输入到默认站点的错误日志中,其它两种无任何效果。

STDIN/STDOUT/STDERR简介:
原始流流打开副本描述
STDINphp://stdin标准输入(standard input),只读,用于从控制台输入内容;
STDOUTphp://stdout标准输出(standard output),只写,用于向控制台输出正常信息
STDERRphp://stderr错误输出(standard error),只写,用于向控制台输出错误信息
  官方推荐使用常量 STDIN、 STDOUT 和 STDERR 来代替它们手动打开的副本封装器“php://stdin”、 “php://stdout” 和 “php://stderr”。下面我们代码演示它们的用法。
  

二、PHP STDIN用法:

  PHP语言中"STDIN"用于从控制台读取内容,遇到此常量或者通过fopen()函数打开“php://stdin”,脚本将会等待用户输入内容,直到用户按下回车键提交。
测试脚本test.php内容:
<?php
echo "请输出站点名称: ";
$name = fgets(STDIN);
echo sprintf("输入的站点名称为: %s\n", $name);

$stdin = fopen('php://stdin', 'r');
echo "请输出域名: ";
$domain = fread($stdin, 128); //最多读取128个字符
echo sprintf("输入的域名为: %s\n", $domain);
fclose($stdin);
运行结果:
[root@aiezu.com ~]# php test.php 
请输出站点名称: 爱E族
输入的站点名称为: 爱E族

请输出域名: aiezu.com
输入的域名为: aiezu.com
 

三、PHP STDOUT用法:

  PHP语言中"STDOUT"用于向控制台输出标准信息;向此常量、或者向fopen()函数打开的"php://stdout"写入的内容将直接输出到控制台的标准输出;标准输出的内容可以用过">"或者"1>"重定向到指定地方,比如文件。
测试脚本test.php内容:
<?php
fwrite(STDOUT, "我是通过STDOUT写入;\n");

$stdout = fopen("php://stdout", "w");
fwrite($stdout, "我是通过php://stdout写入;");
fclose($stdout);
运行结果:
[root@aiezu.com ~]# php test.php 1> test.out
[root@aiezu.com ~]# cat test.out
我是通过STDOUT写入;
我是通过php://stdout写入;
 

四、PHP STDERR用法:

  PHP语言中"STDERR"用于向控制台输出错误信息;向此常量、或者向fopen()函数打开的"php://stderr"写入的内容将直接输出到控制台的错误输出;错误输出的内容可以用过"2>"重定向到指定地方,比如文件;也可以使用"2>&1"将错误输出定向到标准输出,与标准输出合并。
测试脚本test.php内容:
<?php
fwrite(STDERR, "STDERR写入的错误输出;\n");

fwrite(STDOUT, "STDOUT写入的正常输出;\n");

$stderr = fopen("php://stdout", "w");
fwrite($stderr, "php://stderr写入的错误输出;\n");
fclose($stderr);
正常输出和错误输出分别定向到不同文件:
[root@aiezu.com ~]# php test.php 1>test.ok 2>test.err
[root@aiezu.com ~]# cat test.ok
STDOUT写入的正常输出;
php://stderr写入的错误输出;
[root@aiezu tmp]# cat test.err
STDERR写入的错误输出;
正常输出和错误输出合并定向到统一文件:
[root@aiezu.com ~]# php test.php 1>AllInOne 2>&1
[root@aiezu.com ~]# cat AllInOne
STDERR写入的错误输出;
STDOUT写入的正常输出;
php://stderr写入的错误输出;
  

 四、附录:

CentOS使用Yum为PHP安装Xdebug调试神器

PHPlinyu520 发表了文章 • 0 个评论 • 96 次浏览 • 2016-11-17 22:10 • 来自相关话题

一、实验环境:操作系统:CentOS Linux release 7.2.1511 (Core)PHP版本:PHP 5.4.16 (cli) ,Yum方式安装Xdebug版本:2.2.7-1.el7 
  
二、安装前准备:
  不管是Lamp环境还是Lnmp环境,这里不讲述安装过程,这里只讲述Xdebug的安装。虽然使用yum方式安装Xdebug比较简单,但是还是建议在实验环境测试,安装前最好备份数据。
 
三、安装:
1、使用yum安装xdebug:[root@aiezu.com ~]# yum list|grep xdebug
php-pecl-xdebug.x86_64 2.2.7-1.el7 @epel
[root@aiezu.com ~]# yum install php-pecl-xdebug安装完成后,会生成“/etc/php.d/xdebug.ini”配置文件,配置文件中已经设置好xdebug的so文件,我们在这配置文件中设置xdebug设置参数。
 
四、配置Xdebug:
1、创建日志目录:
  我们创建/tmp/xdebug做为日志存储目录:[root@aiezu.com ~]# mkdir -p /tmp/xdebug
[root@aiezu.com ~]# chmod -R 777 /tmp/xdebug 
2、配置xdebug参数:
  修改“/etc/php.d/xdebug.ini”文件,根据你的需求配置参数,详细参数见附件中的《Xdebug详细参数表》。; Enable xdebug extension module
zend_extension=/usr/lib64/php/modules/xdebug.so

;启用代码自动跟踪
xdebug.auto_trace = On
;指定堆栈跟踪文件的存放目录
xdebug.trace_output_dir = /tmp/xdebug
;PHP代码跟踪日志文件名格式
xdebug.trace_output_name = trace.%c.%H
;启用性能检测分析
xdebug.profiler_enable=On
;允许收集传递给函数的参数变量
xdebug.collect_params= 4
;允许收集函数调用的返回值
xdebug.collect_return=On
;是否收集include、require的文件
xdebug.collect_includes = On
;是否收集内存的增加还是减少
;xdebug.show_mem_delta = On
;是否打印函数调用的最外围中的所有局部变量
;xdebug.show_local_vars = On
xdebug.profiler_enable = Off
;xdebug.profiler_output_dir = /tmp/xdebug
;xdebug.profiler_output_name = cachegrind.out.%H注:设置“xdebug.auto_trace = On”时,将会在执行所有PHP脚本之前先自动启用跟踪;另外,你也可以设置为“xdebug.auto_trace = 0”,并在PHP脚本开头和结尾分别调用xdebug_start_trace()和 xdebug_stop_trace()函数开启和结束跟踪。如:<?php
xdebug_start_trace();
//要追踪的代码
xdebug_stop_trace(); 
五、查看追踪日志:
  设置好配置文件后,并重启httpd服务,如果开启自动追踪,或者在脚本中使用xdebug_start_trace()和xdebug_stop_trace()函数开启追踪,那么在“/tmp/xdebug”命令下就可以看到追踪日志了。你可以使用vim查看他们,找出脚本中的问题。

附件:Xdebug详细参数表:选项名类型默认值参数选项描述xdebug.auto_tracebooleanOff是否在脚本运行之前自动调用相关追踪函数。xdebug.cli_colorinteger0如果值=1:
  当处于CLI模式或连接虚拟控制台时,Xdebug将高亮显示var_dumps()和堆栈输出;在Windows中,这需要安装ANSICON工具。
如果值=2:
  不管是否处于CLI模式或连接虚拟控制台,Xdebug都会高亮显示var_dumps()或堆栈输出;这种情况下,你可能会看到转义后的代码。
该参数自2.2版本开始引入。xdebug.collect_assignmentsbooleanOff用于控制是否为函数跟踪添加变量赋值功能。
该参数自2.1版本开始引入。xdebug.collect_includesbooleanOn控制是否在跟踪文件中写入include()、include_once()、require()、require_once()等函数中用到的文件名。xdebug.collect_paramsinteger0控制在调用函数时,是否收集传递给函数的参数信息。
  如果值=0,则不显示任何信息。
  如果值=1,只显示类型和大小信息,例如:string(6)、array(8)。
  如果值=2,将显示类型和大小,以及全部信息的工具提示。
  如果值=3,将显示变量的全部内容。
  如果值=4,将显示变量的全部内容和变量名。
如果参数值过大,这可能会占用大量的内存;不过,在Xdebug 2中不会出现该问题,因为Xdebug 2将相关数据写入磁盘中,而不是占用内存。xdebug.collect_returnbooleanOff控制是否在追踪文件中写入函数调用的返回值。xdebug.collect_varsbooleanOff控制是否收集指定作用域中的变量信息。由于需要反向工程PHP的操作码数组,因此Xdebug的分析速度可能比较慢。xdebug.coverage_enablebooleanOn控制是否允许通过设置内部结构来启用代码覆盖率功能。
该参数自2.2版本开始引入。xdebug.default_enablebooleanOn当发生异常或错误时,是否默认显示堆栈信息。xdebug.dump.*stringEmpty这里的*可以是COOKIE, FILES, GET, POST, REQUEST, SERVER, SESSION中的任意一个。用于指定发生错误时是否显示超全局变量数组中的索引变量信息。比如,你想要显示请求的IP地址和请求方式,可以设置为xdebug.dump.SERVER=REMOTE_ADD,REQUEST_METHOD多个索引变量用英文逗号隔开,如果要输出其中的所有变量,可以直接用*,例如:xdebug.dump.GET=*xdebug.dump_globalsbooleanOn控制是否显示通过xdebug.dump.*定义的所有超全局变量的信息。xdebug.dump_oncebooleanOn如果出现多个错误,控制超全局变量信息是在所有错误中显示,还是只在第一个错误中显示。xdebug.dump_undefinedbooleanOn控制是否显示超全局变量中未定义的值。xdebug.extended_infointeger1是否强制进入PHP解析器的"extended_info"模式,这将允许Xdebug以远程调试器对文件或行添加断点。开启此模式将拖慢脚本的允许速度,该参数只能在php.ini中设置。xdebug.file_link_formatstring,用于指定堆栈信息中用到的文件名称的链接样式,这允许IDE通过设置链接协议,直接点击堆栈信息中的文件名称,即可快速打开指定的文件。
例如:ZendStudio://%f@%l(%f表示文件路径,%f表示行号)。
自2.2版本开始引入。xdebug.force_display_errorsinteger0是否强制显示错误信息。
自2.3版本开始引入。xdebug.force_error_reportinginteger0是否强制显示所有错误级别的信息。
自2.3版本开始引入。xdebug.halt_levelinteger0指定出现那些错误级别的错误时,中止程序运行。例如:xdebug.halt_level=E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE(也仅支持上述4种错误级别)。
自2.3版本开始引入。xdebug.idekeystring*complex*指定传递给DBGp调试器处理程序的IDE Key。xdebug.manual_urlstringhttp://www.php.net用于指定从函数堆栈和错误信息链接到的帮助手册的基本URL。
仅2.2.1以下版本可用。xdebug.max_nesting_levelinteger100指定递归的嵌套层级数。xdebug.overload_var_dumpbooleanOn当php.ini中的html_error设为1时,Xdebug是否默认使用自身的改进版本来重载var_dump()。
自2.2版本开始引入。xdebug.profiler_appendinteger0当多个请求映射到相同文件时,指定是覆盖之前的调试信息文件还是追加内容到该文件中。xdebug.profiler_enableinteger0指定是否启用Xdebug的性能分析,并创建性能信息文件。xdebug.profiler_output_dirstring/tmp指定性能分析信息文件的输出目录xdebug.profiler_output_namestringcachegrind.out.%p

 指定性能分析信息文件的名称xdebug.remote_enablebooleanOff是否开启远程调试xdebug.remote_handlerstringdbgp指定远程调试的处理协议xdebug.remote_hoststringlocalhost指定远程调试的主机名xdebug.remote_logstring 指定远程调试的日志文件名xdebug.remote_modestringreq可以设为req或jit,req表示脚本一开始运行就连接远程客户端,jit表示脚本出错时才连接远程客户端。xdebug.remote_portinteger9000指定远程调试的端口号xdebug.trace_optionsinteger0指定对于之后的请求,追踪文件是追加内容还是覆盖之前内容。xdebug.trace_output_dirstring/tmp指定追踪文件的存放目录xdebug.trace_output_namestringtrace.%c指定追踪文件的名称xdebug.show_exception_tracebooleanOff是否开启异常跟踪xdebug.show_mem_deltabooleanOff是否追踪内存的变化xdebug.show_local_varsbooleanOff是否显示局部变量  查看全部
一、实验环境:
  • 操作系统:CentOS Linux release 7.2.1511 (Core)
  • PHP版本:PHP 5.4.16 (cli) ,Yum方式安装
  • Xdebug版本:2.2.7-1.el7 

  
二、安装前准备:
  不管是Lamp环境还是Lnmp环境,这里不讲述安装过程,这里只讲述Xdebug的安装。虽然使用yum方式安装Xdebug比较简单,但是还是建议在实验环境测试,安装前最好备份数据。
 
三、安装:
1、使用yum安装xdebug:
[root@aiezu.com ~]# yum list|grep xdebug
php-pecl-xdebug.x86_64 2.2.7-1.el7 @epel
[root@aiezu.com ~]# yum install php-pecl-xdebug
安装完成后,会生成“/etc/php.d/xdebug.ini”配置文件,配置文件中已经设置好xdebug的so文件,我们在这配置文件中设置xdebug设置参数。
 
四、配置Xdebug:
1、创建日志目录:
  我们创建/tmp/xdebug做为日志存储目录:
[root@aiezu.com ~]# mkdir -p /tmp/xdebug
[root@aiezu.com ~]# chmod -R 777 /tmp/xdebug
 
2、配置xdebug参数:
  修改“/etc/php.d/xdebug.ini”文件,根据你的需求配置参数,详细参数见附件中的《Xdebug详细参数表》。
; Enable xdebug extension module
zend_extension=/usr/lib64/php/modules/xdebug.so

;启用代码自动跟踪
xdebug.auto_trace = On
;指定堆栈跟踪文件的存放目录
xdebug.trace_output_dir = /tmp/xdebug
;PHP代码跟踪日志文件名格式
xdebug.trace_output_name = trace.%c.%H
;启用性能检测分析
xdebug.profiler_enable=On
;允许收集传递给函数的参数变量
xdebug.collect_params= 4
;允许收集函数调用的返回值
xdebug.collect_return=On
;是否收集include、require的文件
xdebug.collect_includes = On
;是否收集内存的增加还是减少
;xdebug.show_mem_delta = On
;是否打印函数调用的最外围中的所有局部变量
;xdebug.show_local_vars = On
xdebug.profiler_enable = Off
;xdebug.profiler_output_dir = /tmp/xdebug
;xdebug.profiler_output_name = cachegrind.out.%H
注:设置“xdebug.auto_trace = On”时,将会在执行所有PHP脚本之前先自动启用跟踪;另外,你也可以设置为“xdebug.auto_trace = 0”,并在PHP脚本开头和结尾分别调用xdebug_start_trace()和 xdebug_stop_trace()函数开启和结束跟踪。如:
<?php
xdebug_start_trace();
//要追踪的代码
xdebug_stop_trace();
 
五、查看追踪日志:
  设置好配置文件后,并重启httpd服务,如果开启自动追踪,或者在脚本中使用xdebug_start_trace()和xdebug_stop_trace()函数开启追踪,那么在“/tmp/xdebug”命令下就可以看到追踪日志了。你可以使用vim查看他们,找出脚本中的问题。

附件:Xdebug详细参数表:
选项名类型默认值参数选项描述
xdebug.auto_tracebooleanOff是否在脚本运行之前自动调用相关追踪函数。
xdebug.cli_colorinteger0如果值=1:
  当处于CLI模式或连接虚拟控制台时,Xdebug将高亮显示var_dumps()和堆栈输出;在Windows中,这需要安装ANSICON工具。
如果值=2:
  不管是否处于CLI模式或连接虚拟控制台,Xdebug都会高亮显示var_dumps()或堆栈输出;这种情况下,你可能会看到转义后的代码。
该参数自2.2版本开始引入。
xdebug.collect_assignmentsbooleanOff用于控制是否为函数跟踪添加变量赋值功能。
该参数自2.1版本开始引入。
xdebug.collect_includesbooleanOn控制是否在跟踪文件中写入include()、include_once()、require()、require_once()等函数中用到的文件名。
xdebug.collect_paramsinteger0控制在调用函数时,是否收集传递给函数的参数信息。
  如果值=0,则不显示任何信息。
  如果值=1,只显示类型和大小信息,例如:string(6)、array(8)。
  如果值=2,将显示类型和大小,以及全部信息的工具提示。
  如果值=3,将显示变量的全部内容。
  如果值=4,将显示变量的全部内容和变量名。
如果参数值过大,这可能会占用大量的内存;不过,在Xdebug 2中不会出现该问题,因为Xdebug 2将相关数据写入磁盘中,而不是占用内存。
xdebug.collect_returnbooleanOff控制是否在追踪文件中写入函数调用的返回值。
xdebug.collect_varsbooleanOff控制是否收集指定作用域中的变量信息。由于需要反向工程PHP的操作码数组,因此Xdebug的分析速度可能比较慢。
xdebug.coverage_enablebooleanOn控制是否允许通过设置内部结构来启用代码覆盖率功能。
该参数自2.2版本开始引入。
xdebug.default_enablebooleanOn当发生异常或错误时,是否默认显示堆栈信息。
xdebug.dump.*stringEmpty这里的*可以是COOKIE, FILES, GET, POST, REQUEST, SERVER, SESSION中的任意一个。用于指定发生错误时是否显示超全局变量数组中的索引变量信息。比如,你想要显示请求的IP地址和请求方式,可以设置为xdebug.dump.SERVER=REMOTE_ADD,REQUEST_METHOD多个索引变量用英文逗号隔开,如果要输出其中的所有变量,可以直接用*,例如:xdebug.dump.GET=*
xdebug.dump_globalsbooleanOn控制是否显示通过xdebug.dump.*定义的所有超全局变量的信息。
xdebug.dump_oncebooleanOn如果出现多个错误,控制超全局变量信息是在所有错误中显示,还是只在第一个错误中显示。
xdebug.dump_undefinedbooleanOn控制是否显示超全局变量中未定义的值。
xdebug.extended_infointeger1是否强制进入PHP解析器的"extended_info"模式,这将允许Xdebug以远程调试器对文件或行添加断点。开启此模式将拖慢脚本的允许速度,该参数只能在php.ini中设置。
xdebug.file_link_formatstring,用于指定堆栈信息中用到的文件名称的链接样式,这允许IDE通过设置链接协议,直接点击堆栈信息中的文件名称,即可快速打开指定的文件。
例如:ZendStudio://%f@%l(%f表示文件路径,%f表示行号)。
自2.2版本开始引入。
xdebug.force_display_errorsinteger0是否强制显示错误信息。
自2.3版本开始引入。
xdebug.force_error_reportinginteger0是否强制显示所有错误级别的信息。
自2.3版本开始引入。
xdebug.halt_levelinteger0指定出现那些错误级别的错误时,中止程序运行。例如:xdebug.halt_level=E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE(也仅支持上述4种错误级别)。
自2.3版本开始引入。
xdebug.idekeystring*complex*指定传递给DBGp调试器处理程序的IDE Key。
xdebug.manual_urlstringhttp://www.php.net用于指定从函数堆栈和错误信息链接到的帮助手册的基本URL。
仅2.2.1以下版本可用。
xdebug.max_nesting_levelinteger100指定递归的嵌套层级数。
xdebug.overload_var_dumpbooleanOn当php.ini中的html_error设为1时,Xdebug是否默认使用自身的改进版本来重载var_dump()。
自2.2版本开始引入。
xdebug.profiler_appendinteger0当多个请求映射到相同文件时,指定是覆盖之前的调试信息文件还是追加内容到该文件中。
xdebug.profiler_enableinteger0指定是否启用Xdebug的性能分析,并创建性能信息文件。
xdebug.profiler_output_dirstring/tmp指定性能分析信息文件的输出目录
xdebug.profiler_output_namestringcachegrind.out.%p

 
指定性能分析信息文件的名称
xdebug.remote_enablebooleanOff是否开启远程调试
xdebug.remote_handlerstringdbgp指定远程调试的处理协议
xdebug.remote_hoststringlocalhost指定远程调试的主机名
xdebug.remote_logstring 指定远程调试的日志文件名
xdebug.remote_modestringreq可以设为req或jit,req表示脚本一开始运行就连接远程客户端,jit表示脚本出错时才连接远程客户端。
xdebug.remote_portinteger9000指定远程调试的端口号
xdebug.trace_optionsinteger0指定对于之后的请求,追踪文件是追加内容还是覆盖之前内容。
xdebug.trace_output_dirstring/tmp指定追踪文件的存放目录
xdebug.trace_output_namestringtrace.%c指定追踪文件的名称
xdebug.show_exception_tracebooleanOff是否开启异常跟踪
xdebug.show_mem_deltabooleanOff是否追踪内存的变化
xdebug.show_local_varsbooleanOff是否显示局部变量 

PHP魔术方法合集

PHPlinyu520 发表了文章 • 0 个评论 • 52 次浏览 • 2016-11-17 13:28 • 来自相关话题

  PHP 将所有以“__”(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以“__”为前缀。魔术方法描述__construct()初始化一个对象时触发;__destruct()对象销毁,或者脚本执行完时触发;__autoload()当使用一个不可访问的类时触发;__clone()对象被克隆时触发;__get()获取一个不可访问(属性不存在、或者无权限)的属性时触发;__set()为一个不可访问的属性赋值的时候触发;__isset()当用isset()函数判断一个不可访问的属性时触发;__unset()当用unset()函数操作一个不可访问的属性时触发;__call()当调用一个不可访问的方法时触发;__callStatic()当调用一个不可访问的静态方法时触发;__toString()当一个对象被当做字符串来操作时触发;
如$obj是一个对象,echo $obj,就会触发__toString();__invoke()当一个对象被当做函数来使用时触发;
如$obj是一个对象,$obj()就会触发__invoke();__sleep()在将使用serialize时触发;__wakeup()在使用unserialize后触发;__set_state()当调用var_export()导出类时触发(PHP 5.1.0起);__debugInfo() 当调用var_dump()导出一个对象时调用(PHP 5.6.0起); 
用法演示:
1、__autoload()魔术方法:
__autoload()是我们最为常用的魔术方法,常常用于自定加载类文件,做到按需加载:<?php
//爱E族 aiezu.com
function __autoload($class) {
if (class_exists($class, false)) return;
$file = sprintf("./class/%s.php", str_replace('_', DIRECTORY_SEPARATOR, $class));
require_once($file);
}
// 当类Core_Db不存在时,自动引入类文件:./class/Core/Db.php
$db = new Core_Db(); 
2、__debugInfo()魔术方法:
<?php
class Aiezu {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function __debugInfo() {
return array('SiteName'=> $this->name);
}
}
var_dump(new Aiezu('爱E族'));​PHP 5.6.0以下版本运行结果:object(Aiezu)#1 (1) {
["name":"Aiezu":private]=>
string(7) "爱E族"
}PHP 5.6.0以上版本运行结果:object(Aiezu)#1 (1) {
["SiteName"]=>
string(7) "爱E族"

3、__sleep()魔术方法:<?php
class Aiezu {
private $name;
private $url = 'aiezu.com';
public function __construct($name) {
$this->name = $name;
}
public function __sleep() {
return array('url'); //指定要序列化的属性列表
}
}
echo serialize(new Aiezu('爱E族'));输出:O:5:"Aiezu":1:{s:10:"Aiezuurl";s:9:"aiezu.com";} 查看全部
  PHP 将所有以“__”(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以“__”为前缀。
魔术方法描述
__construct()初始化一个对象时触发;
__destruct()对象销毁,或者脚本执行完时触发;
__autoload()当使用一个不可访问的类时触发;
__clone()对象被克隆时触发;
__get()获取一个不可访问(属性不存在、或者无权限)的属性时触发;
__set()为一个不可访问的属性赋值的时候触发;
__isset()当用isset()函数判断一个不可访问的属性时触发;
__unset()当用unset()函数操作一个不可访问的属性时触发;
__call()当调用一个不可访问的方法时触发;
__callStatic()当调用一个不可访问的静态方法时触发;
__toString()当一个对象被当做字符串来操作时触发;
如$obj是一个对象,echo $obj,就会触发__toString();
__invoke()当一个对象被当做函数来使用时触发;
如$obj是一个对象,$obj()就会触发__invoke();
__sleep()在将使用serialize时触发;
__wakeup()在使用unserialize后触发;
__set_state()当调用var_export()导出类时触发(PHP 5.1.0起);
__debugInfo() 当调用var_dump()导出一个对象时调用(PHP 5.6.0起);
 
用法演示:
1、__autoload()魔术方法:
__autoload()是我们最为常用的魔术方法,常常用于自定加载类文件,做到按需加载:
<?php
//爱E族 aiezu.com
function __autoload($class) {
if (class_exists($class, false)) return;
$file = sprintf("./class/%s.php", str_replace('_', DIRECTORY_SEPARATOR, $class));
require_once($file);
}
// 当类Core_Db不存在时,自动引入类文件:./class/Core/Db.php
$db = new Core_Db();
 
2、__debugInfo()魔术方法:
<?php
class Aiezu {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function __debugInfo() {
return array('SiteName'=> $this->name);
}
}
var_dump(new Aiezu('爱E族'));
​PHP 5.6.0以下版本运行结果:
object(Aiezu)#1 (1) {
["name":"Aiezu":private]=>
string(7) "爱E族"
}
PHP 5.6.0以上版本运行结果:
object(Aiezu)#1 (1) {
["SiteName"]=>
string(7) "爱E族"
}
 
3、__sleep()魔术方法:
<?php
class Aiezu {
private $name;
private $url = 'aiezu.com';
public function __construct($name) {
$this->name = $name;
}
public function __sleep() {
return array('url'); //指定要序列化的属性列表
}
}
echo serialize(new Aiezu('爱E族'));
输出:
O:5:"Aiezu":1:{s:10:"Aiezuurl";s:9:"aiezu.com";}

PHP判断键名是否存在的方法

回复

PHP匿名用户 回复了问题 • 1 人关注 • 1 个回复 • 45 次浏览 • 2016-11-17 00:08 • 来自相关话题

PHP自定义异常处理函数

PHPlinyu520 发表了文章 • 0 个评论 • 55 次浏览 • 2016-11-16 13:56 • 来自相关话题

  我们常需要根据项目的不同,对代码运行日志记录有不同的需求。这不同的需求包含,需要记录的内容不同、记录的格式不同、日志的输出方式(写如文件、发EMail、发短信等)不同。这时,我们可以将自己的日志记录需求实现方法定义到一个类中,然后再通过下面这些函数,将类的方法注册到对应的事件,这样当事件发生时,系统自定会按我们的需求将日志记录到指定的地方。

一、register_shutdown_function函数:
  register_shutdown_function()函数用来设置当PHP脚本执行完成、或者exit()退出时要调用的函数。register_shutdown_function(array('Err','shutdown_function'));  
二、set_error_handler函数:
  set_error_handler函数使用来设置脚本发生错误时调用的函数,用法如下:set_error_handler(array('Err','error_handler'));通过 set_error_handler() 函数设置用户自定义的错误处理程序,然后触发错误(通过 trigger_error()):

三、set_exception_handler函数:set_exception_handler(array('Err','appException'));
简单示例:<?php
date_default_timezone_set('PRC');
register_shutdown_function(array('Err','successHandle'));
set_error_handler(array('Err','errorHandler'));
set_exception_handler(array('Err','exceptionHandle'));
class Err {
private static $logFile = 'log.txt';
//脚本发生错误
public static function errorHandler($errno, $errstr, $errfile, $errline){
$msg = sprintf("Error: %s %s %s:%s", $errno, $errstr, $errfile, $errline);
self::writeLog($msg);
}

//脚本执行完成
public static function successHandle() {
self::writeLog("Success.");
}

//脚本抛出异常
public static function exceptionHandle($exception) {
$msg = sprintf("Exception: %s", $exception->getMessage());
self::writeLog($msg);
}

//写日志
private static function writeLog( $msg ) {
$msg = sprintf("%s %s\t%s\n", date('Y-m-d H:i:s'), $_SERVER['REMOTE_ADDR'], $msg);
file_put_contents(self::$logFile, $msg, FILE_APPEND);
}
}

throw new Exception("发生异常啦"); 查看全部
  我们常需要根据项目的不同,对代码运行日志记录有不同的需求。这不同的需求包含,需要记录的内容不同、记录的格式不同、日志的输出方式(写如文件、发EMail、发短信等)不同。这时,我们可以将自己的日志记录需求实现方法定义到一个类中,然后再通过下面这些函数,将类的方法注册到对应的事件,这样当事件发生时,系统自定会按我们的需求将日志记录到指定的地方。

一、register_shutdown_function函数:
  register_shutdown_function()函数用来设置当PHP脚本执行完成、或者exit()退出时要调用的函数。
register_shutdown_function(array('Err','shutdown_function'));
  
二、set_error_handler函数:
  set_error_handler函数使用来设置脚本发生错误时调用的函数,用法如下:
set_error_handler(array('Err','error_handler'));
通过 set_error_handler() 函数设置用户自定义的错误处理程序,然后触发错误(通过 trigger_error()):

三、set_exception_handler函数:
set_exception_handler(array('Err','appException'));

简单示例:
<?php
date_default_timezone_set('PRC');
register_shutdown_function(array('Err','successHandle'));
set_error_handler(array('Err','errorHandler'));
set_exception_handler(array('Err','exceptionHandle'));
class Err {
private static $logFile = 'log.txt';
//脚本发生错误
public static function errorHandler($errno, $errstr, $errfile, $errline){
$msg = sprintf("Error: %s %s %s:%s", $errno, $errstr, $errfile, $errline);
self::writeLog($msg);
}

//脚本执行完成
public static function successHandle() {
self::writeLog("Success.");
}

//脚本抛出异常
public static function exceptionHandle($exception) {
$msg = sprintf("Exception: %s", $exception->getMessage());
self::writeLog($msg);
}

//写日志
private static function writeLog( $msg ) {
$msg = sprintf("%s %s\t%s\n", date('Y-m-d H:i:s'), $_SERVER['REMOTE_ADDR'], $msg);
file_put_contents(self::$logFile, $msg, FILE_APPEND);
}
}

throw new Exception("发生异常啦");

PHP fwrite 与 file_put_contents 两个函数的区别

PHPlinyu520 发表了文章 • 0 个评论 • 78 次浏览 • 2016-11-16 11:00 • 来自相关话题

一、fwrite函数和file_put_contents函数的区别:
  fwrite()函数和file_put_contents()函数都是将字符串写入到文件,但它们又有一定区别,具体如下表:函数名功能简介fwrite()将字符串写入或追加到文件中;
写入文件前,需使用fopen()函数打开文件,
写入文件后,需使用fclose()函数关闭文件。file_put_contents()将字符串写入或追加到文件中;
函数会自动执行打开文件、写入文件、关闭文件操作。 
二、写入文件演示:
1、使用fwrite函数将字符串写入文件:<?php
//以从文件头开始写入的方式打开文件,会覆盖文件原有的内容
$handle = fopen('a.txt', 'w');
$num = fwrite($handle, "爱E族\n");
fclose($handle);
echo $num; //输出:8(汉字为3字节,E和换行符各一个字节) 
2、使用file_put_contents函数将字符串写入到文件:<?php
$num = file_put_contents('b.txt', "爱E族\n");
echo $num; // 输出:8 
三、追加文件演示:
1、使用fwrite函数追加文件:<?php
//以追加的方式打开文件,将文件尾部开始写入,不会覆盖原有内容
$handle = fopen('a.txt', 'a');
$num = fwrite($handle, "Aiezu.com\n");
fclose($handle);
echo $num; //输出:10 
2、使用file_put_contents函数追加文件:<?php
// LOCK_EX: 写文件的时候先锁定,防止多人同时写入造成内容丢失
$num = file_put_contents('b.txt', "Aiezu.com\n", FILE_APPEND|LOCK_EX);
echo $num; // 输出:10 
四、性能比较:
1、写入性能比较:<?php
$num = 1000;

$start = microtime(true);
for($i=1; $i<=$num; $i++) {
file_put_contents('b.txt', "Aiezu.com\n");
}
$time = microtime(true)-$start;
echo sprintf("file_put_contents函数写入%d次耗时%.3f秒\n", $num, $time);


$start = microtime(true);
for($i=1; $i<=$num; $i++) {
$handle = fopen('a.txt', "w");
fwrite($handle, "Aiezu.com\n");
fclose($handle);
}
$time = microtime(true)-$start;
echo sprintf("fwrite函数写入%d次耗时%.3f秒\n", $num, $time);输出:file_put_contents函数写入1000次耗时0.994秒
fwrite函数写入1000次耗时1.108秒
本例可以看出,对于覆写文件内容,file_put_contents函数会比fwrite函数稍快。
2、追加内容性能比较:<?php
$num = 100000;

$start = microtime(true);
for($i=1; $i<=$num; $i++) {
file_put_contents('a.txt', "爱E族", FILE_APPEND);
}
$time = microtime(true)-$start;
echo sprintf("file_put_contents函数追加内容%d次耗时%.3f秒\n", $num, $time);

$start = microtime(true);
for($i=1; $i<=$num; $i++) {
$handle = fopen('b.txt', "a");
fwrite($handle, "爱E族");
fclose($handle);
}
$time = microtime(true)-$start;
echo sprintf("fwrite一次打开追加内容一次,重复%d次耗时%.3f秒\n", $num, $time);

$start = microtime(true);
$handle = fopen('c.txt', "a");
for($i=1; $i<=$num; $i++) {
fwrite($handle, "爱E族");
}
fclose($handle);
$time = microtime(true)-$start;
echo sprintf("fwrite一次打开,追加内容%d次耗时%.3f秒\n", $num, $time);输出:file_put_contents函数追加内容100000次耗时0.765秒
fwrite一次打开追加内容一次,重复100000次耗时0.580秒
fwrite一次打开,追加内容100000次耗时0.112秒  本例可以看出,对于追加文件内容来说,fwrite函数比file_put_contents函数快很多,如果是fwrite一次打开写入多次,那更是快很多倍。
  通过上面两例,发现更令人惊奇的一点,两个函数的追加内容比覆写内容,快近百倍,这是为什么呢?大家可以亲自测一下。
 
五、总结:
  写入少量内容,单次写入,我们建议使用file_put_contents函数、一行代码,简单方便,性能也不错。对于连续写入多次,或者写入大块内容,建议使用fwrite函数配合其他函数,使用二进制流的方式,边读边写,减少内存占用。 查看全部
一、fwrite函数和file_put_contents函数的区别:
  fwrite()函数和file_put_contents()函数都是将字符串写入到文件,但它们又有一定区别,具体如下表:
函数名功能简介
fwrite()将字符串写入或追加到文件中;
写入文件前,需使用fopen()函数打开文件,
写入文件后,需使用fclose()函数关闭文件。
file_put_contents()将字符串写入或追加到文件中;
函数会自动执行打开文件、写入文件、关闭文件操作。
 
二、写入文件演示:
1、使用fwrite函数将字符串写入文件:
<?php
//以从文件头开始写入的方式打开文件,会覆盖文件原有的内容
$handle = fopen('a.txt', 'w');
$num = fwrite($handle, "爱E族\n");
fclose($handle);
echo $num; //输出:8(汉字为3字节,E和换行符各一个字节)
 
2、使用file_put_contents函数将字符串写入到文件:
<?php
$num = file_put_contents('b.txt', "爱E族\n");
echo $num; // 输出:8
 
三、追加文件演示:
1、使用fwrite函数追加文件:
<?php
//以追加的方式打开文件,将文件尾部开始写入,不会覆盖原有内容
$handle = fopen('a.txt', 'a');
$num = fwrite($handle, "Aiezu.com\n");
fclose($handle);
echo $num; //输出:10
 
2、使用file_put_contents函数追加文件:
<?php
// LOCK_EX: 写文件的时候先锁定,防止多人同时写入造成内容丢失
$num = file_put_contents('b.txt', "Aiezu.com\n", FILE_APPEND|LOCK_EX);
echo $num; // 输出:10
 
四、性能比较:
1、写入性能比较:
<?php
$num = 1000;

$start = microtime(true);
for($i=1; $i<=$num; $i++) {
file_put_contents('b.txt', "Aiezu.com\n");
}
$time = microtime(true)-$start;
echo sprintf("file_put_contents函数写入%d次耗时%.3f秒\n", $num, $time);


$start = microtime(true);
for($i=1; $i<=$num; $i++) {
$handle = fopen('a.txt', "w");
fwrite($handle, "Aiezu.com\n");
fclose($handle);
}
$time = microtime(true)-$start;
echo sprintf("fwrite函数写入%d次耗时%.3f秒\n", $num, $time);
输出:
file_put_contents函数写入1000次耗时0.994秒
fwrite函数写入1000次耗时1.108秒

本例可以看出,对于覆写文件内容,file_put_contents函数会比fwrite函数稍快。
2、追加内容性能比较:
<?php
$num = 100000;

$start = microtime(true);
for($i=1; $i<=$num; $i++) {
file_put_contents('a.txt', "爱E族", FILE_APPEND);
}
$time = microtime(true)-$start;
echo sprintf("file_put_contents函数追加内容%d次耗时%.3f秒\n", $num, $time);

$start = microtime(true);
for($i=1; $i<=$num; $i++) {
$handle = fopen('b.txt', "a");
fwrite($handle, "爱E族");
fclose($handle);
}
$time = microtime(true)-$start;
echo sprintf("fwrite一次打开追加内容一次,重复%d次耗时%.3f秒\n", $num, $time);

$start = microtime(true);
$handle = fopen('c.txt', "a");
for($i=1; $i<=$num; $i++) {
fwrite($handle, "爱E族");
}
fclose($handle);
$time = microtime(true)-$start;
echo sprintf("fwrite一次打开,追加内容%d次耗时%.3f秒\n", $num, $time);
输出:
file_put_contents函数追加内容100000次耗时0.765秒
fwrite一次打开追加内容一次,重复100000次耗时0.580秒
fwrite一次打开,追加内容100000次耗时0.112秒
  本例可以看出,对于追加文件内容来说,fwrite函数比file_put_contents函数快很多,如果是fwrite一次打开写入多次,那更是快很多倍。
  通过上面两例,发现更令人惊奇的一点,两个函数的追加内容比覆写内容,快近百倍,这是为什么呢?大家可以亲自测一下。
 
五、总结:
  写入少量内容,单次写入,我们建议使用file_put_contents函数、一行代码,简单方便,性能也不错。对于连续写入多次,或者写入大块内容,建议使用fwrite函数配合其他函数,使用二进制流的方式,边读边写,减少内存占用。

PHP array_udiff_uassoc 函数

PHPllslx520 发表了文章 • 0 个评论 • 65 次浏览 • 2016-11-14 14:25 • 来自相关话题

一、函数功能:
  计算出第一个数组与其他数组的差集(考虑键名和键值,对键名和键值的比较都使用自定义函数)。比较两到多个数组,找出第一个数组中不包含在其他任何数组中的键/值对。此函数键值比较和键名比较都使用用户自定义函数。关于计算差集系列函数的区别请参考:PHP数组计算差集系列函数的区别。

二、函数语法:array array_udiff_uassoc($array1 , $array2[, $...], $user_value_compare_func, $user_key_compare_func)
三、函数参数:参数名描述$array1参与比较的第一个数组;$array2参与比较的第二个数组;...参与比较的更多数组;$user_value_compare_func用户自定义回调函数,用来比较键值。如果认为第一个键值小于,等于,或大于第二个键值时必须分别返回一个小于零,等于零,或大于零的整数。只有键名比较返回0,对应的键值才会传递给此自定义函数比较。$user_key_compare_func用户自定义回调函数,用来比较键名。如果认为第一个键名小于,等于,或大于第二个键名时必须分别返回一个小于零,等于零,或大于零的整数。 
四、返回值:返回第一个数组与其他数组的键名/键值对差集组成的数组。
五、用法举例:
1、array_udiff_uassoc 函数工作流程解析:
  大体分为3步:1、每个数组key的排序去重;2、判断第一个数组的key是否与其他数组的key相等,如果相等返回0,然后执行第3步;3、判断第2步相等的key对应的值是否相等,相等返回0,此key和对应的值不会再出现在返回数组中,执行第1步比较下一对key。<?php
function user_key_compare_func($k1, $k2) {
echo sprintf("debug key: %s vs %s %s\n", $k1, $k2, $k1===$k2 ? 0 : ($k1>$k2?1:-1) ); //debug行
if ( $k1 === $k2 ) {
return 0;
}
return $k1 > $k2 ? 1 : -1;
}

function user_value_compare_func($v1, $v2) {
echo sprintf("debug value: %s vs %s %s\n", $v1, $v2, $v1===$v2 ? 0 : ($v1>$v2?1:-1) ); //debug行
if ( $v1 === $v2 ) {
return 0;
}
return $v1 > $v2 ? 1 : -1;
}

$arr1 = array('爱E族', 'aiezu', 'b'=>'bb',);
$arr2 = array('name'=>'爱E族', 'b'=>'bb', 'aiezu');

$result = array_udiff_uassoc($arr1, $arr2, "user_value_compare_func", "user_key_compare_func");
print_r($result);输出:debug key: 1 vs 0 1 #$arr1的key排序去重
debug key: b vs 1 -1
debug key: 0 vs b -1 #$arr2的key排序去重
debug key: b vs name -1

debug key: 0 vs b -1 #key不相等
debug key: 0 vs 0 0 #key相等,下步比较key对应的键值
debug value: 爱E族 vs aiezu 1 #key对应的键值不相等,key:0,value:爱E族会出现在返回数组中
debug key: b vs 0 -1
debug key: b vs b 0 #key相等,下步比较key对应的键值
debug value: bb vs bb 0 #key对应的键值也相等,$arr1中键b和对应的键值bb不会出现在返回数组中
debug key: 1 vs 0 1
debug key: 1 vs b 1
debug key: 1 vs name 1
Array
(
[0] => 爱E族
[1] => aiezu
)
2、使用类函数作为键值和键名比较函数,找出三个数组的差集:<?php
class user {
function key_compare($k1, $k2) {
if ( $k1 === $k2 ) {
return 0;
}
return $k1 > $k2 ? 1 : -1;
}
function value_compare($v1, $v2) {
if ( $v1 === $v2 ) {
return 0;
}
return $v1 > $v2 ? 1 : -1;
}
}
$arr1 = array('爱E族', 'aiezu', 'b'=>'bb',);
$arr2 = array('name'=>'爱E族', 'b'=>'bb', 'aiezu');
$arr3 = array('1'=>'aiezu');
$result = array_udiff_uassoc($arr1, $arr2, $arr3, array("user", "value_compare"), array("user", "key_compare"));
print_r($result);输出:Array
(
[0] => 爱E族
) 查看全部
一、函数功能:
  计算出第一个数组与其他数组的差集(考虑键名和键值,对键名和键值的比较都使用自定义函数)。比较两到多个数组,找出第一个数组中不包含在其他任何数组中的键/值对。此函数键值比较和键名比较都使用用户自定义函数。关于计算差集系列函数的区别请参考:PHP数组计算差集系列函数的区别

二、函数语法:
array array_udiff_uassoc($array1 , $array2[, $...], $user_value_compare_func, $user_key_compare_func)

三、函数参数:
参数名描述
$array1参与比较的第一个数组;
$array2参与比较的第二个数组;
...参与比较的更多数组;
$user_value_compare_func用户自定义回调函数,用来比较键值。如果认为第一个键值小于,等于,或大于第二个键值时必须分别返回一个小于零,等于零,或大于零的整数。只有键名比较返回0,对应的键值才会传递给此自定义函数比较。
$user_key_compare_func用户自定义回调函数,用来比较键名。如果认为第一个键名小于,等于,或大于第二个键名时必须分别返回一个小于零,等于零,或大于零的整数。
 
四、返回值:
返回第一个数组与其他数组的键名/键值对差集组成的数组。

五、用法举例:
1、array_udiff_uassoc 函数工作流程解析:
  大体分为3步:1、每个数组key的排序去重;2、判断第一个数组的key是否与其他数组的key相等,如果相等返回0,然后执行第3步;3、判断第2步相等的key对应的值是否相等,相等返回0,此key和对应的值不会再出现在返回数组中,执行第1步比较下一对key。
<?php
function user_key_compare_func($k1, $k2) {
echo sprintf("debug key: %s vs %s %s\n", $k1, $k2, $k1===$k2 ? 0 : ($k1>$k2?1:-1) ); //debug行
if ( $k1 === $k2 ) {
return 0;
}
return $k1 > $k2 ? 1 : -1;
}

function user_value_compare_func($v1, $v2) {
echo sprintf("debug value: %s vs %s %s\n", $v1, $v2, $v1===$v2 ? 0 : ($v1>$v2?1:-1) ); //debug行
if ( $v1 === $v2 ) {
return 0;
}
return $v1 > $v2 ? 1 : -1;
}

$arr1 = array('爱E族', 'aiezu', 'b'=>'bb',);
$arr2 = array('name'=>'爱E族', 'b'=>'bb', 'aiezu');

$result = array_udiff_uassoc($arr1, $arr2, "user_value_compare_func", "user_key_compare_func");
print_r($result);
输出:
debug   key: 1 vs 0 1  #$arr1的key排序去重
debug key: b vs 1 -1
debug key: 0 vs b -1 #$arr2的key排序去重
debug key: b vs name -1

debug key: 0 vs b -1 #key不相等
debug key: 0 vs 0 0 #key相等,下步比较key对应的键值
debug value: 爱E族 vs aiezu 1 #key对应的键值不相等,key:0,value:爱E族会出现在返回数组中
debug key: b vs 0 -1
debug key: b vs b 0 #key相等,下步比较key对应的键值
debug value: bb vs bb 0 #key对应的键值也相等,$arr1中键b和对应的键值bb不会出现在返回数组中
debug key: 1 vs 0 1
debug key: 1 vs b 1
debug key: 1 vs name 1
Array
(
[0] => 爱E族
[1] => aiezu
)

2、使用类函数作为键值和键名比较函数,找出三个数组的差集:
<?php
class user {
function key_compare($k1, $k2) {
if ( $k1 === $k2 ) {
return 0;
}
return $k1 > $k2 ? 1 : -1;
}
function value_compare($v1, $v2) {
if ( $v1 === $v2 ) {
return 0;
}
return $v1 > $v2 ? 1 : -1;
}
}
$arr1 = array('爱E族', 'aiezu', 'b'=>'bb',);
$arr2 = array('name'=>'爱E族', 'b'=>'bb', 'aiezu');
$arr3 = array('1'=>'aiezu');
$result = array_udiff_uassoc($arr1, $arr2, $arr3, array("user", "value_compare"), array("user", "key_compare"));
print_r($result);
输出:
Array
(
[0] => 爱E族
)