PHP函数的实现原理及性能分析结论

1.函数调用的时候zend会先在一个全局的funtion_table中通过函数名查询相关信息,function_table是一个哈希表。必然的,名字越长查询所需要的时间就越多。 因此,在实际编写程序的时候,对多次调用的函数,名字建议不要太长。
2.函数递归是通过堆栈来完成的。在php中,也是利用类似的方法来实现。Zend为每个php函数分配了一个活动符号表(active_sym_table),记录当前函数中所有局部变量的状态。所有的符号表通过堆栈的形式来维护,每当有函数调用的时候,分配一个新的符号表并入栈。当调用结束后当前符号表出栈。由此实现了状态的保存和递归。 对于栈的维护,zend在这里做了优化。预先分配一个长度为N的静态数组来模拟堆栈,这种通过静态数组来模拟动态数据结构的手法在我们自己的程序中也经常有使用,这种方式避免了每次调用带来的内存分配、销毁。ZEND只是在函数调用结束时将当前栈顶的符号表数据clean掉即可。因为静态数组长度为N,一旦函数调用层次超过N,程序不会出现栈溢出,这种情况下zend就会进行符号表的分配、销毁,因此会导致性能下降很多。在zend里面,N目前取值是32。因此,我们编写php程序的时候,函数调用层次最好不要超过32。
3.php中所有的函数都放在一个hash表中,在不同个数下查找效率都应该还是接近于O(1),所以性能差距不大。
4.内置函数,其本质上就是真正的c函数,每一个内置函数,php在最终编译后都会展开成为一个名叫zif_xxxx的function,比如我们常见的sprintf,对应到底层就是zif_sprintf。Zend在执行的时候,如果发现是内置函数,则只是简单的做一个转发操作。Zend提供了一系列的api供调用,包括参数获取、数组操作、内存分配等。内置函数的参数获取,通过zend_parse_parameters方法来实现,对于数组、字符串等参数,zend实现的是浅拷贝,因此这个效率是很高的。可以这样说,对于php内置函数,其效率和相应c函数几乎相同,唯一多了一次转发调用。
5.所有的函数都放在一个hash表中,在不同个数下查找效率都应该还是接近于O(1),所以性能差距不大。
6.相对c来说,php函数调用的开销大很多,对于简单函数来说性能还是有一定影响。因此php中函数不宜嵌套封装太深。

  1. count是O(1)的复杂度,和具体数组的大小无关。
    8.php里字符串是用一个复合结构来描述,包括指向具体数据的指针和字符串长度(和c++中string类似),因此strlen就直接返回字符串长度了,是常数级别的操作。
    另外,对于非字符串类型的变量调用strlen,它会首先将变量强制转换为字符串再求长度,这点需要注意。
    9.isset并非真正的函数,因此它的效率会比后者高很多。推荐用它代替array_key_exists.
    10。普通的追加元素,建议使用array []。
    11.sort和usort两者都是用于排序,不同的是前者可以指定排序策略,类似我们C里面的qsort和C++的sort。在排序上两者都是采用标准的快排来实现。
    12.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. 如不是特殊需要,参数传递都建议使用传值而不是传引用。当然,如果参数是很大的数组且需要修改时可以考虑引用传递。

参考文章https://blog.csdn.net/heiyeshuwu/article/details/5840025

你可能感兴趣的:(PHP函数的实现原理及性能分析结论)