>  기사  >  백엔드 개발  >  PHP 효율성 및 최적화 개선을 위한 몇 가지 제안

PHP 효율성 및 최적화 개선을 위한 몇 가지 제안

零到壹度
零到壹度원래의
2018-05-15 10:56:181913검색

이 문서의 내용은 PHP 효율성 및 최적화 향상에 대한 몇 가지 제안을 공유하기 위한 것입니다. 특정 참고 가치가 있습니다. 도움이 필요한 친구가 참조할 수 있습니다.

1 문자열

1.1 정규 표현식을 덜 사용하세요.
표현식은 PHP의 내부 문자열 조작 함수를 사용할 수 있습니다. 정규 표현식보다 효율성이 높기 때문에 정규 표현식 대신 사용해 보세요.
정규화가 성능을 가장 많이 소모한다는 것은 말할 필요도 없습니다.
str_replace 함수는 preg_replace보다 훨씬 빠르고 strtr 함수는 str_replace보다 빠릅니다.
놓친 유용한 기능이 있나요?
예: strpbrk(), strncasecmp(), strpos(), strrpos(), Stripos(), strripos().
1.2 문자 교체
단일 문자만 변환해야 한다면 문자열을 strtr() 함수로 사용하여 배열 대신 교체를 완료하세요.
$addr = strtr($addr, "abcd", " efgh"); / / 권장
$addr = strtr($addr, array('a' => 'e', ​​​​)); // 권장하지 않음
효율성 향상: 10배.
str_replace 문자 교체는 일반 교체 preg_replace보다 빠르지만 strtr은 str_replace보다 1/4 빠릅니다.
또한 불필요한 대체를 수행하지 마십시오. str_replace는 대체 없이도 매개변수에 메모리를 할당합니다. 매우 느리다!
strpos를 사용하여 먼저(매우 빠르게) 검색하여 교체가 필요한지 확인하고, 그렇다면 교체하세요.
교체가 필요한 경우 효율성은 거의 동일하며 그 차이는 약 0.1%입니다.
교체가 필요하지 않은 경우: strpos를 사용하면 200% 더 빠릅니다.
1.3 큰 문자열 압축
gzcompress() 및 gzuncompress()를 사용하여 큰 문자열을 압축 및 압축 해제한 다음 데이터베이스에서 저장하고 검색합니다.
이 내장 기능은 gzip 알고리즘을 사용하며 문자열을 90%까지 압축할 수 있습니다.
1.4 에코 출력
에코 문자열은 도트 커넥터 대신 쉼표를 사용하여 더 빠르게 만듭니다.
하지만 echo는 실제 기능이 아닌 언어 구조입니다.
그러나 쉼표로 구분된 여러 문자열을 "함수" 매개변수로 전달할 수 있으므로 속도가 더 빨라집니다.
echo $str1, $str2; // 빠름
echo $str1 . $str2; // 약간 느림

1.5 작은따옴표를 사용해 보세요
PHP 엔진에서는 작은따옴표와 큰따옴표를 사용하여 문자열 변수를 캡슐화할 수 있습니다. . 하지만 속도는 매우 다릅니다!
큰따옴표로 묶인 문자열을 사용하면 PHP 엔진이 먼저 문자열 내용을 읽고 그 안에 있는 변수를 찾은 다음 변수에 해당하는 값으로 변경하도록 지시합니다.
일반적으로 문자열에는 변수가 없으며 큰따옴표를 사용하면 성능이 저하됩니다.
큰따옴표로 묶은 문자열 대신 문자열 연결을 사용하는 것이 더 좋습니다.

$output = "This is a plain string";  // 不好的实践
$output = 'This is a plain string';  // 好的实践
$type = "mixed";                     // 不好的实践
$output = "This is a $type string";
$type = 'mixed';                     // 好的实践
$output = 'This is a ' . $type . ' string';

1.6 strlen 대신 isset을 사용하세요
문자열의 길이를 확인할 때 가장 먼저 생각한 것은 strlen() 함수를 사용하는 것입니다.
이 함수는 어떤 계산도 하지 않고 zval 구조(PHP 변수를 저장하는 데 사용되는 C의 내장 데이터 구조)에 저장된 알려진 문자열 길이만 반환하기 때문에 매우 빠르게 실행됩니다.
단, strlen()은 함수이기 때문에 함수 호출이 소문자, 해시 검색 등 여러 단계를 거쳐 호출된 함수와 함께 실행되기 때문에 다소 느릴 것입니다.
어떤 경우에는 isset() 트릭을 사용하여 코드 실행 속도를 높일 수 있습니다. 예:

