はじめに
今回は演算子に焦点をあて、
‘==’と‘===’
‘==’
まずはベンチマークを取ってみます。
<?php
$t = microtime(true);
$i = 0;
while($i < 1000) {
if ('a' == 'b') {}
++$i;
}
$tmp = microtime(true) - $t;
var_dump($tmp);
?>
<?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)
‘===’
それでは実装を見ていきましょう。まずは
‘==’
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_
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 }
文字列の場合、
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 }
数値の場合、
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に変換して比較が行われます。
一方、
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行目でまず型のチェックを行い、
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型についてのチェックが行われ、
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の比較をしていて、
ここまででis_
‘==’
is_nullと‘===’
is_
- is_
bool - booleanであるかを調べる
- is_
resource - リソースかどうかを調べる
- is_
long - 整数型かどうかを調べる
- is_
float - float型かどうかを調べる
- is_
string - 文字列かどうかを調べる
- is_
array - 配列かどうかを調べる
- is_
object - オブジェクトかどうかを調べる
- is_
numeric - 数字または数値形式の文字列かどうかを調べる
- is_
callable - 関数としてコール可能な構造であるかどうかを調べる
まずはベンチマークを取ってみます。
<?php
$t = microtime(true);
$i = 0;
$a = null;
while($i < 1000) {
if ($a === null) {}
++$i;
}
$tmp = microtime(true) - $t;
var_dump($tmp);
?>
<?php
$t = microtime(true);
$i = 0;
$a = null;
while($i < 1000) {
if (is_null($a)) {}
++$i;
}
$tmp = microtime(true) - $t;
var_dump($tmp);
?>
$ php benchmark_identical2.php float(0.000123023986816) $ php benchmark_is_null.php float(0.00032114982605)
‘===’
is_
240 PHP_FUNCTION(is_null)
241 {
242 php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_NULL);
243 }
203 static void php_is_type(INTERNAL_FUNCTION_PARAMETERS, int type)
204 {
205 zval **arg;
206
207 if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
208 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only one argument expected");
209 RETURN_FALSE;
210 }
211
212 if (Z_TYPE_PP(arg) == type) {
中略
231 RETURN_TRUE;
232 } else {
233 RETURN_FALSE;
234 }
235 }
php_
php_
is_