常用技术分享:PHP 5和PHP 7在开发中最常遇到的兼容性写法总结

王志勇 发表于 2019年06月30日 11:41

PHP 7引入了强类型,在报错方面比PHP 5严格了很多。所以,很多PHP 5下开发的程序,到了PHP 7会有各种报错、无法运行。其实,只要稍加改动,原来的PHP 5程序就可以兼容PHP 7的语法,但无疑改动的工作量是难以估计的,需要对每个模块都重新测试。这种改动不像前端设计所见所得,程序由于模块数量庞大,可能会有少量改动不彻底而引发bug

服务器版的PHP的php.ini,默认是不显示报错,即display_errors=Off,所以看不到报错。程序开发当中,则必须把display_errors改为display_errors=On,根据报错内容开发、修改程序。

很多PHP教程、技术文章或博客,字符串使用的是双引号,例如$a1="abc";。应该尽量改为单引号,在HTML、JavaScript、CSS里双引号、单引号没有区别,但是PHP里有区别。
PHP里的单引号的执行效率更高。使用双引号,解释器需要搜索字符串里可能存在的变量,例如:$a1="abc$a2";,如果改成这样,解释器则不搜索(可能存在的变量):$a1='abc'.$a2;

所以,PHP使用单引号是一个好习惯

我个人在开发中,尽量地减少使用某一版本的新特性,从而使程序能在更多平台下运行。我最近6个月编写的新程序,都是在PHP 5开发的,现在需要全部改写为PHP 7的写法。

PHP 5和PHP 7在开发中,最常遇到的兼容性写法:

1. $_POST、$_GET、$_COOKIE,到了PHP 7,必须给它们加上一个@号,可以防止报错,例如:

下列3行在PHP 5下永远不会报错,但在PHP 7,当它们的值不存在时,会报错:
$a1=$_POST['c1'];
$a2=$_GET['c2'];
$a3=$_COOKIE['c3'];

改为这样可以兼容PHP 5、PHP 7,不会报错:
$a1=@$_POST['c1'];
$a2=@$_GET['c2'];
$a3=@$_COOKIE['c3'];

2. 事先清空数组,防止复杂的程序里出现的数据错乱,在PHP 5里,过去我一直用这样的方法,不会报错,这是十分常用的基本语句:
$a1='';
$a1[1]='abc';

到了PHP 7,如上这样写会报错。因为PHP 7,增强了数据类型。必须改成这样可以清空数组,可以兼容PHP 5、PHP 7:
$a1=array();
$a1[1]='abc';

3. if语句当中出现的符合条件才赋值的变量$a1,必须先声明这个变量$a1。如果不事先声明,在PHP 5下永远不会报错,但是PHP 7会报错。

例如这样写,PHP 5不会报错,到了PHP 7会报错:
if ($b1==3) $a1='abc';

PHP 7必须这样写:
$a1='';
if ($b1==3) $a1='abc';

同时,有时候$b1的变量也是需要符合条件,它才会存在,上述程序依然会报错,特殊情况、必要时要这样写:
$a1='';
if (@$b1==3) $a1='abc';

2019-08-05 22:31更新
或者在某种很特殊的情况下可以这样声明变量$b1,如下列的第2行,兼容PHP 7、PHP 5:
$a1='';
if (!@$b1) $b1=0;
if ($b1==3) $a1='abc';

说明:第2行的if (!@$b1) $b1=0;,这一行在PHP 5不需要声明变量$b1,PHP 7在很特殊的环境里,可以通过这种方式声明变量$b1,以防止报错。

if (!@$b1)的语法说明,if (!$b1)是PHP 5的写法,它的含义相当于if ($b1==''),或者if ($b1==0),或者if ($b1==false)。到了PHP 7,需要在$b1前加个@以防止报错,就是if (!@$b1),这个写法在PHP 5下也正常运行。
(更新完毕)

4. PHP 7删去了少部分的超全局变量$_SERVER,例如$_SERVER['HTTP_X_FORWARDED_FOR']。这个变量的作用是获得用户的真实IP,如果使用了此变量,会报错。只能用:$ip=$_SERVER['REMOTE_ADDR'];

5. 在PHP 7下开发程序时,还需要尽量兼顾PHP 5的写法,使这2个版本的写法整体一致,达到互相兼容。比如PHP 7的新的写法,太空船写法:
echo $a <=> $b;