if (strlen($foo) < 5) {
    echo "Foo is too short";
}
// 使用isset()
if (!isset($foo{5})) {
    echo "Foo is too short";
}

1.7 문자열을 분할하려면 분할을 사용하세요
문자열을 분할할 때는 분할()이 폭발()보다 빠릅니다.

split()
0.001813 - 0.002271초(평균 0.002042초)
explode()
0.001678 - 0.003626초(평균 0.002652초)

1.8 에코가 인쇄보다 효율적입니다.
echo는 값을 반환하지 않기 때문에, print는 하나의 Integer 유형을 반환합니다.
참고: echo가 큰 문자열을 출력할 때 조정이 없으면 성능에 심각한 영향을 미칩니다.
압축을 위해 Apache의 mod_deflate를 켜거나, ob_start를 켜서 콘텐츠를 버퍼에 넣으면 성능 문제가 개선될 수 있습니다.

2개 성명

2.1 最好不用@
用@掩盖错误会降低脚本运行速度,并且在后台有很多额外操作。
用@比起不用,效率差距 3 倍。特别不要在循环中使用@。
在 5 次循环的测试中,即使是先用error_reporting(0)关掉错误,循环完成后再打开,都比用@快。
2.2 避免使用魔术方法
对于__开头的函数就命名为魔术函数,它们都在特定的条件下触发。
这些魔术函数包括:__construct()、__get()、__call()、__autoload()等等。
以__autoload() 为例,如果不能将类名与实际的磁盘文件对应起来,将不得不做大量的文件存在判断。
而判断文件存在需要磁盘I/O操作,众所周知,磁盘I/O操作的效率很低,因此这才是使得autoload机制效率降低的原因。
因此,在系统设计时,需要定义一套清晰的、将类名与实际磁盘文件映射的机制。
这个规则越简单越明确,__autoload()机制的效率就越高。
autoload机制并不是天然的效率低下,只有滥用autoload、设计不好的自动装载函数,才会导致其效率的降低.
所以说,尽量避免使用__autoload等魔术方法,有待商榷。
2.3 别在循环里用函数
例如:

for($x=0; 
$x < count($array); 
$x++) {
}

这种写法在每次循环的时候都会调用 count() 函数,效率大大降低,建议这样:

$len = count($array);
for($x=0; $x < $len; $x++) {
}

