你必须知道的非常有用的9个php功能特性

1、给函数传递任意个参数
你可能已经知道php可以定义函数的可选参数,但是还有一种方法,可以给函数传递任意数量的参数。

首先,一个可选参数的例子:

// function with 2 optional arguments
function foo($arg1 = '', $arg2 = '') {

    echo "arg1: $arg1\n";
    echo "arg2: $arg2\n";

}

foo('hello','world');
/* prints:
arg1: hello
arg2: world
*/

foo();
/* prints:
arg1:
arg2:
*/

现在,来看一下我们怎样去创建一个可以接收任意数量参数的函数。
这里,我们要用func_get_args()函数。

// yes, the argument list can be empty
function foo() {

    // returns an array of all passed arguments
    $args = func_get_args();

    foreach ($args as $k => $v) {
        echo "arg".($k+1).": $v\n";
    }

}

foo();
/* prints nothing */

foo('hello');
/* prints
arg1: hello
*/

foo('hello', 'world', 'again');
/* prints
arg1: hello
arg2: world
arg3: again
*/

笔者注:php5.6之后的版本还有另外一种方法实现。
如下:

function add(...$args)
{
    $result = 0;
    foreach($args as $arg)
        $result += $arg;
    return $result;
}

同时可以在调用函数时,把数组展开为函数参数:

$arr = [2, 3];
add(1, ...$arr);
// 结果为 6

2、使用glob()去查找文件
许多php函数都有一个长并且带有描述性的名字。然而,一个名叫glob()的函数可能比较难告诉你是干什么的,
除非你在其他地方已经很熟悉它了。
可以理解为一个比scandir()函数更强大的版本,它可以通过模式匹配来搜索文件。

// get all php files
$files = glob('*.php');

print_r($files);
/* output looks like:
Array
(
[0] => phptest.php
[1] => pi.php
[2] => post_output.php
[3] => test.php
)
*/

还可以像这样匹配多个文件类型:

// get all php files AND txt files
$files = glob('*.{php,txt}', GLOB_BRACE);

print_r($files);
/* output looks like:
Array
(
[0] => phptest.php
[1] => pi.php
[2] => post_output.php
[3] => test.php
[4] => log.txt
[5] => test.txt
)
*/

提醒一下,基于你的查询,可以返回一个路径下的文件:

$files = glob('../images/a*.jpg');

print_r($files);
/* output looks like:
Array
(
[0] => ../images/apple.jpg
[1] => ../images/art.jpg
)
*/

如果你要得到每个文件的全路径,只需要在每个返回的值上面调用realpath()函数:

$files = glob('../images/a*.jpg');

// applies the function to each array element
$files = array_map('realpath',$files);

print_r($files);
/* output looks like:
Array
(
[0] => C:\wamp\www\images\apple.jpg
[1] => C:\wamp\www\images\art.jpg
)
*/

3、内存使用信息
通过观察你的脚本的内存使用情况,你可以更好的优化你的代码。
php有一个垃圾收集器和一个非常复杂的内存管理器。
在你的脚步运行期间,它的内存使用量是在不断变化的。
要获取当前的内存使用量,可以使用memory_get_usage()函数。
在任意时间获取内存的最大使用量,可以用memory_get_peak_usage()函数。

echo "Initial: ".memory_get_usage()." bytes \n";
/* prints
Initial: 361400 bytes
*/

// let's use up some memory
for ($i = 0; $i < 100000; $i++) {
$array []= md5($i);
}

// let's remove half of the array
for ($i = 0; $i < 100000; $i++) {
unset($array[$i]);
}

echo "Final: ".memory_get_usage()." bytes \n";
/* prints
Final: 885912 bytes
*/

echo "Peak: ".memory_get_peak_usage()." bytes \n";
/* prints
Peak: 13687072 bytes
*/

4、CPU使用信息

为此,我们将利用getrusage()函数。记住,这个函数在windows平台不可用。

print_r(getrusage());
/* prints
Array
(
[ru_oublock] => 0
[ru_inblock] => 0
[ru_msgsnd] => 2
[ru_msgrcv] => 3
[ru_maxrss] => 12692
[ru_ixrss] => 764
[ru_idrss] => 3864
[ru_minflt] => 94
[ru_majflt] => 0
[ru_nsignals] => 1
[ru_nvcsw] => 67
[ru_nivcsw] => 4
[ru_nswap] => 0
[ru_utime.tv_usec] => 0
[ru_utime.tv_sec] => 0
[ru_stime.tv_usec] => 6269
[ru_stime.tv_sec] => 0
)

*/

