Home »  PHP » PHP7在项目中的实践

PHP7在项目中的实践

成功上线经历的几个阶段

PHP7未出欲出之际,对于它已经是“如雷贯耳”,什么提升性能数倍,什么让PHP变成强类型云云。共事的小伙伴们都是些前沿技术追崇者,一心想把它引入到自身的项目中,于是开始了漫长的尝试,分为以下几个阶段:

第一阶段:观察

PHP7诞生期,作为一个旁观者看网上同仁们的使用概况,并立下军令状,201x年xx月xx日务必完成对于PHP7的升级;

第二阶段:尝试

遇到瓶颈,Mongodb扩展是我们迈不过去的一个大坑。

第三阶段:灰心

好多瓶颈,由于PHP7打破向下兼容的定律,很多扩展也变得不支持,而他们迟迟没有升级解决方案,让小伙伴们瞬间沉入谷底,对于能否升级PHP7表示深深的怀疑。

第四阶段:开花

相对于第一阶段已经过去2~3年的时间,PHP7已经成熟普及在了大街小巷,升级它的欲望不由自主的再次升起。一个下午搜寻了各大英文资料,并进行了多次验证实验,结果是美好的,终于让PHP7在项目中不需要很多改动的情况下运行起来了。

以下是项目中遇到的问题以及解决办法:

差异项 PHP5.6 PHP7.0 解决办法
强类型 对于类型没有严格的检验 对于类型有严格的检验,需要对类型进行重新声明 覆盖全站测试,响应解决
xhprof性能检测工具 具有官方的xhprof扩展 xhprof作为php研发人员的最爱,在之前版本完美支持,但在php7目前不具有该扩展,需要编译安装。 git clone https://github.com/longxinH/xhprof.git ./xhprofcd xhprof/extension/phpize7.0./configure --with-php-config=php-config7.0make && sudo make install
symfony yaml 组件 v2.1.3 v3.3.2 升级
Mysql主从 使用php Mysqlnd_ms扩展 不支持 使用PHP语言自身编写主从代替mysqlnd_ms扩展
Mongodb collection insert 允许 $colelction->insert(['a' => 1]) 不允许,insert方法参数为引用类型,必须传递变量 修正
Mongodb 通过Mongo.so驱动 通过Mongodb.so驱动,并且对于Mongo.so驱动代码完全不兼容 composer安装 https://github.com/alcaeus/mongo-php-adapter 兼容老的代码,但这不是个长久的办法,后续待时间充沛可逐渐往Mongodb.so驱动进行转移。在进行Mongodb操作时不允许使用Mongo.so驱动方式
if语法 允许$a = 1;$b = 0;if($a > $b) {break;} 不允许 break 修正
Framework Error类 服务无Error Class 服务具有Error Class 继承于Throwable 调整Error逻辑
Exception set_exception_handler 回调是Exception对象 PHP7实现了一个全局的throwable接口,原来的Exception和部分Error都实现了这个接口(interface), 以接口的方式定义了异常的继承结构。于是,PHP7中更多的Error变为可捕获的Exception返回给开发者,如果不进行捕获则为Error,如果捕获就变为一个可在程序内处理的Exception。这些可被捕获的Error通常都是不会对程序造成致命伤害的Error,例如函数不存。PHP7进一步方便开发者处理,让开发者对程序的掌控能力更强。因为在默认情况下,Error会直接导致程序中断,而PHP7则提供捕获并且处理的能力,让程序继续执行下去,为程序员提供更灵活的选择。 Exception替换为throwable
composer phpoffice/phpexcel 1.7.9 1.8.1 进行升级
$foo->$bar['baz'] Foo::$bar'baz' $foo->{$bar['baz']} Foo::{$bar['baz']}() ($foo->$bar)['baz'] (Foo::$bar)'baz' 利用正则全局搜索更改调用方式.例如:$foo->$bar['baz']可加入{}进行解析优先级标识$foo->{$bar['baz']}

第五阶段,筹备

经过第四阶段的实验,PHP7看情况要呼之欲出啦,但情况不仅其然,仍有很多障碍在前进的见路旁,比如:

