这里说下,一开始发表的是编译升级到php5.5.0,可是后来我发现了config.nice之后,就补充了一篇更简单的升级办法,就是后来的PHP5.4的升级
那为什么今天要补充一篇平滑升级到5.6.0呢,因为今天我升级的时候碰到了几个小问题,具体细节,下面会详细说明
在这之前我想说下,这次的升级是平滑升级。群里以及在网上看到不少朋友有类似这样的顾虑
[success]为什么PHP更新这么频繁?更新是不是要重启服务?我是不是要关闭网站?[/success]
这里我稍微总结几点:
既然是平滑升级,是不需要宕机,也不需要停止服务,是不存在关闭网站的说法
而升级最后的重启,重启的是PHP加载的配置文件,不影响你当前运行的网站
php-fpm是属于FastCgi,一旦启动是在内存中跑的,和你编译升级的过程没有任何关系
[success]
你可以从这篇文章了解什么是FastCgi
什么是CGI、FastCGI、PHP-CGI、PHP-FPM、Spawn-FCGI?
http://levi.yii.so/archives/1068
[/success]
但是不是说平滑升级了,就没有问题了,他最大的一个问题在于:升级PHP后,和你当前项目存在不兼容的部分。
一般而言PHP每次升级,不会和上一个版本出现较明显的不兼容,如果你的项目也一直在更新,可以不用当心。
然而如果你的项目非常老旧,我建议可以在每个大项目做一次更新,比如PHP5.4-PHP5.5、PHP5.5-PHP5.6,一般这样的版本更新至少也要间隔1年左右的时间了
[success]
我不建议长期守着较旧的版本,或者来个飞跃比较大的更新,往往这样才会出现大问题。当然,你可以根据自己习惯来决定何时更新。
[/success]
平滑升级PHP
OK,聊到这里说回正题,之前的文章有提到,平滑升级PHP非常简单,只要如下操作即可,并且我这次的升级也是如此照做
wget http://am1.php.net/get/php-5.6.0.tar.gz/from/this/mirror
tar -zvxf mirror
cp php-5.5.16/config.nice php-5.6.0/
cd php-5.6.0/
./config.nice
make ZEND_EXTRA_LIBS='-liconv'
make install
# 更新后会看到提示几个建议的操作
/root/php-5.6.0/build/shtool install -c ext/phar/phar.phar /usr/local/webserver/php-d/php-5.5.0/bin
ln -s -f /usr/local/webserver/php-d/php-5.5.0/bin/phar.phar /usr/local/webserver/php-d/php-5.5.0/bin/phar
/usr/local/webserver/php-d/php-5.5.0/bin/pecl php-ini /usr/local/webserver/php-d/php-5.5.0/etc/php.ini
一切顺利,拷贝一个PHP执行文件到启动目录,查看下当前版本
ln -f /usr/local/webservice/php-d/php/php-5.5.0/bin/php /etc/init.d/
service php -v
[success]我之前安装PHP的时候,由于安装目录位置在php-5.5.0,所以现在平滑升级也是在这个目录,大家下面看到这个目录嫑觉得奇怪[/success]
问题出现了,如下
Zend OPcache requires Zend Engine API version 220121212.
The Zend Engine API version 220131226 which is installed, is newer.
Contact Zend Technologies at http://www.zend.com/ for a later version of Zend OPcache.
PHP Warning: PHP Startup: imagick: Unable to initialize module
Module compiled with module API=20121212
PHP compiled with module API=20131226
These options need to match
in Unknown on line 0
PHP Warning: PHP Startup: memcache: Unable to initialize module
Module compiled with module API=20121212
PHP compiled with module API=20131226
These options need to match
in Unknown on line 0
PHP Warning: PHP Startup: pdo_mysql: Unable to initialize module
Module compiled with module API=20121212
PHP compiled with module API=20131226
These options need to match
in Unknown on line 0
PHP Warning: PHP Startup: redis: Unable to initialize module
Module compiled with module API=20121212
PHP compiled with module API=20131226
These options need to match
in Unknown on line 0
PHP 5.6.0 (cli) (built: Aug 30 2014 11:03:17)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
从提示上去理解很容易,PHP编译的扩展的内核和当前PHP内核不一致,那就说重新编译下扩展即可。
[success]处于好奇,我在网上搜了下,见到不少朋友的奇葩方法,比如把PHP重装回去,这里就不推荐了。[/success]
重新编译扩展
具体方法之前已提到过了,大家可以[点击这里查看查看详细文档],这里我就只用imagick来举例,代码如下:
wget http://pecl.php.net/get/imagick-3.1.2.tgz
tar -xvzf imagick-3.1.2.tgz
cd imagick-3.1.2
/usr/local/webserver/php-d/php-5.5.0/bin/phpize
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/
./configure --with-php-config=/usr/local/webserver/php-d/php-5.5.0/bin/php-config
make
make install
当然你也可以直接使用pecl安装扩展,更简单
/usr/local/webserver/php-d/php-5.5.0/bin/pecl uninstall imagick
/usr/local/webserver/php-d/php-5.5.0/bin/pecl install imagick
OK,到这里算完事了吗?没有哦,执行下PHP文件,还是会有上面内核不对的错误,这是为什么呢?而在网上搜了一大圈,大致就两种回答:
重新安装旧版本,使其对应内核
重新编译扩展
第一条我是肯定不会去做的,否则我升级的意义呢?重新编译扩展我是做了,难道有什么不对的吗?无意间,我想到这么一个问题。
我的PHP是正常升级了,扩展也更新了
那说明一切正常,但是执行PHP后,还是说我内核不对
说明php.ini可能配置不正常
打开php.ini,排查后,我发现是内核加载目录路径错了,需要重新修改为当前内核路径,如下:
# 修改扩展目录位置
extension_dir = "/usr/local/webserver/php-d/php-5.5.0/lib/php/extensions/no-debug-non-zts-20131226/"
# 修改opcache目录位置
zend_extension=/usr/local/webserver/php-d/php-5.5.0/lib/php/extensions/no-debug-non-zts-20131226/opcache.so
再执行下PHP试试,一切正常,重启PHP-FPM
service php -v
Zend OPcache requires Zend Engine API version 220121212.
The Zend Engine API version 220131226 which is installed, is newer.
Contact Zend Technologies at http://www.zend.com/ for a later version of Zend OPcache.
PHP 5.6.0 (cli) (built: Aug 30 2014 11:03:17)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
service php-fpm restart
[success]注意,直到这一步,我才重启PHP-FPM哦![/success]
关于如何配置opcache,以及配置php-fpm,请参考这篇文章,这里不再赘述
http://levi.yii.so/archives/2987
PHP 5.6.0 有哪些更新
在网上搜过,只言片语比较少,我这里结合PHP官网给出的实例,做个简单说明
常量标量表达式
const ONE = 1;
const TWO = ONE * 2;
class C {
const THREE = TWO + 1;
const ONE_THIRD = ONE / self::THREE;
const SENTENCE = 'The value of THREE is '.self::THREE;
public function f($a = ONE + self::THREE) {
return $a;
}
}
echo (new C)->f()."n";
echo C::SENTENCE;
?>
以上例程会输出:
4
The value of THREE is 3
操作符实现可变参数函数
function f($req, $opt = null, ...$params) {
// $params is an array containing the remaining arguments.
printf('$req: %d; $opt: %d; number of params: %d'."n",
$req, $opt, count($params));
}
f(1);
f(1, 2);
f(1, 2, 3);
f(1, 2, 3, 4);
f(1, 2, 3, 4, 5);
?>
以上例程会输出:
$req: 1; $opt: 0; number of params: 0
$req: 1; $opt: 2; number of params: 0
$req: 1; $opt: 2; number of params: 1
$req: 1; $opt: 2; number of params: 2
$req: 1; $opt: 2; number of params: 3
参数解包功能
function add($a, $b, $c) {
return $a + $b + $c;
}
$operators = [2, 3];
echo add(1, ...$operators);
?>
以上例程会输出:
6
使用**操作符计算乘方
printf("2 ** 3 == %dn", 2 ** 3);
printf("2 ** 3 ** 2 == %dn", 2 ** 3 ** 2);
$a = 2;
$a **= 3;
printf("a == %dn", $a);
?>
以上例程会输出:
2 ** 3 == 8
2 ** 3 ** 2 == 512
a == 8
使用use关键字导入函数和常量
namespace NameSpace {
const FOO = 42;
function f() { echo __FUNCTION__."n"; }
}
namespace {
use const NameSpaceFOO;
use function NameSpacef;
echo FOO."n";
f();
}
?>
以上例程会输出:
42
NameSpacef
交互式的PHP调试器phpdbg
这里不做详细说明,点击查看官方文档 >
默认字符编码
在 php.ini 中通过 default_charset 设置默认编码
GMP对象支持操作符重载
$a = gmp_init(42);
$b = gmp_init(17);
// Pre-5.6 code:
var_dump(gmp_add($a, $b));
var_dump(gmp_add($a, 17));
var_dump(gmp_add(42, $b));
// New code:
var_dump($a + $b);
var_dump($a + 17);
var_dump(42 + $b);
?>
字符串安全比较
$expected = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$correct = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$incorrect = crypt('1234', '$2a$07$usesomesillystringforsalt$');
var_dump(hash_equals($expected, $correct));
var_dump(hash_equals($expected, $incorrect));
?>
以上例程会输出:
bool(true)
bool(false)
新增魔术方法__debugInfo(),便于调试
class C {
private $prop;
public function __construct($val) {
$this->prop = $val;
}
public function __debugInfo() {
return [
'propSquared' => $this->prop ** 2,
];
}
}
var_dump(new C(42));
?>
以上例程会输出:
object(C)#1 (1) {
["propSquared"]=>
int(1764)
}