除非你有系统管理员背景,否则,上面的看起来比较难理解。
这里有每一项的解释(你不需要记忆):
ru_oublock: block output operations(块输出操作)
ru_inblock: block input operations (块输入操作)
ru_msgsnd: messages sent (消息发送)
ru_msgrcv: messages received (消息接收)
ru_maxrss: maximum resident set size (最大常驻内存大小)
ru_ixrss: integral shared memory size (共享内存大小)
ru_idrss: integral unshared data size (非共享数据大小)
ru_minflt: page reclaims (页面回收)
ru_majflt: page faults (页面错误)
ru_nsignals: signals received (信号接收)
ru_nvcsw: voluntary context switches
ru_nivcsw: involuntary context switches
ru_nswap: swaps (交换空间)
ru_utime.tv_usec: user time used (microseconds) (用户时间,毫秒部分)
ru_utime.tv_sec: user time used (seconds) (用户时间,秒部分)
ru_stime.tv_usec: system time used (microseconds) (系统时间,毫秒部分)
ru_stime.tv_sec: system time used (seconds) (系统时间,秒部分)
要知道脚步消耗了多少CPU时间,必须看用户时间和系统时间,默认提供秒和毫秒两部分数据。
用毫秒数的值除以100万,再加上秒数,得到一个十进制表示的总秒数。
看例子:

// sleep for 3 seconds (non-busy)
sleep(3);

$data = getrusage();
echo "User time: ".
($data['ru_utime.tv_sec'] +
$data['ru_utime.tv_usec'] / 1000000);
echo "System time: ".
($data['ru_stime.tv_sec'] +
$data['ru_stime.tv_usec'] / 1000000);

/* prints
User time: 0.011552
System time: 0
*/

尽管脚本的运行时间大约为3秒,但是cpu使用还是非常非常低的。
因为在脚本睡眠期间,实际上没有消耗cpu资源。
还有其他许多任务需要实时,但是很可能并没有使用cpu时间,比如等待磁盘的操作。
所以,就如你所看到的,cpu的使用和实际运行的时间不总是相同的。
另外一个例子:

// loop 10 million times (busy)
for($i=0;$i<10000000;$i++) {

}

$data = getrusage();
echo "User time: ".
($data['ru_utime.tv_sec'] +
$data['ru_utime.tv_usec'] / 1000000);
echo "System time: ".
($data['ru_stime.tv_sec'] +
$data['ru_stime.tv_usec'] / 1000000);

/* prints
User time: 1.424592
System time: 0.004204
*/

花费了大约1.4秒的CPU时间,几乎全部是用户时间,因为没有系统调用。
系统时间是cpu执行系统内核调用的时间量。
有一个例子如下:

$start = microtime(true);
// keep calling microtime for about 3 seconds
while(microtime(true) - $start < 3) {

}

$data = getrusage();
echo "User time: ".
($data['ru_utime.tv_sec'] +
$data['ru_utime.tv_usec'] / 1000000);
echo "System time: ".
($data['ru_stime.tv_sec'] +
$data['ru_stime.tv_usec'] / 1000000);

/* prints
User time: 1.088171
System time: 1.675315
*/

现在有较多的系统使用时间了,这是因为多次调用了microtime()函数,
它是通过操作系统来取得时间的。
你可能已经注意到了,这些时间加起来都不到3秒。
这是因为有可能有其他进程在运行,再者,在整个持续的3秒里面,脚本并没有100%的使用CPU。

5、魔术常量
php提供了非常有用的魔术常量来获取当前所在的行数(__LINE__),文件路径(__FILE__)
,目录路径(__DIR__),函数名(__FUNCTION__),类名(__CLASS__),方法名(__METHOD__)和命名空间(__NAMESPACE__)。
我们不会在这里解释每一个魔术常量,但是会展示一些有用的案例。
当需要包含其他文件时,利用__FILE__常量是个不错的主意(PHP5.3之后的版本也可以用__DIR__)。

// this is relative to the loaded script's path
// it may cause problems when running scripts from different directories
require_once('config/database.php');

// this is always relative to this file's path
// no matter where it was included from
require_once(dirname(__FILE__) . '/config/database.php');

使用__LINE__使得更容易调试,你可以追踪到行号:

// some code
// ...
my_debug("some debug message", __LINE__);
/* prints
Line 4: some debug message
*/

// some more code
// ...
my_debug("another debug message", __LINE__);
/* prints
Line 11: another debug message
*/

function my_debug($msg, $line) {
echo "Line $line: $msg\n";
}

6、生成唯一ID
可能存在这样一种情况,你需要生成一段唯一的字符串。
我见过很多人用md5()函数来达到这个目的,即使是不适合用来达到这个目的:

// generate unique string
echo md5(time() . mt_rand(1,1000000));

事实上php有个名叫uniqid()的函数就可以达到这个目的。

// generate unique string
echo uniqid();
/* prints
4bd67c947233e
*/

// generate another unique string
echo uniqid();
/* prints
4bd67c9472340
*/

虽然他们是唯一的,但是看起来确很相似,这是因为生成的字符串和服务器时间有关。
这也有好的一面,因为每个新生成的ID都是按字母顺序来的,所以他们是可排序的。
为了减少出行重复的几率,你可以通过加前缀,或者添加第二个参数:

