phpコアに深く入り込むphp in array
10262 ワード
まずphp in array関数の基本知識を紹介します.
定義と使用法
in_array()関数は、配列内で所定の値を検索します.
構文in_array(value,array,type)
パラメータ
説明
value
必要です.配列で検索する値を指定します.
array
必要です.検索する配列を指定します.
type
オプション.このパラメータをtrueに設定すると、検索したデータと配列の値のタイプが同じかどうかを確認します.
説明
与えられた値valueが配列arrayに存在する場合、trueが返されます.3番目のパラメータがtrueに設定されている場合、関数は要素が配列に存在し、データ型が所定の値と同じ場合にのみtrueを返します.
配列にパラメータが見つからない場合、関数はfalseを返します.
注記:valueパラメータが文字列でtypeパラメータがtrueに設定されている場合、検索は大文字と小文字を区別します.
何気なくコードを見た
テストしてみた
[root@dev tmp]# time php b.php real 0m9.517s user 0m4.486s sys 0m0.015s
なんと9 sが必要
in_arrayはこんな感じ
haystackでneedleを検索し、strictを設定していない場合は緩やかな比較を使用します.
needle
検索対象の値.needleが文字列の場合、比較は大文字と小文字を区別します.
haystack
この配列.
strict
3番目のパラメータstrictの値がTRUEの場合in_array()関数は、needleのタイプがhaystackと同じかどうかもチェックします.
ではソースコードを見てみましょう
最初のステップはext/standard/array.cファイル中
ついでにarrayが見えてきましたsearch,元とin_arrayの内部実装はほぼ一致する
関数のパラメータが./zend.h中
#define INTERNAL_FUNCTION_PARAM_PASSTHRU ht, return_value, return_value_ptr, this_ptr, return_value_used TSRMLS_CC
ステップ2 ext/standard/array.cファイルでphp_を表示するsearch_Arrayプロトタイプ
strictという値の違いには2つの比較方法があることを発見し,2つの関数の違いを見てみよう.
is_identical_functionチェックタイプが同じかどうか
is_equal_functionはタイプが同じかどうかをチェックしないので、暗黙的な変換が必要です
定義と使用法
in_array()関数は、配列内で所定の値を検索します.
構文in_array(value,array,type)
パラメータ
説明
value
必要です.配列で検索する値を指定します.
array
必要です.検索する配列を指定します.
type
オプション.このパラメータをtrueに設定すると、検索したデータと配列の値のタイプが同じかどうかを確認します.
説明
与えられた値valueが配列arrayに存在する場合、trueが返されます.3番目のパラメータがtrueに設定されている場合、関数は要素が配列に存在し、データ型が所定の値と同じ場合にのみtrueを返します.
配列にパラメータが見つからない場合、関数はfalseを返します.
注記:valueパラメータが文字列でtypeパラメータがtrueに設定されている場合、検索は大文字と小文字を区別します.
何気なくコードを見た
テストしてみた
[root@dev tmp]# time php b.php real 0m9.517s user 0m4.486s sys 0m0.015s
なんと9 sが必要
in_arrayはこんな感じ
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
haystackでneedleを検索し、strictを設定していない場合は緩やかな比較を使用します.
needle
検索対象の値.needleが文字列の場合、比較は大文字と小文字を区別します.
haystack
この配列.
strict
3番目のパラメータstrictの値がTRUEの場合in_array()関数は、needleのタイプがhaystackと同じかどうかもチェックします.
ではソースコードを見てみましょう
最初のステップはext/standard/array.cファイル中
/* }}} */
/* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
Checks if the given value exists in the array */
PHP_FUNCTION(in_array)
{
php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
Searches the array for a given value and returns the corresponding key if successful */
PHP_FUNCTION(array_search)
{
php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
ついでにarrayが見えてきましたsearch,元とin_arrayの内部実装はほぼ一致する
関数のパラメータが./zend.h中
#define INTERNAL_FUNCTION_PARAM_PASSTHRU ht, return_value, return_value_ptr, this_ptr, return_value_used TSRMLS_CC
ステップ2 ext/standard/array.cファイルでphp_を表示するsearch_Arrayプロトタイプ
/* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
* 0 = return boolean
* 1 = return key
*/
static void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
{
zval *value, /* value to check for */
*array, /* array to check in */
**entry, /* pointer to array entry */
res; /* comparison result */
HashPosition pos; /* hash iterator */
zend_bool strict = 0; /* strict comparison or not */
ulong num_key;
uint str_key_len;
char *string_key;
int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|b", &value, &array, &strict) == FAILURE) {
return;
}
if (strict) {
is_equal_func = is_identical_function;
}
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
is_equal_func(&res, value, *entry TSRMLS_CC);
if (Z_LVAL(res)) {
if (behavior == 0) {
RETURN_TRUE;
} else {
/* Return current key */
switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 0, &pos)) {
case HASH_KEY_IS_STRING:
RETURN_STRINGL(string_key, str_key_len - 1, 1);
break;
case HASH_KEY_IS_LONG:
RETURN_LONG(num_key);
break;
}
}
}
zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
Checks if the given value exists in the array */
strictという値の違いには2つの比較方法があることを発見し,2つの関数の違いを見てみよう.
is_identical_functionチェックタイプが同じかどうか
ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
Z_TYPE_P(result) = IS_BOOL;
if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
Z_LVAL_P(result) = 0;
return SUCCESS;
}
switch (Z_TYPE_P(op1)) {
case IS_NULL:
Z_LVAL_P(result) = 1;
break;
case IS_BOOL:
case IS_LONG:
case IS_RESOURCE:
Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
break;
case IS_DOUBLE:
Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
break;
case IS_STRING:
Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
&& (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
break;
case IS_ARRAY:
Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2)
zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
break;
case IS_OBJECT:
if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
} else {
Z_LVAL_P(result) = 0;
}
break;
default:
Z_LVAL_P(result) = 0;
return FAILURE;
}
return SUCCESS;
}
/* }}} */
is_equal_functionはタイプが同じかどうかをチェックしないので、暗黙的な変換が必要です
ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
return FAILURE;
}
ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
return SUCCESS;
}
/* }}} */
==》compare_function
ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
int ret;
int converted = 0;
zval op1_copy, op2_copy;
zval *op_free;
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG):
ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)compare_objects(op1, op2 TSRMLS_CC));
return SUCCESS;
}
/* break missing intentionally */
default:
if (Z_TYPE_P(op1) == IS_OBJECT) {
if (Z_OBJ_HT_P(op1)->get) {
op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
ret = compare_function(result, op_free, op2 TSRMLS_CC);
zend_free_obj_get_result(op_free TSRMLS_CC);
return ret;
} else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
ALLOC_INIT_ZVAL(op_free);
if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
ZVAL_LONG(result, 1);
zend_free_obj_get_result(op_free TSRMLS_CC);
return SUCCESS;
}
ret = compare_function(result, op_free, op2 TSRMLS_CC);
zend_free_obj_get_result(op_free TSRMLS_CC);
return ret;
}
}
if (Z_TYPE_P(op2) == IS_OBJECT) {
if (Z_OBJ_HT_P(op2)->get) {
op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
ret = compare_function(result, op1, op_free TSRMLS_CC);
zend_free_obj_get_result(op_free TSRMLS_CC);
return ret;
} else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
ALLOC_INIT_ZVAL(op_free);
if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
ZVAL_LONG(result, -1);
zend_free_obj_get_result(op_free TSRMLS_CC);
return SUCCESS;
}
ret = compare_function(result, op1, op_free TSRMLS_CC);
zend_free_obj_get_result(op_free TSRMLS_CC);
return ret;
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
ZVAL_LONG(result, 1);
return SUCCESS;
}
}
if (!converted) {
if (Z_TYPE_P(op1) == IS_NULL) {
zendi_convert_to_boolean(op2, op2_copy, result);
ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
return SUCCESS;
} else if (Z_TYPE_P(op2) == IS_NULL) {
zendi_convert_to_boolean(op1, op1_copy, result);
ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
return SUCCESS;
} else if (Z_TYPE_P(op1) == IS_BOOL) {
zendi_convert_to_boolean(op2, op2_copy, result);
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
return SUCCESS;
} else if (Z_TYPE_P(op2) == IS_BOOL) {
zendi_convert_to_boolean(op1, op1_copy, result);
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
return SUCCESS;
} else {
zendi_convert_scalar_to_number(op1, op1_copy, result);
zendi_convert_scalar_to_number(op2, op2_copy, result);
converted = 1;
}
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
ZVAL_LONG(result, 1);
return SUCCESS;
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
ZVAL_LONG(result, -1);
return SUCCESS;
} else if (Z_TYPE_P(op1)==IS_OBJECT) {
ZVAL_LONG(result, 1);
return SUCCESS;
} else if (Z_TYPE_P(op2)==IS_OBJECT) {
ZVAL_LONG(result, -1);
return SUCCESS;
} else {
ZVAL_LONG(result, 0);
return FAILURE;
}
}
}
}
/* }}} */