让函数在循环外面一次获得循环次数。
2.4 使用三元运算符
在简单的判断语句中,三元运算符?:更简洁高效。
2.5 使用选择分支语句
switch、case好于使用多个if、else if语句,并且代码更加容易阅读和维护。
2.6 屏蔽敏感信息
使用 error_reporting() 函数来预防潜在的敏感信息显示给用户。
理想的错误报告应该被完全禁用在php.ini文件里
如果用的是共享虚拟主机,php.ini不能修改,最好添加 error_reporting() 函数。
放在每个脚本文件的第一行,或者用require_once()来加载,能有效的保护敏感的SQL查询和路径,在出错时不被显示。
2.7 不实用段标签34be907719e18072f62a198f7caa6408这种方式是鼓励的,可以是代码更加简洁。
2.8 纯PHP代码不加结束标记
如果文件内容是纯 PHP 代码,最好在文件末尾删除 PHP 结束标记?>。
这可以避免在 PHP 结束标记之后万一意外加入了空格或者换行符,会导致 PHP 开始输出这些空白,而脚本中此时并无输出的意图。
2.9 永远不要使用register_globals和magic quotes
这是两个很古老的功能,在当时(十年前)也许是一个好方法,但现在看来并非如此。
老版本的PHP在安装时会默认打开这两个功能,这会引起安全漏洞、编程错误及其他的问题。
如只有用户输入了数据时才会创建变量等。
PHP5.4.0开始这两个功能都被舍弃了,所以每个程序员都应该避免使用。
如果你过去的程序有使用这两项功能,那就尽快将其剔除吧。
3 函数
3.1 尽量使用PHP内部函数
内置函数使用C语言实现,并且经过PHP官方优化,效率更高。
3.2 使用绝对路径
在include和require中尽量使用绝对路径。
如果包含相对路径,PHP会在include_path里面遍历查找文件。
用绝对路径就会避免此类问题,解析路径所需的时间会更少。
3.3 包含文件
尽量不要用require_once和include_once包含文件,它们多一个判断文件是否被引用的过程,能不用尽量不用。
而使用require、include方法代替。
鸟哥在其博客中就多次声明,尽量不要用require_once和include_once。
3.4 函数快于类方法
调用只有一个参数、并且函数体为空的函数,花费的时间等于7-8次$localvar++运算。
而同一功能的类方法大约为15次$localvar++运算。
3.5 用子类方法
基类里面只放能重用的方法,其他功能尽量放在子类中实现,子类里方法的性能优于在基类中。
3.6 类的性能和其方法数量没有关系
新添加10个或多个方法到测试的类后,性能没什么差异。
3.7 读取文件内容
在可以用file_get_contents()替代file()、fopen()、feof()、fgets()等系列方法的情况下,尽量用file_get_contents()。
因为他的效率高得多!
3.8  引用传递参数
通过参数地址引用的方式,实现函数多个返回值,这比按值传递效率高。
方法是在参数变量前加个 &。
3.9 方法不要细分得过多
仔细想想你真正打算重用的是哪些代码?
3.10 尽量静态化
如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍。
当然了,这个测试方法需要在十万级以上次执行,效果才明显。
其实,静态方法和非静态方法的效率主要区别在内存。
静态方法在程序开始时生成内存,实例方法(非静态方法)在程序运行中生成内存。
所以,静态方法可以直接调用,实例方法要先成生实例再调用,静态速度很快,但是多了会占内存。
任何语言都是对内存和磁盘的操作,至于是否面向对象,只是软件层的问题,底层都是一样的,只是实现方法不同。
静态内存是连续的,因为是在程序开始时就生成了,而实例方法申请的是离散的空间,所以当然没有静态方法快。
静态方法始终调用同一块内存,其缺点就是不能自动进行销毁,而实例化可以销毁。
3.11 用C扩展方式实现
코드에 시간이 많이 걸리는 함수가 많다면 C 확장으로 구현하는 것을 고려해 보세요.
4 변수
4.1 시간에 따라 변수 삭제
배열, 개체 및 GLOBAL 변수는 특히 PHP에서 메모리를 차지합니다. 이는 PHP의 기본 zend 엔진으로 인해 발생합니다.
일반적으로 PHP 배열의 메모리 활용도는 1/10에 불과합니다.
즉, C 언어에서 100M 메모리 배열은 PHP에서 1G가 필요합니다.
특히 PHP를 백엔드 서버로 사용하는 시스템에서는 과도한 메모리 소모 문제가 자주 발생합니다.
4.2 $_SERVER 변수를 사용하세요
스크립트 실행 시간을 구해야 한다면 time()보다 $_SERVER['REQUSET_TIME']이 더 좋습니다.
하나는 기성품으로 바로 사용할 수 있고, 다른 하나는 함수를 통해 얻은 결과가 필요합니다.
4.3 메소드에서 지역 변수 생성
클래스 메소드에서 지역 변수를 생성하는 것은 메소드에서 지역 변수를 호출하는 것만큼 빠르며 거의 빠릅니다.
4.4 지역 변수는 전역 변수보다 빠릅니다.
지역 변수는 스택에 저장되기 때문입니다.
함수가 차지하는 스택 공간이 그다지 크지 않으면 메모리의 이 부분이 캐시에 부딪힐 가능성이 높으며 CPU 액세스 효율성이 매우 높습니다.
반대로 함수가 전역 변수와 지역 변수를 동시에 사용하는 경우 두 주소의 차이가 클 경우 CPU 캐시를 앞뒤로 전환해야 하므로 효율성이 떨어집니다.
4.5 객체 속성 대신 지역 변수
객체 속성(클래스의 변수, 예: $this->prop++) 생성은 지역 변수보다 3배 느립니다.
4.6 지역 변수를 미리 선언하세요
선언되지 않은 지역 변수를 만드는 것은 이미 정의된 지역 변수를 만드는 것보다 9~10배 느립니다.
4.7 전역 변수 선언은 주의하세요
어떤 함수에서도 사용되지 않은 전역 변수를 선언하면 성능이 저하됩니다.
이것은 동일한 수의 로컬 변수를 선언하는 것과 같습니다. PHP는 전역 변수가 존재하는지 확인할 수 있습니다.
4.8 ++$i를 사용하여 증가
변수 $i의 증가 또는 감소를 수행할 때 $i++는 ++$i보다 느립니다.
이 차이점은 PHP에만 해당되며 다른 언어에는 적용되지 않습니다. 따라서 C 또는 Java 코드를 수정하지 말고 즉시 더 빨라질 것으로 기대하세요. 작동하지 않습니다.
++$i에는 3개의 명령어(opcode)만 필요하고 $i++에는 4개의 명령어가 필요하므로 더 빠릅니다.
사후 증가는 실제로 이후에 증가되는 임시 변수를 생성합니다.
접두사 증가는 원래 값에서 직접 증가합니다.
이것은 Zend의 PHP 최적화 프로그램과 마찬가지로 최적화 형태입니다.
모든 명령어 최적화 프로그램이 동일한 최적화를 수행하는 것은 아니기 때문에 이 최적화는 좋은 생각이라는 점을 명심하세요.
4.9 변수를 함부로 복사하지 마세요
때때로 PHP 코드를 더 깔끔하게 만들기 위해 일부 PHP 초보자(저 포함)는 미리 정의된 변수를 더 짧은 이름의 변수에 복사합니다.
실제로 이로 인해 메모리 소비가 두 배로 늘어나 프로그램 속도가 느려질 뿐입니다.
아래 예에서 사용자가 악의적으로 512KB의 텍스트를 삽입하면 1MB의 메모리가 소모된다고 상상해보세요!

