>  기사  >  백엔드 개발  >  PHP 최적화 및 주의사항에 대한 심층적인 이해

PHP 최적화 및 주의사항에 대한 심층적인 이해

黄舟
黄舟원래의
2017-07-27 10:15:181071검색

이 기사는 PHP의 고효율 작성 방법에 대한 자세한 분석 및 소개입니다. 요약은 매우 상세하고 포괄적이므로 PHP 수준을 향상시키는 데 매우 도움이 됩니다.

1. 가능한 한 정적으로 만드세요:

정적일 수 있는 메서드라면 정적으로 선언하면 속도가 1/4까지 증가할 수 있습니다. 세 번.

물론 이 테스트 방법은 레벨 100,000 이상에서 실행해야 효과가 뚜렷하게 나타납니다.

실제로 정적 메서드와 비정적 메서드 간 효율성의 주요 차이점은 메모리입니다. 정적 메서드는 프로그램이 시작될 때 메모리를 생성하고, 인스턴스 메서드는 프로그램이 실행되는 동안 메모리를 생성하므로 정적 메서드를 직접 호출할 수 있으며, 인스턴스 메서드는 먼저 인스턴스를 생성해야 합니다. 인스턴스 호출 메서드는 정적 속도가 매우 빠르지만 너무 많으면 메모리를 차지합니다.

모든 언어는 메모리와 디스크에서 작동합니다. 객체 지향인지 아닌지는 단지 소프트웨어 계층의 문제일 뿐입니다. 하지만 구현 방법이 다릅니다. 정적 메모리는 프로그램 시작 시 생성되기 때문에 연속적이지만, 인스턴스는 불연속적인 공간에 적용되므로 당연히 정적 방식만큼 빠르지는 않습니다.

정적 메서드는 항상 동일한 메모리 조각을 호출합니다. 단점은 자동으로 소멸될 수 없지만 인스턴스화에 의해 소멸될 수 있다는 것입니다.

2. echo는 반환 값이 없고 print는 정수를 반환하기 때문에 print보다 더 효율적입니다.

테스트:


Echo
0.000929 - 0.001255 s (平均 0.001092 seconds)
Print
0.000980 - 0.001396 seconds (平均 0.001188 seconds)

차이는 약 8%이고 전체 echo는 더 빠릅니다.

큰 문자열을 에코할 때 조정을 하지 않으면 성능에 심각한 영향을 미칠 수 있다는 점에 유의하세요. 압축을 위해 apache를 열려면 mod_deflate를 사용하고, 콘텐츠를 버퍼에 먼저 넣으려면 ob_start를 엽니다.

3. 루프 도중이 아니라 루프 전에 최대 루프 수를 설정하십시오.

모든 바보는 이것을 이해합니다.

4. 특히 큰 배열을 해제하기 위해 변수를 삭제합니다.

PHP에서 특히 배열과 개체가 메모리를 차지합니다. 이는 PHP의 기본 zend 엔진으로 인해 발생합니다. 1/10, 즉 C 언어에서 100M 메모리 배열은 PHP에서 1G가 필요합니다.

특히 PHP를 백엔드 서버로 사용하는 시스템에서는 과도한 메모리 소모 문제가 자주 발생합니다.

5. __get, __set, __autoload 등과 같은 매직 메서드를 사용하지 마세요.

__로 시작하는 함수의 경우 특정 조건에서 처음으로 액세스하는 함수에 이름을 지정하세요. 일반적으로 다음과 같은 마법 함수가 있습니다

__construct(), __destruct(), __get(), __set(), __unset(), __call(), __callStatic(), __sleep(), __wakeup( ) , __toString(), __set_state(), __clone(), __autoload()

<strong>__construct(),__destruct(),__get(),__set(),__unset(),__call(),__callStatic(),__sleep(),__wakeup(),__toString(),__set_state(),__clone(),__autoload()</strong>

