脚本宝典收集整理的这篇文章主要介绍了百度工程师讲PHP函数的实现原理及性能分析(三),脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
常用PHP函数实现及介绍
count
count是我们经常用到的
一个函数,其
功能是返回
一个数组的长度。
count这个
函数,其复杂度是多少呢? 一种常见的说法是count
函数会遍历整个数组然后求出元素个数,因此复杂度是O(n)。那实际情况是不是这样呢?我们回到count的实现来看一下,通过
源码可以发现,对于数组的count操作,
函数最终的路径是zif_count->
PHP_count_recursive-> zend_hash_num_elements,而zend_hash_num_elements的行为是 return ht->nNumOfElements,可见,这是
一个O(1)而不是O(n)的操作。实际上,数组在
PHP底层就是
一个hash_table,对于hash表,zend中专门有
一个元素nNumOfElements记录了当前元素的个数,因此对于一般的count实际上直接就返回了这个值。由此,我们得出结论: count是O(1)的复杂度,和具体数组的大小无关。
非
数组类型的变量,count的行为时
怎样?对于未设置变量返回0,而像int、do
uble、string等则会返回1
Strlen用于返回
一个字符串的长度。那么,他的
实现原理是如何的呢?我们都
知道在c中strlen是
一个o(n)的
函数,会顺序遍历字符串直到遇到\0,然后出长度。
PHP中
是否也这样呢?答案是否定的,
PHP里字符串是用
一个复合结构来描述,
包括指向具体数据的指针和字符串长度(和c++中string类似),因此 strlen就直接返回字符串长度了,是常数级别的操作。另外,对于非字符串类型的变量
调用strlen,它会首先将变量强制转换为字符串再求长度,这点需要注意。
这两个
函数最常见的
用法都是判断
一个 key是否在数组中存在。但是前者还可以用于判断
一个变量是否被设置过。如前文所述,isset并非真正的
函数,因此它的效率会比后者高很多。推荐用它代替array_key_exists。
array_push和array[]
两者都是往数组尾部追加
一个元素。不同的是前者可以一次push多个。他们最大的区别在于
一个是
函数一个是语言结构,因此后者效率要更高。因此如果只是普通的追加元素,建议使用array []。
两者都是提供产生
随机数的
功能,前者使用 libc标准的rand。后者用了 Mersenne Twister 中已知的特性作为
随机数发生器,它可以产生
随机数值的平均速度比 libc 提供的 rand() 快四倍。因此如果对
性能要求较高,可以考虑
用Mt_rand代替前者。我们都知道,rand产生的是伪
随机数,在C中需要用srand
显示指定种子。但是在
PHP中,rand会自己帮你
默认
调用一次srand,一般情况下不需要自己再
显示的
调用。需要注意的是,如果特殊情况下需要
调用srand时,一定要配套
调用。就是说srand对于rand,mt_srand对应srand,切不可混合使用,否则是无效的。
sort和 usort
两者都是用于排序,不同的是前者可以指定排序策略,类似我们C里面的qsort和C++的sort。在排序上两者都是采用标准的快排来实现,对于有排序需求的,如非特殊情况
调用PHP提供的这些
方法就可以了,
不用自己重新实现一遍,效率会低很多。
原因见前文对于
用户函数和内置
函数的分析比对。
urlencode和rawurlencode
这两个都是用于 url编码, 字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数。两者唯一的区别在于对于空格,urlencode会编码为+,而 rawurlencode会编码为%20。一般情况下除了
搜索引擎,我们的策略都是空格编码为%20。因此采用后者的居多。注意的是encode和 decode
系列一定要配套使用。
这一系列的
函数包括strcmp、
strncmp、
strcasecmp、strncasecmp,实现
功能和C
函数相同。但也有不同,由于
PHP的字符串是允许\0出现,因此在判断的时候底层使用的是memcmp系列而非strcmp,理论上来说更快。另外由于
PHP直接能
获取到字符串长度,因此会首先这方面的检查,很多情况下效率就会高很多了。
is_int和is_numeric
这两个
函数功能相似又不完全相同,使用的时候一定需要注意他们的区别。Is_int:判断
一个变量类型是否是整数型,
PHP变量中专门有
一个字段表征类型,因此直接判断这个类型即可,是
一个绝对 O(1)的操作 Is_numeric:判断
一个变量是否是整数或数字字符串,也就是说除了整数型变量会返回true之外,对于字符串变量,如果形如”1234”,”1e4”等也会被判为true。这个时候会遍历字符串进行判断。
总结及建议
总结:
通过对
函数实现的
原理分析和
性能测试,我们总结出以下一些结论
1.
PHP的
函数调用开销相对
较大。
2.
函数相关信息保存在
一个大的hash_table中,每次
调用时通过
函数名在hash表中查找,因此
函数名长度对
性能也有一定影响。
3.
函数返回引用没有实际意义
4. 内置
PHP函数性能比
用户函数高很多,尤其对于字符串类操作。
5. 类
方法、普通
函数、静态
方法效率几乎相同,没有太大差异
6. 除去空
函数调用的影响,内置
函数和同样
功能的C
函数性能基本差不多。
7. 所有的参数传递都是采用引用计数的浅拷贝,代价很小。
8.
函数个数对
性能影响几乎可以忽略
建议:
因此,对于PHP函数的使用,有如下一些建议
1. 一个功能可以用内置函数完成,尽量使用它而不是自己编写PHP函数。
2. 如果某个功能对性能要求很高,可以考虑用扩展来实现。
3. PHP函数调用开销较大,因此不要过分封装。有些功能,如果需要调用的次数很多本身又只用1、2行代码就行实现的,建议就不要封装调用了。
4. 不要过分迷恋各种设计模式,如上一条描述,过分的封装会带来性能的下降。需要考虑两者的权衡。PHP有自己的特点,切不可东施效颦,过分效仿java的模式。
5. 函数不宜嵌套过深,递归使用要谨慎。
6. 伪函数性能很高,同等功能实现下优先考虑。比如用isset代替array_key_exists
7. 函数返回引用没有太大意义,也起不到实际作用,建议不予考虑。
8. 类成员方法效率不比普通函数低,因此不用担心性能损耗。建议多考虑静态方法,可读性及安全性都更好。
9. 如不是特殊需要,参数传递都建议使用传值而不是传引用。当然,如果参数是很大的数组且需要修改时可以考虑引用传递。
脚本宝典总结
以上是脚本宝典为你收集整理的百度工程师讲PHP函数的实现原理及性能分析(三)全部内容,希望文章能够帮你解决百度工程师讲PHP函数的实现原理及性能分析(三)所遇到的问题。
如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。