这样的写法,对于发布版的程序,尽量不使用,否则在PHP 7下开发的程序,在PHP 5下会报错。

有关报错的错误级别
上述列举的5种情形,只有第2种的错误级别最高,其余的4种情况,PHP 7通过error_reporting(0);语句可以屏蔽、或防止报错,程序可以正常运行。
第2种情形,即使屏蔽了报错,程序依然无法正常运行,并可能导致数据写入严重错误,必要时需要用$a1=array();语句来事先清空数组。

Feedval是PHP 5下开发,正在全力改为兼容PHP 5、PHP 7的写法。

2019-06-30 21:26更新:
第1种情形相对好改一些,用批量查找、替换。
第3种情形,最容易出现。

2019-07-03 08:33更新:
变量$_SERVER['HTTP_REFERER']必须改为@$_SERVER['HTTP_REFERER'],即:
$a1=@$_SERVER['HTTP_REFERER'];

这个变量的作用是获得访问来源,当访问来源为空时,$a1=$_SERVER['HTTP_REFERER'];在PHP 7下会报错。

2019-08-08 12:08更新:
同上述的第3种情形,但是,是在循环程序里的数组,这一种情形还特别常出现,例如PHP 5时这样写不会报错:

$b3=array();
……
for ($g=0;$g<=6;$g++) $b3[$a1].="\n".$o4[$s+$g]; //(第3行)

上述的省略号表示这当中穿插了别的程序语句。第3行在PHP 7下会报错,因为$b3[$a1]第一次被引用的时候,值是空的,所以会报错

在PHP 7里,当需要引用数组变量时,如果这个变量是空的,那么需要对数组里的每个值都一一声明变量,否则会报错。为了省事,很多时候用循环程序给每个值都一一声明变量。

改成这样,可以解决报错:

for ($g=0;$g<=6;$g++) @$b3[$a1].="\n".$o4[$s+$g];

这种写法相当于在第一次赋值时,加个@防止变量为空。于是我试验了这样的写法,在容易报错的(数组的)变量前加个@:

<?@$b3[1]='abc';
echo $b3[1];?>

运行结果为:abc
在PHP 7、PHP 5下都正常运行,无报错。

这种写法,在很多年以后的未来的PHP 8、PHP 9,说不定会报错,所以改为这样,肯定不会报错:

<?if (!@$b3[1]) $b3[1]='';
……
$b3[1]='abc';
echo $b3[1];?>

同样的,循环程序改成这样:

$b3=array();
……
for ($g=0;$g<=6;$g++){if (!@$b3[$a1]) $b3[$a1]='';$b3[$a1].="\n".$o4[$s+$g];}

10条评论:
1   自由勇 2019-06-30 21:26
第1种情形相对好改一些,用批量查找、替换。
第3种情形,最容易出现。
2   angel2018 2019-06-30 21:42
勇哥,你熟悉了php5,再进阶到php7,估计很快就能适应了。我想的是,在同一种php语言思维架构方面,版本升级到更高,但框架是不是相差不太大。既然是升级的更高的版本,在规范规则方面,就会去掉少部或部分原有的,加入新的语法逻辑。

不知道我的想法是否和勇哥最近使用php7之后一样呢?

自由勇 2019-06-30 21:44
是的,思维架构基本上没有变化。对于我个人,开发中遇到的PHP 5和PHP 7的不同主要在于本文的总结,其它地方我个人编写的程序不需要改动就能互相兼容,所以这次在程序上PHP 5转PHP 7还是比较顺利。

自由勇 2019-06-30 21:49
我工作的开发环境,变化很大。因为PHP 7,目前无论如何都无法在XP系统上安装,应该是微软禁止的。只能等待将来有第三方开发者,开发XP系统下的PHP 7平台。

一开始用了几天我把开发环境部署在Win 10,但是系统的配色长时间工作感觉很刺眼。
现在是在Win 7下开发PHP 7。

3   angel2018 2019-07-01 01:54
勇哥,win 7把桌面优化一下,还是相接近XP的。win10,经过2-3个版本迭代了,是很大改动。

要不,或者下个win2003系统试试,看能不能支持php7,win2003的架构界面也很接近xp系统。

自由勇 2019-07-01 07:27
好的,有时间我再试试Win 2003,应该是和XP的内核一样。
我用的Win 7、Win 10已经经过优化,部署了一样的环境,安装所有完全一样的软件。唯一不一样的是,Win 7、Win 10不支持XP时代的自定义开始菜单。