// 不好的实践
$description = $_POST[&#39;description&#39;];
echo $description;
// 好的实践
 echo $_POST[&#39;description&#39;];

4.10 循环内部不要声明变量
尤其是大变量,这好像不只是PHP里面要注意的问题吧?
4.11 一定要对变量进行初始化
这里的“初始化”指的是“声明”。
当需要没有初始化的变量,PHP解释器会自动创建一个变量,但依靠这个特性来编程并不是一个好主意。
这会造成程序的粗糙,或者使代码变得另人迷惑。
因为你需要探寻这个变量是从哪里开始被创建的。
另外,对一个没有初始化的变量进行递增操作要比初始化过的来得慢。
所以对变量进行初始化会是个不错的主意。
5 数组
5.1 用字符串而不是数组作为参数
如果一个函数既能接受数组,又能接受简单字符做为参数,那么尽量用字符作为参数。
例如,字符替换函数,参数列表并不是太长,就可以考虑额外写一段替换代码。
使得每次传递参数都是一个字符,而不是接受数组做为查找和替换参数。
5.2 数组元素加引号
$row['id']比$row[id]速度快7倍。
如果不带引号,例如$a[name],那么PHP会首先检查有没有define定义的name常量
如果有,就用这个常量值作为数组键值。如果没有,再查找键值为字符串'name'的数组元素。
多了一个查找判断的过程,所以建议养成数组键名加引号的习惯。
正如上面字符串部分所述,用'又比用"速度更快。
5.3 多维数组操作
多维数组尽量不要循环嵌套赋值。
5.4 循环用foreach
尽量用foreach代替while和for循环,效率更高。
6 架构
6.1 压缩输出
在php.ini中开启gzip压缩:
zlib.output_compression = On
zlib.output_compression_level = (level)
level可能是1-9之间的数字,你可以设置不同的数字。
几乎所有的浏览器都支持Gzip的压缩方式,gzip可以降低80%的输出.
付出的代价是,大概增加了10%的cpu计算量。
但是还是会赚到了,因为带宽减少了,页面加载会变得很快。
如果你使用apache,也可以激活mod_gzip模块。
6.2 静态化页面
Apache/Nginx解析一个PHP脚本的时间,要比解析一个静态HTML页面慢2至10倍。
所以尽量使页面静态化,或使用静态HTML页面。
6.3 将PHP升级到最新版
提高性能的最简单的方式是不断升级、更新PHP版本。
6.4 利用PHP的扩展
一直以来,大家都在抱怨PHP内容太过繁杂。
最近几年来,开发人员作出了相应的努力,移除了项目中的一些冗余特征。
即便如此,可用库以及其它扩展的数量还是很可观。
甚至一些开发人员开始考虑实施自己的扩展方案。
6.5 PHP缓存
一般情况下,PHP脚本被PHP引擎编译后执行,会被转换成机器语言,也称为操作码。
如果PHP脚本反复编译得到相同的结果,为什么不完全跳过编译过程呢?
PHP加速器缓存了编译后的机器码,允许代码根据要求立即执行,而不经过繁琐的编译过程。
对PHP开发人员而言,目前提供了两种可用的缓存方案。
一种是APC(Alternative PHP Cache,可选PHP缓存),它是一个可以通过PEAR安装的开源加速器。
另一种流行的方案是OPCode,也就是操作码缓存技术。
6.6 使用NoSQL缓存
Memchached或者Redis都可以。
这些是高性能的分布式内存对象缓存系统,能提高动态网络应用程序性能,减轻数据库的负担。
这对运算码 (OPcode)的缓存也很有用,使得脚本不必为每个请求重新编译。

위 내용은 PHP 효율성 및 최적화 개선을 위한 몇 가지 제안의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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