以下是研发双环境解决办法(ubuntu14.04):

>小技巧:观察是否使用此源,可查看 /et/php/ 下是否具有 5.6/ 7.0/ 7.1/ 目录,如果具有,说明使用了这个源.

sudo add-apt-repository ppa:ondrej/php # 下面所有的操作都是根据这个源而来的,如果具有其他的php软件源可进行卸载,后再去安装此源
sudo apt-get update
sudo apt-get purge php5 php5-cli php5-common php5-dev php5-fpm
sudo apt-get install php5.6 php5.6-dev php5.6-fpm php5.6-mbstring php5.6-mysql php-xml php5.6-xml php-mongo php-redis php5.6-zip

sudo apt-get install php7.0 php7.0-dev php-mongodb php7.0-fpm php7.0-mbstring php7.0-mysql  php-pear php7.0-xml php7.0-zip
sudo pecl install redis #遇到提示,请输入:yes,一路狂奔
sudo apt-get install php7.0-zip
sudo apt-get install php7.0-curl
sudo apt-get install php-imagick
sudo ln -sf /etc/php/7.0/mods-available/redis.ini /etc/php/7.0/fpm/conf.d/20-redis.ini
sudo ln -sf /etc/php/7.0/mods-available/redis.ini /etc/php/7.0/cli/conf.d/20-redis.ini
sudo service php7.0-fpm restart

第三步

项目中编写环境切换脚本

#!/usr/bin/env php
<?php

function php70()
{
    shell_exec("sudo update-alternatives --set php /usr/bin/php7.0");
    $php70FpmConf = '/etc/php/7.0/fpm/pool.d/www.conf';
    $php56FpmConf = '/etc/php/5.6/fpm/pool.d/www.conf';
    if (file_exists($php56FpmConf)) {
        shell_exec("sudo sed -i 's/"."127.0.0.1:9000"."/"."\/run\/php\/php5.6-fpm.sock"."/g' {$php56FpmConf}");
        shell_exec("sudo service php5.6-fpm restart");
    } else {
        throw new \Exception("php 5.6 fpm conf not find");
    }

    if (file_exists($php70FpmConf)) {
        shell_exec("sudo sed -i 's/"."\/run\/php\/php7.0-fpm.sock"."/"."127.0.0.1:9000"."/g' {$php70FpmConf}");
        shell_exec("sudo service php7.0-fpm restart");
    } else {
        throw new \Exception("php 7.0 fpm conf not find");
    }

}

function php56()
{
    shell_exec("sudo update-alternatives --set php /usr/bin/php5.6");
    $php70FpmConf = '/etc/php/7.0/fpm/pool.d/www.conf';
    $php56FpmConf = '/etc/php/5.6/fpm/pool.d/www.conf';
    if (file_exists($php56FpmConf)) {
        shell_exec("sudo sed -i 's/"."\/run\/php\/php5.6-fpm.sock"."/"."127.0.0.1:9000"."/g' {$php56FpmConf}");
        shell_exec("sudo service php5.6-fpm restart");
    } else {
        throw new \Exception("php 5.6 fpm conf not find");
    }

    if (file_exists($php70FpmConf)) {
        $strContent = file_get_contents($php70FpmConf);
        shell_exec("sudo sed -i 's/"."127.0.0.1:9000"."/"."\/run\/php\/php7.0-fpm.sock"."/g' {$php70FpmConf}");
        shell_exec("sudo service php7.0-fpm restart");
    } else {
        throw new \Exception("php 7.0 fpm conf not find");
    }
}

if (isset($_SERVER['argv']) &&
    isset($_SERVER['argv'][1])) {
    if ($_SERVER['argv'][1] === 'php70') {
        php70();
    }
    if ($_SERVER['argv'][1] === 'php56') {
        php56();
    }
}

第六阶段,结果

终于经过小伙伴们的层层努力,PHP7迭代顺利升级到线上,开花结果;

预计进行引入的几个特性

异常捕获机制优化,防止错误冒泡

强类型

传参

一行代码引入多个命名空间

升级总结