9月
8
PHP Optimization Tricks
PHP优化技巧
原文地址:http://ilia.ws/archives/12-PHP-Optimization-Tricks.html
PHP优化技巧
原文地址:http://ilia.ws/archives/12-PHP-Optimization-Tricks.html
| 英文 | 中文 |
| There are a number of tricks that you can use to squeeze the last bit of performance from your scripts. These tricks won't make your applications much faster, but can give you that little edge in performance you may be looking for. More importantly it may give you insight into how PHP internals works allowing you to write code that can be executed in more optimal fashion by the Zend Engine. Please keep in mind that these are not the 1st optimization you should perform. There are some far easier and more performance advantageous tricks, however once those are exhausted and you don't feel like turning to C, these maybe tricks you would want to consider. So, without further ado... 1) When working with strings and you need to check that the string is either of a certain length you'd understandably would want to use the strlen() function. This function is pretty quick since it's operation does not perform any calculation but merely return the already known length of a string available in the zval structure (internal C struct used to store variables in PHP). However because strlen() is a function it is still somewhat slow because the function call requires several operations such as lowercase & hashtable lookup followed by the execution of said function. In some instance you can improve the speed of your code by using a isset() trick. Ex. if (strlen($foo) < 5) { echo "Foo is too short"; } vs. if (!isset($foo{5})) { echo "Foo is too short"; } Calling isset() happens to be faster then strlen() because unlike strlen(), isset() is a language construct and not a function meaning that it's execution does not require function lookups and lowercase. This means you have virtually no overhead on top of the actual code that determines the string's length. 2) When incrementing or decrementing the value of the variable $i++ happens to be a tad slower than ++$i. This is something PHP specific and does not apply to other languages, so don't go modifying your C or Java code thinking it'll suddenly become faster, it won't. ++$i happens to be faster in PHP because instead of 4 opcodes used for $i++ you only need 3. Post incrementation actually causes in the creation of a temporary var that is then incremented. While pre-incrementation increases the original value directly. This is one of the optimization that opcode optimized like Zend's PHP optimizer. It is a still a good idea to keep in mind since not all opcode optimizers perform this optimization and there are plenty of ISPs and servers running without an opcode optimizer. 3) When it comes to printing text to screen PHP has so many methodologies to do it, not many users even know all of them. This tends to result in people using output methods they are already familiar from other languages. While this is certainly an understandable approach it is often not best one as far as performance in concerned. print vs echo Even both of these output mechanism are language constructs, if you benchmark the two you will quickly discover that print() is slower than echo(). The reason for that is quite simple, print function will return a status indicating if it was successful or not, while echo simply print the text and nothing more. Since in most cases (haven't seen one yet) this status is not necessary and is almost never used it is pointless and simply adds unnecessary overhead. printf Using printf() is slow for multitude of reasons and I would strongly discourage it's usage unless you absolutely need to use the functionality this function offers. Unlike print and echo printf() is a function with associated function execution overhead. More over printf() is designed to support various formatting schemes that for the most part are not needed in a language that is typeless and will automatically do the necessary type conversions. To handle formatting printf() needs to scan the specified string for special formatting code that are to be replaced with variables. As you can probably imagine that is quite slow and rather inefficient. heredoc This output method comes to PHP from PERL and like most features adopted from other languages it's not very friendly as far as performance is concerned. While this method allows you to easily output large chunks of text while preserving things like newlines and even allow for variable handling inside the text block this is quite slow and there are better ways to do that. Performance wise this is just marginally faster then printf() however it does not offer nearly as much functionality. ?><? When you need to output a large or even a medium sized static bit of text it is faster and simpler to put it outside the of PHP. This will make the PHP's parser effectively skipover this bit of text and output it as is without any overhead. You should be careful however and not use this for many small strings in between PHP code as multiple context switches between PHP and plain text will ebb away at the performance gained by not having PHP print the text via one of it's functions or constructs. 4) Many scripts tend to reply on regular expression to validate the input specified by user. While validating input is a superb idea, doing so via regular expression can be quite slow. In many cases the process of validation merely involved checking the source string against a certain character list such as A-Z or 0-9, etc... Instead of using regex in many instances you can instead use the ctype extension (enabled by default since PHP 4.2.0) to do the same. The ctype extension offers a series of function wrappers around C's is*() function that check whether a particular character is within a certain range. Unlike the C function that can only work a character at a time, PHP function can operate on entire strings and are far faster then equivalent regular expressions. Ex. preg_match("![0-9]+!", $foo); vs ctype_digit($foo); 5) Another common operation in PHP scripts is array searching. This process can be quite slow as regular search mechanism such as in_array() or manuall implementation work by itterating through the entire array. This can be quite a performance hit if you are searching through a large array or need to perform the searches frequently. So what can you do? Well, you can do a trick that relies upon the way that Zend Engine stores array data. Internally arrays are stored inside hash tables when they array element (key) is the key of the hashtables used to find the data and result is the value associated with that key. Since hashtable lookups are quite fast, you can simplify array searching by making the data you intend to search through the key of the array, then searching for the data is as simple as $value = isset($foo[$bar])) ? $foo[$bar] : NULL;. This searching mechanism is way faster then manual array iteration, even though having string keys maybe more memory intensive then using simple numeric keys. Ex. $keys = array("apples", "oranges", "mangoes", "tomatoes", "pickles"); if (in_array('mangoes', $keys)) { ... } vs $keys = array("apples" => 1, "oranges" => 1, "mangoes" => 1, "tomatoes" => 1, "pickles" => 1); if (isset($keys['mangoes'])) { ... } The bottom search mechanism is roughly 3 times faster. If you know or have any additional optimization tricks let me know | 这里是几条优化技巧,你可以在你最终优化时用到它们。这些技巧并不是让你的代码变得更快,而只能使代码稍稍的优化一点。更重要的是它可以让你洞察到PHP内在的运行原理,使得ZEND引擎能够更好的对代码进行优化。提醒一下,这不是你在编码开始时就要执行的优化。有一些更简单更快的优化技巧,在使用后,however once those are exhausted and you don't feel like turning to C, these maybe tricks you would want to consider. So, without further ado... 1) 当对字符串进行操作时,如果你需要检查字符串是否超过某一长度,你很容易理解如何使用strlen()函数。这个函数执行较快,没有进行任何计算操作,而仅仅返回C结果字符串的长度(在PHP中的变量与C变量内部结构相同)。但是strlen()是一个函数,于其他函数一样,在使用时需要进行几个操作,如全部小写化,函数查找。在某些场合,不可以使用isset()来提高你的代码速度。 例子: if (strlen($foo) < 5) { echo "Foo is too short"; } vs. if (!isset($foo{5})) { echo "Foo is too short"; } 调用isset()比strlen()要快,因为isset(0是一种语法结构而不是以个函数。在执行时不需要进行小写化和函数查找。这意味着你并没有真正取得字符串的长度。 2)使用递增或递减时,$i++比++$i稍慢,和其他语言相比,在PHP是一个特例的,不要在C和JAVA中也使用这个技巧。在PHP中$++比++$i快的原因是$i++进行了四次计算,而++$i进行三次。后缀递加先申请了一个临时变量,然后增加。而前缀递加直接使用了原变量。这也是ZEND的PHP优化器优化的一部分,但这还是一个好的建议,因为并不是所有的优化器都优化了这一点,以及并不是所有ISP都支持优化器。 3)当需要输出文本时,PHP有很多的方法。很多PHPer并不知道所有的方法,结果PHPers使用了他们以前所习惯的语法。这是可以理解的,虽然这并不是达到所有程序运行的最佳效率。 print 对 echo 两者都是语法结构,但print比echo 还是稍稍慢一点。理由很简单,不管是否需要,print会返回一个状态标示,而echo只是简单的输出而不做其他任何事情。而在绝大多数情况下,这个状态标示是没有用到的不必要的花费。 printf 使用printf()很慢,我强烈建议不在万不得已的时候不要使用这个函数。printf()对花费函数消耗。printf()是给需要进行参数格式化的情况下使用的。php是类型无关语言,大部分时间用在类型的隐形转化上。调用printf()来格式化字符串需要在字符串中扫描需要被替换的特殊字符,你可以预计的到这样的速度和效率。 heredoc 这种输出方式继承自PERL,这也被其他语言所采用。 没时间翻译了,给个精要得了: ?><? 替代 ?> <? 这样,PHP在执行时就不需要退出去处理那些空白输出。 当然,我觉得这个可以直接删掉这一个?><? 4)很多脚本都喜欢使用正则表达式来验证用户输入数据,但正则匹配的速度是很慢的,在很多情况下,我们只是验证数据是不是象A-Z,0-9等等。我们可以使用ctype来替代正则。ctype扩展提供了一系列类C的is*()函数,不象C函数一次只能对一个字符进行验证,PHP的ctype函数可以对整个字符串操作,比正则的运行效率要高。 例子: preg_match("![0-9]+!", $foo); vs ctype_digit($foo); 5) 另一个PHP常用的操作是数组搜索,这个操作使用正则查找或完全遍历整个数组来实现,这在查找一个大数组或频繁查找时相当耗资源,我们该怎么做呢?你可以使用ZEND引擎技巧来优化它,关联数组元素实质上是以哈希表来存储的。哈希表查询速度是非常快的。所以查找数据可以简单的这样写:$value = isset($foo[$bar])) ? $foo[$bar] : NULL;这种查找模式比遍历查找要快,即便是字符关键字比数字关键字占用了更多内存。 例子: $keys = array("apples", "oranges", "mangoes", "tomatoes", "pickles"); if (in_array('mangoes', $keys)) { ... } vs $keys = array("apples" => 1, "oranges" => 1, "mangoes" => 1, "tomatoes" => 1, "pickles" => 1); if (isset($keys['mangoes'])) { ... } 下一个查找比上一个要快3倍。 如果你知道其他的优化技巧,请告诉我 |

0 引用