没有了自定义开始菜单,每次打开工作的文件夹或软件,需要多花费5-10秒,每天这样的操作50-200次以上。

微软几年前已经在封(隔开)杀XP,从H81主板(可通过注入解决),到后来的火狐、谷歌浏览器高版本,再到现在的Apache 2.4.39、PHP 7,都是人为地不支持。

4   自由勇 2019-08-08 12:24
2019-08-05 22:31更新:
或者在某种很特殊的情况下可以这样声明变量$b1,如下列的第2行,兼容PHP 7、PHP 5:
$a1='';
if (!@$b1) $b1=0;
if ($b1==3) $a1='abc';

说明:第2行的if (!@$b1) $b1=0;,这一行在PHP 5不需要声明变量$b1,PHP 7在很特殊的环境里,可以通过这种方式声明变量$b1,以防止报错。

if (!@$b1)的语法说明,if (!$b1)是PHP 5的写法,它的含义相当于if ($b1==''),或者if ($b1==0),或者if ($b1==false)。到了PHP 7,需要在$b1前加个@以防止报错,就是if (!@$b1),这个写法在PHP 5下也正常运行。

5   自由勇 2019-08-08 12:25
2019-08-08 12:08更新:
同上述的第3种情形,但是,是在循环程序里的数组,这一种情形还特别常出现,例如PHP 5时这样写不会报错:

$b3=array();
……
for ($g=0;$g<=6;$g++) $b3[$a1].="\n".$o4[$s+$g]; //(第3行)

上述的省略号表示这当中穿插了别的程序语句。第3行在PHP 7下会报错,因为$b3[$a1]第一次被引用的时候,值是空的,所以会报错。

在PHP 7里,当需要引用数组变量时,如果这个变量是空的,那么需要对数组里的每个值都一一声明变量,否则会报错。为了省事,很多时候用循环程序给每个值都一一声明变量。

改成这样,可以解决报错:

for ($g=0;$g<=6;$g++) @$b3[$a1].="\n".$o4[$s+$g];

这种写法相当于在第一次赋值时,加个@防止变量为空。于是我试验了这样的写法,在容易报错的(数组的)变量前加个@:

<?@$b3[1]='abc';
echo $b3[1];?>

运行结果为:abc
在PHP 7、PHP 5下都正常运行,无报错。

这种写法,在很多年以后的未来的PHP 8、PHP 9,说不定会报错,所以改为这样,肯定不会报错:

<?if (!@$b3[1]) $b3[1]='';
……
$b3[1]='abc';
echo $b3[1];?>

同样的,循环程序改成这样:

$b3=array();
……
for ($g=0;$g<=6;$g++){if (!@$b3[$a1]) $b3[$a1]='';$b3[$a1].="\n".$o4[$s+$g];}

6   angel2018 2019-08-15 03:36
勇哥,博客又切换回美国VPS了?哈哈。
:)
香港的VPS的问题,还是没解决到吗?

自由勇 2019-08-15 10:43
是的,换回美国VPS有一个多星期了。
之前香港的VPS很不稳定,有时一天宕机三四次。

之后他们升级了,一直稳定,我用 uptime 命令测试,一直在线。就是前天他们更换内存,停机几小时。
最近没有时间,有时间再换回香港VPS试试。

美国VPS很少宕机。

发表评论:
名字: (*必填)
博客: (可省)

正文:

  记住信息?

直接发送Trackback到此文章

说明:本评论系统不支持HTML代码。(您的留言需要审核,审核规则请见这里。)

王志勇:1980-09-26 (39周岁)
程序设计,前端设计。

版权声明:本博客所有文章,均符合原创的定义,禁止转载,违者将必究;正确的方法是贴原文的标题和网址即可。

与此相关的链接
自由勇专栏

Blog存档 Archives

2019年09月
2019年08月
2019年07月
2019年06月
2019年05月
2019年04月(30)
2019年03月(30)
2019年02月(30)
2019年01月(30)
2018年12月(30)
2018年11月(30)
2018年10月(30)
2018年09月(17)
2016年-2017年(9)
2014年06月-09月(10)
2013年 +

2012年 +
2011年 +
2010年 +
2009年 +
2008年 +
2007年 +
2006年 +
2005年09月(4)

Copyright © 2006-2019 auiou.com All rights reserved.
此Blog程序由王志勇编写 已经发布在Arsue