실제로 __autoload가 클래스 이름을 실제 디스크 파일과 효율적으로 비교할 수 없는 경우(참고로 이는 실제 디스크 파일을 나타냅니다. 파일명뿐만 아니라 시스템은 파일이 존재하는지(각 인클루드 경로에 포함된 경로에서 검색해야 함)에 대해 많은 판단을 해야 하며, 파일이 존재하는지 판단하려면 디스크 I/O 작업이 필요합니다. , 디스크 I/O 작업의 효율성이 매우 낮다는 것은 잘 알려져 있으므로 이것이 자동 로드 메커니즘의 효율성이 감소하는 이유입니다.

따라서 시스템을 설계할 때 클래스 이름을 실제 디스크 파일에 매핑하기 위한 명확한 메커니즘을 정의해야 합니다. 이 규칙이 더 간단하고 명확할수록 자동 로드 메커니즘은 더 효율적입니다.

결론: 자동 로드 메커니즘은 본질적으로 비효율적입니다. 자동 로드 기능을 남용하고 잘못 설계된 자동 로드 기능만 있으면 효율성이 저하됩니다.

따라서 논의의 여지가 있는 __autoload 매직 방법을 사용하지 마십시오.

6.requiere_once()는 더 많은 리소스를 소비합니다.

이는 requirere_once가 파일 참조 여부를 확인해야 하기 때문입니다. 따라서 최대한 많이 사용해야 합니다. 피하기 위해 일반적으로 사용되는 require/include 메소드가 있습니다.

7. 포함 및 요구 사항에 절대 경로를 사용하세요.

상대 경로가 포함된 경우 PHP는 파일을 찾기 위해 include_path를 탐색합니다.


절대 경로를 사용하면 이러한 문제를 피할 수 있으므로 운영 체제 경로를 해결하는 데 시간이 덜 걸립니다.

8. 스크립트가 실행될 때 시간을 가져와야 하는 경우에는 $_SERVER['REQUSET_TIME']이 time();
상상하는 것보다 낫습니다. 하나는 기성품으로 바로 사용할 수 있고, 다른 하나는 함수를 통해 얻은 결과가 필요합니다.

9. PHP의 내부 문자열 조작 기능을 사용할 수 있다면 정규 표현식보다 효율성이 높기 때문에 정규 표현식 대신 사용해 보세요.
정규 표현식이 가장 많은 성능을 소모한다는 것은 말할 필요도 없습니다.

혹시 놓친 유용한 기능이 있나요? 예: strpbrk() strncasecmp() strpos()/strrpos()/stripos()/strripos() 변환해야 할 것이 단일 문자뿐인 경우

배열 대신 문자열을 사용하세요. strtr:


<?php
$addr = strtr($addr, "abcd", "efgh"); // good
$addr = strtr($addr, array(&#39;a&#39; => &#39;e&#39;, )); // bad
?>

효율성 향상: 10배.

10.str_replace 문자 교체는 일반 교체 preg_replace보다 빠르지만 strtr은 str_replace보다 1/4 빠릅니다.

另外不要做无谓的替换即使没有替换,str_replace 也会为其参数分配内存。很慢!解决办法:
用 strpos 先查找(非常快),看是否需要替换,如果需要,再替换效率:- 如果需要替换:效率几乎相等,差别在 0.1% 左右。
如果不需要替换:用 strpos 快 200%。

11.参数为字符串

如果一个函数既能接受数组又能接受简单字符做为参数,例如字符替换函数,并且参数列表不是太长,可以考虑额外写一段替换代码,使得每次传递参数都是一 个字符,而不是接受数组做为查找和替换参数。大事化小,1+1>2;

12.最好不用@,用@掩盖错误会降低脚本运行速度;

用@实际上后台有很多操作。用@比起不用@,效率差距:3 倍。特别不要在循环中使用@,在 5 次循环的测试中,即使是先用 error_reporting(0) 关掉错误,在循环完成后再打开,都比用@快。

13.$row['id']比$row[id]速度快7倍

建议养成数组键加引号的习惯;

14.在循环里别用函数

例如For($x=0; $x 48501fad7ec9f8ada671c1a739f00b12prop++)比局部变量要慢3倍;

19.建立一个未声明的局部变量要比一个已经定义过的局部变量慢9-10倍

20.声明一个未被任何一个函数使用过的全局变量也会使性能降低(和声明相同数量的局部变量一样)。
PHP可能去检查这个全局变量是否存在;

21.方法的性能和在一个类里面定义的方法的数目没有关系

因为我添加10个或多个方法到测试的类里面(这些方法在测试方法的前后)后性能没什么差异;

22.在子类里方法的性能优于在基类中;

23.只调用一个参数并且函数体为空的函数运行花费的时间等于7-8次$localvar++运算,而一个类似的方法(类里的函数)运行等于大约15次$localvar++运算;

24 用单引号代替双引号来包含字符串,这样做会更快一些。
因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会。

PHP 引擎允许使用单引号和双引号来封装字符串变量,但是这个是有很大的差别的!使用双引号的字符串告诉 PHP 引擎首先去读取字符串内容,查找其中的变 量,并改为变量对应的值。一般来说字符串是没有变量的,所以使用双引号会导致性能不佳。最好是使用字

符串连接而不是双引号字符串。


BAD:
$output = "This is a plain string";
GOOD:
$output = &#39;This is a plain string&#39;;
BAD:
$type = "mixed";
$output = "This is a $type string";
GOOD:
$type = &#39;mixed&#39;;
$output = &#39;This is a &#39; . $type .&#39; string&#39;;

25.当echo字符串时用逗号代替点连接符更快些。

echo一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加上了双引号)。
例如echo $str1,$str2。

26.Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。

尽量多用静态HTML页面,少用脚本。

28.尽量使用缓存,建议用memcached。

高性能的分布式内存对象缓存系统,提高动态网络应用程序性能,减轻数据库的负担;
也对运算码 (OP code)的缓存很有用,使得脚本不必为每个请求做重新编译。

29.使用ip2long()和long2ip()函数把IP地址转成整型存放进数据库而非字符型。

这几乎能降低1/4的存储空间。同时可以很容易对地址进行排序和快速查找;

30.使用checkdnsrr()通过域名存在性来确认部分email地址的有效性

这个内置函数能保证每一个的域名对应一个IP地址;

31.使用mysql_*的改良函数mysqli_*;

32.试着喜欢使用三元运算符(?:);

33.是否需要PEAR

在你想在彻底重做你的项目前,看看PEAR有没有你需要的。PEAR是个巨大的资源库,很多php开发者都知道;

35.使用error_reporting(0)函数来预防潜在的敏感信息显示给用户。

理想的错误报告应该被完全禁用在php.ini文件里。可是如果你在用一个共享的虚拟主机,php.ini你不能修改,那么你最好添加error_reporting(0)函数,放在每个脚本文件的第一行(或用
require_once()来加载)这能有效的保护敏感的SQL查询和路径在出错时不被显示;

36.使用 gzcompress() 和gzuncompress()对容量大的字符串进行压缩(解压)在存进(取出)数据库时。

这种内置的函数使用gzip算法能压缩到90%;

37.通过参数变量地址得引用来使一个函数有多个返回值。

你可以在变量前加个“&”来表示按地址传递而非按值传递;

38. 完全理解魔术引用和SQL注入的危险。

Fully understand “magic quotes” and the dangers of SQL injection. I'm hoping that most developers reading this are already familiar with SQL injection. However, I list it here because it's absolutely critical to understand. If you've never heard the term before, spend the entire rest of the day googling and reading.

39.某些地方使用isset代替strlen

当操作字符串并需要检验其长度是否满足某种要求时,你想当然地会使用strlen()函数。此函数执行起来相当快,因为它不做任何计算,只返回在zval 结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数,多多少少会有些慢,因为函数调用会经过诸多步骤,如字母小写化(译注:指函数名小写化,PHP不区分函数名大小写)、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用isset() 技巧加速执行你的代码。
(举例如下)

if (strlen($foo) < 5) { echo “Foo is too short”$$ }

(与下面的技巧做比较)

if (!isset($foo{5})) { echo “Foo is too short”$$ }

调用isset()恰巧比strlen()快,因为与后者不同的是,isset()作为一种语言结构,意味着它的执行不需要函数查找和字母小写化。也就是说,实际上在检验字符串长度的顶层代码中你没有花太多开销。

40.使用++$i递增


When incrementing or decrementing the value of the variable $i++ happens to be a tad slower then ++$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 preincrementation 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.

当执行变量$i的递增或递减时,$i++会比++$i慢一些。这种差异是PHP特有的,并不适用于其他语言,所以请不要修改你的C或Java代码并指望它们能立即变快,没用的。++$i更快是因为它只需要3条指令(opcodes),$i++则需要4条指令。后置递增实际上会产生一个临时变量,这个临时变量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种,正如Zend的PHP优化器所作的那样。牢记这个优化处理不失为一个好主意,因为并不是所有的指令优化器都会做同样的优化处理,并且存在大量没有装配指令优化器的互联网服务
提供商(ISPs)和服务器。

40. 不要随便就复制变量

有时候为了使 PHP 代码更加整洁,一些 PHP 新手(包括我)会把预定义好的变量复制到一个名字更简短的变量中,其实这样做的结果是增加了一倍的内存消耗,只会使程序更加慢。试想一下,在下面的例子中,如果用户恶意插入 512KB 字节的文字到文本输入框中,这样就会导致 1MB 的内存被消耗!


BAD:
$description = $_POST[&#39;description&#39;];

echo $description;
GOOD:
echo $_POST[&#39;description&#39;];

41 使用选择分支语句

switch case好于使用多个if,else if语句,并且代码更加容易阅读和维护。

42.在可以用file_get_contents替代file、fopen、feof、fgets

在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情况下,尽量用file_get_contents,因为他的效率高得多!但是要注意file_get_contents在打开一个URL文件时候的PHP版本问题;

43.尽量的少进行文件操作,虽然PHP的文件操作效率也不低的;

44.优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作(在update上,我被恶批过);

45.尽可能的使用PHP内部函数

46.循环内部不要声明变量,尤其是大变量:对象

(这好像不只是PHP里面要注意的问题吧?);

47.多维数组尽量不要循环嵌套赋值;

48.foreach效率更高,尽量用foreach代替while和for循环;

49.“用i+=1代替i=i+1。符合c/c++的习惯,效率还高”;

50.对global变量,应该用完就unset()掉;

51 并不是事必面向对象(OOP),面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。

52 不要把方法细分得过多,仔细想想你真正打算重用的是哪些代码?

53 如果在代码中存在大量耗时的函数,你可以考虑用C扩展的方式实现它们。

54、打开apache的mod_deflate模块,可以提高网页的浏览速度。
(提到过echo 大变量的问题)

55、数据库连接当使用完毕时应关掉,不要用长连接。

56、split比exploade快


split()
0.001813 - 0.002271 seconds (avg 0.002042 seconds)
explode()
0.001678 - 0.003626 seconds (avg 0.002652 seconds)
Split can take regular expressions as delimiters, and runs faster too. ~23% on average.

위 내용은 PHP 최적화 및 주의사항에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.