// with prefix
echo uniqid('foo_');
/* prints
foo_4bd67d6cd8b8f
*/

// with more entropy
echo uniqid('',true);
/* prints
4bd67d6cd8b926.12135106
*/

// both
echo uniqid('bar_',true);
/* prints
bar_4bd67da367b650.43684647
*/

相对于md5(),它不仅生成的字符串比它短,还更节省存储空间。

7、序列化
你是否曾经需要在文本或者数据库里面存储一个复杂变量?你不需要自己去想一个把数组或者对象转成格式化字符串的解决方案。
因为PHP已经有了这样的功能。
有两个流行的序列化变量的方法,这里有一个使用serialize() 和 unserialize()的例子:

// a complex array
$myvar = array(
'hello',
42,
array(1,'two'),
'apple'
);

// convert to a string
$string = serialize($myvar);

echo $string;
/* prints
a:4:{i:0;s:5:"hello";i:1;i:42;i:2;a:2:{i:0;i:1;i:1;s:3:"two";}i:3;s:5:"apple";}
*/

// you can reproduce the original variable
$newvar = unserialize($string);

print_r($newvar);
/* prints
Array
(
[0] => hello
[1] => 42
[2] => Array
(
[0] => 1
[1] => two
)

[3] => apple
)
*/

这是PHP原生的序列化方法。然而,自从JSON在这些年逐渐流行起来,他们觉得在PHP5.2版中加入JSON支持。
现在你可以像这样使用json_encode() 和 json_decode()函数:

// a complex array
$myvar = array(
'hello',
42,
array(1,'two'),
'apple'
);

// convert to a string
$string = json_encode($myvar);

echo $string;
/* prints
["hello",42,[1,"two"],"apple"]
*/

// you can reproduce the original variable
$newvar = json_decode($string);

print_r($newvar);
/* prints
Array
(
[0] => hello
[1] => 42
[2] => Array
(
[0] => 1
[1] => two
)

[3] => apple
)
*/

她更紧凑,在这两个方法里面,它是最好的,而且兼容javascript和其它许多语言。
但是,对于复杂对象,有可能会丢失一些信息。

8、压缩字符串
谈到压缩,通常我们会想到文件,比如ZIP归档。在PHP里面,不用任何归档文件压缩一个长字符串也是可能的。
下面的例子,我们将利用 gzcompress() 和 gzuncompress()函数:

$string =
"Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc ut elit id mi ultricies
adipiscing. Nulla facilisi. Praesent pulvinar,
sapien vel feugiat vestibulum, nulla dui pretium orci,
non ultricies elit lacus quis ante. Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Aliquam
pretium ullamcorper urna quis iaculis. Etiam ac massa
sed turpis tempor luctus. Curabitur sed nibh eu elit
mollis congue. Praesent ipsum diam, consectetur vitae
ornare a, aliquam a nunc. In id magna pellentesque
tellus posuere adipiscing. Sed non mi metus, at lacinia
augue. Sed magna nisi, ornare in mollis in, mollis
sed nunc. Etiam at justo in leo congue mollis.
Nullam in neque eget metus hendrerit scelerisque
eu non enim. Ut malesuada lacus eu nulla bibendum
id euismod urna sodales. ";

$compressed = gzcompress($string);

echo "Original size: ". strlen($string)."\n";
/* prints
Original size: 800
*/

echo "Compressed size: ". strlen($compressed)."\n";
/* prints
Compressed size: 418
*/

// getting it back
$original = gzuncompress($compressed);

我们使归档大小减小了几乎50%。类似的函数gzencode() 和 gzdecode() ,使用不同的算法可以得到类似的结果。

9、注册关闭函数
有一个叫register_shutdown_function(),允许你在脚本运行完毕的时候执行一些代码。
想象一下,你想在脚本运行结束的时候获取一些基准统计信息,比如运行了多长时间:

// capture the start time
$start_time = microtime(true);

// do some stuff
// ...

// display how long the script took
echo "execution took: ".
(microtime(true) - $start_time).
" seconds.";

起初这看起来微不足道,你只是把你的代码添加到文件底部,它会在运行结束时被执行。但是,假如你曾经调用了exit()函数,
这些代码将永远不会执行。另外,假如某个地方有致命错误,又或者脚步被用户终止了(在浏览器里面按下停止按钮),这些代码页不会
执行。
当你用register_shutdown_function()时,不管你的脚本因为什么而终止,它都会执行:当你用register_shutdown_function()时,不管你的脚本因为什么而终止,它都会执行:

$start_time = microtime(true);

register_shutdown_function('my_shutdown');

// do some stuff
// ...

function my_shutdown() {
global $start_time;

echo "execution took: ".
(microtime(true) - $start_time).
" seconds.";
}


转载链接 http://www.360us.net/archives/527


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值