九个PHP很有用的功能
下面是九个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
*/
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:块输出操作
ru_inblock:块输入操作
ru_msgsnd:发送的消息
ru_msgrcv:收到的消息
ru_maxrss:最大驻留集大小
ru_ixrss:整体共享内存大小
ru_idrss:整数非共享数据大小
ru_minflt:页面回收
ru_majflt:页面错误
ru_nsignals:接收到的信号
ru_nvcsw:自愿上下文切换
ru_nivcsw:非自愿上下文切换
ru_nswap:掉期
ru_utime.tv_usec:用户使用时间(微秒)
ru_utime.tv_sec:用户使用时间(秒)
ru_stime.tv_usec:系统使用时间(微秒)
ru_stime.tv_sec:系统使用时间(秒)
要查看脚本消耗了多少 CPU 功率,我们需要查看“用户时间”和“系统时间”值。默认情况下,秒和微秒部分是单独提供的。您可以将微秒值除以 1 万,然后将其添加到秒值中,以十进制数的形式获得总秒数。
让我们看一个例子:
// 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 秒。这是因为服务器上可能还有其他进程,并且脚本在 100 秒的整个持续时间内没有使用 3% CPU。
5. 魔术常数
PHP 提供了有用的魔术常量,用于获取当前行号 ()、文件路径 ()、目录路径 ()、函数名称 ()、类名 ()、方法名 (__METHOD__) 和命名空间 ()。__LINE____FILE____DIR____FUNCTION____CLASS____NAMESPACE__
我们不会在本文中逐一介绍其中的每一个,但我会向您展示一些用例。
当包含其他脚本时,最好使用常量(或者,从 PHP 5.3 开始):__FILE____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));
实际上有一个名为uniqid()的PHP函数用于此目的。
// 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近年来变得如此流行,他们决定在PHP 5.2中添加对它的支持。现在你也可以使用 和 函数: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() 时,无论脚本停止运行的原因,代码都将执行:
$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.";
}
评论 (0)