TL;DR
version_compare()
関数を使うときは、桁区切りのフォーマットは同一にしたほうが安心です。
もし、比較時に version_compare("2.0.0", "2.0", ">")
と2つのフォーマットが違うと、直感的には同じバージョンだったとしても、小数点で区切られた数が多い方が大きいと判定され、想定しない動きになる可能性があります。
前提条件
$ php -v
PHP 5.6.27 (cli) (built: Oct 15 2016 09:29:55)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
バージョン判定がうまくいかない?
比較する2つの値が同じフォーマットの時
version_compare()
を用い、比較する値がどちらも同じフォーマット(x.y.z
)となっている場合です。以下コードを書き、実行してみます。
<?php
print "2.0.0 > 2.0.0 = False? : " . (version_compare("2.0.0", "2.0.0", ">") ? "True" : "False") . "\n";
print "2.0.0 < 2.0.0 = False? : " . (version_compare("2.0.0", "2.0.0", "<") ? "True" : "False") . "\n";
print "2.0.0 >= 2.0.0 = True? : " . (version_compare("2.0.0", "2.0.0", ">=") ? "True" : "False") . "\n";
print "2.0.0 <= 2.0.0 = True? : " . (version_compare("2.0.0", "2.0.0", "<=") ? "True" : "False") . "\n";
print "2.0.0 == 2.0.0 = True? : " . (version_compare("2.0.0", "2.0.0", "==") ? "True" : "False") . "\n";
print "2.0.0 != 2.0.0 = False? : " . (version_compare("2.0.0", "2.0.0", "!=") ? "True" : "False") . "\n";
想定した動きになっています。
$ php version_compare_3_3.php
2.0.0 > 2.0.0 = False? : False
2.0.0 < 2.0.0 = False? : False
2.0.0 >= 2.0.0 = True? : True
2.0.0 <= 2.0.0 = True? : True
2.0.0 == 2.0.0 = True? : True
2.0.0 != 2.0.0 = False? : False
左辺の桁が1桁長いが右辺のほうが大きい値の時
左辺は2.0.0、右辺は2.1となったとき、どんな動きになるでしょうか。
<?php
print "2.0.0 > 2.1 = False? : " . (version_compare("2.0.0", "2.1", ">") ? "True" : "False") . "\n";
print "2.0.0 < 2.1 = True? : " . (version_compare("2.0.0", "2.1", "<") ? "True" : "False") . "\n";
print "2.0.0 >= 2.1 = False? : " . (version_compare("2.0.0", "2.1", ">=") ? "True" : "False") . "\n";
print "2.0.0 <= 2.1 = True? : " . (version_compare("2.0.0", "2.1", "<=") ? "True" : "False") . "\n";
print "2.0.0 == 2.1 = False? : " . (version_compare("2.0.0", "2.1", "==") ? "True" : "False") . "\n";
print "2.0.0 != 2.1 = True? : " . (version_compare("2.0.0", "2.1", "!=") ? "True" : "False") . "\n";
これは、おそらく多くの方が想定した動きになります。
$ php version_compare_3_2_1.php
2.0.0 > 2.1 = False? : False
2.0.0 < 2.1 = True? : True
2.0.0 >= 2.1 = False? : False
2.0.0 <= 2.1 = True? : True
2.0.0 == 2.1 = False? : False
2.0.0 != 2.1 = True? : True
左辺の桁が1桁長い時
では、左辺は2.0.0、右辺は2.0となったとき、どんな動きになるでしょうか。人が見たら、これはイコールと思えるかもしれませんが、実際は違います。
<?php
print "2.0.0 > 2.0 = False? : " . (version_compare("2.0.0", "2.0", ">") ? "True" : "False") . "\n";
print "2.0.0 < 2.0 = False? : " . (version_compare("2.0.0", "2.0", "<") ? "True" : "False") . "\n";
print "2.0.0 >= 2.0 = True? : " . (version_compare("2.0.0", "2.0", ">=") ? "True" : "False") . "\n";
print "2.0.0 <= 2.0 = True? : " . (version_compare("2.0.0", "2.0", "<=") ? "True" : "False") . "\n";
print "2.0.0 == 2.0 = True? : " . (version_compare("2.0.0", "2.0", "==") ? "True" : "False") . "\n";
print "2.0.0 != 2.0 = False? : " . (version_compare("2.0.0", "2.0 ", "!=") ? "True" : "False") . "\n";
桁が長い左辺が大きいと評価されます。
$ php version_compare_3_2.php
2.0.0 > 2.0 = False? : True
2.0.0 < 2.0 = False? : False
2.0.0 >= 2.0 = True? : True
2.0.0 <= 2.0 = True? : False
2.0.0 == 2.0 = True? : False
2.0.0 != 2.0 = False? : True
PHPの ext/standard/versioning.c
の php_version_compare()
をみてください。
メジャーバージョンの桁から順に評価されています。そのうえで、左辺か右辺、どちらかの評価が尽きると、桁が大きい方が小さいという処理に移っています。
2.1.0
と 2.01.0
はどうか
では、フォーマットがにているようで、minorバージョンが1桁の場合と2桁の場合ではどうでしょうか。これも変わった動きをします。
<?php
print "2.1.0 > 2.01.0 = False? : " . (version_compare("2.0.0", "2.01.0", ">") ? "True" : "False") . "\n";
print "2.1.0 < 2.01.0 = False? : " . (version_compare("2.0.0", "2.01.0", "<") ? "True" : "False") . "\n";
print "2.1.0 >= 2.01.0 = True? : " . (version_compare("2.0.0", "2.01.0", ">=") ? "True" : "False") . "\n";
print "2.1.0 <= 2.01.0 = True? : " . (version_compare("2.0.0", "2.01.0", "<=") ? "True" : "False") . "\n";
print "2.1.0 == 2.01.0 = True? : " . (version_compare("2.0.0", "2.01.0", "==") ? "True" : "False") . "\n";
print "2.1.0 != 2.01.0 = False? : " . (version_compare("2.0.0", "2.01.0", "!=") ? "True" : "False") . "\n";
桁が長いほうが、大きいと評価されました。
$ php php:version_compare_3_a.php
2.1.0 > 2.01.0 = False? : False
2.1.0 < 2.01.0 = False? : True
2.1.0 >= 2.01.0 = True? : False
2.1.0 <= 2.01.0 = True? : True
2.1.0 == 2.01.0 = True? : False
2.1.0 != 2.01.0 = False? : True
PHPの ext/standard/versioning.c
の php_version_compare()
をみてください。
…と思ったのですが、あれ、なんでこうなるんだろう。調査中です。
参考資料
- PHP.net - version_compare
- https://github.com/php/php-src/ (ext/standard/versioning.c)