徹底検証!PHP最適化Tips

第3回 演算子と関数の噂を検証

この記事を読むのに必要な時間:およそ 3.5 分

はじめに

今回は演算子に焦点をあて,同様の動きをする演算子や関数と比較検証を行います。

‘==’‘===’

‘=====とを比較します。===は値だけではなく型も含めて比較を行う演算子です。

まずはベンチマークを取ってみます。

benchmark_equal.php

<?php
$t = microtime(true);
$i = 0;
while($i < 1000) {
   if ('a' == 'b') {}
   ++$i;        
}
$tmp = microtime(true) - $t;
var_dump($tmp);
?>

benchmark_identical.php

<?php
$t = microtime(true);
$i = 0;
while($i < 1000) {
   if ('a' === 'b') {}
   ++$i;        
}
$tmp = microtime(true) - $t;
var_dump($tmp);
?>

実行結果

$ php benchmark_equal.php
float(0.00020694732666)
$ php benchmark_identical.php
float(0.000159978866577)

‘===のほうが==よりも僅かに速い結果となりました。

それでは実装を見ていきましょう。まずは==です。

‘==の実体はZend/zend_operators.c内のis_equal_function()にあります。is_equal_function()の中をみると,compare_functionで左辺と右辺の比較を行っていることが分かります。

1539 ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
1540 {
1541     if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1542         return FAILURE;
1543     }
1544     convert_to_boolean(result);
1545     if (result->value.lval == 0) {
1546         result->value.lval = 1;
1547     } else {
1548         result->value.lval = 0;
1549     }
1550     return SUCCESS;
1551 }

次にcompare_function()を見ていきます。同じくzend_operators.cに書かれてます。

1323 ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)

文字列と数値との比較について見ていきます。

1390     if (op1->type == IS_STRING && op2->type == IS_STRING) {
1391         zendi_smart_strcmp(result, op1, op2);
1392         COMPARE_RETURN_AND_FREE(SUCCESS);
1393     }

文字列の場合,zendi_smart_strcmp()で文字列比較が行われます。この関数では文字列が数字のみでできた文字列かを変換しチェックを行い,その結果によって比較処理が異なります。

1417     if (Z_TYPE_P(op1) == IS_LONG && Z_TYPE_P(op2) == IS_LONG) {
1418         ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1419         COMPARE_RETURN_AND_FREE(SUCCESS);
1420     }

数値の場合,型がlong同士であればそのまま比較します。

1421     if ((Z_TYPE_P(op1) == IS_DOUBLE || Z_TYPE_P(op1) == IS_LONG)
1422         && (Z_TYPE_P(op2) == IS_DOUBLE || Z_TYPE_P(op2) == IS_LONG)) {
1423         Z_DVAL_P(result) = (Z_TYPE_P(op1) == IS_LONG ? (double) Z_LVAL_P(op1) : Z_DVAL_P(op1)) - (Z_TYPE_P(op2) == IS_LONG ? (double) Z_LVAL_P(op2) : Z_DVAL_P(op2));
1424         ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1425         COMPARE_RETURN_AND_FREE(SUCCESS);
1426     }

数値の型が違うときはlongなほうの値をdoubleに変換して比較が行われます。

一方,===の実体はZend/zend_operators.c内のis_identical_function()にあります。文字列と数値の場合についての関数の動きを見ていきます。

1471 ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
1472 {
1473     result->type = IS_BOOL;
1474     if (op1->type != op2->type) {
1475         result->value.lval = 0;
1476         return SUCCESS;
1477     }

1474から1477行目でまず型のチェックを行い,型が違えばfalseを返して終了,同じなら値のチェックに入ります。

1478行目から型によってそれぞれの値のチェックが行われます。

1478     switch (op1->type) {
1479         case IS_NULL:
1480             result->value.lval = (op2->type==IS_NULL);
1481             break;

型がnullの場合はもう片方の値の型もnullかどうか比較します。

1482         case IS_BOOL:
1483         case IS_LONG:
1484         case IS_RESOURCE:
1485             result->value.lval = (op1->value.lval == op2->value.lval);
1486             break;
1487         case IS_DOUBLE:
1488             result->value.lval = (op1->value.dval == op2->value.dval);
1489             break;

1482から1489行目ではbool, long, resource, double型についてのチェックが行われ,値はC言語の==演算子で比較が行われます。

1490         case IS_STRING:
1491             if ((op1->value.str.len == op2->value.str.len)
1492                 && (!memcmp(op1->value.str.val, op2->value.str.val,  op1->value.str.len))) {
1493                 result->value.lval = 1;
1494             } else {
1495                 result->value.lval = 0;
1496             }
1497             break;

1490行目からはstringの比較をしていて,文字列長の比較とmemcmpによる文字列の比較が行われます。

ここまででis_identical_function()の解説は終わりです。

‘==では型を考慮しないので,違う型での比較をすることも考えた凝った構造に対して,===では同じ型かを最初にチェックして同じ型の値同士で比較を行うため,シンプルな構造で余計な型の変換もありません。そのため,===のほうが速い結果になったと考えられます。

著者プロフィール

梶原大輔(かじわらだいすけ)

大学卒業後,ヤフー株式会社に入社し,Yahoo!ビデオキャストなどのサービス開発に従事。

現在はグリー株式会社でバックエンドシステムの開発を担当。

URLhttp://d.hatena.ne.jp/kajidai/

コメント

コメントの記入