in_array() php内置函数的源码解读
PHP_FUNCTION ( array_search)
{
php_search_array ( INTERNAL_FUNCTION_PARAM_PASSTHRU, 1 ) ;
}
PHP_FUNCTION ( in_array)
{
php_search_array ( INTERNAL_FUNCTION_PARAM_PASSTHRU, 0 ) ;
}
static inline void php_search_array ( INTERNAL_FUNCTION_PARAMETERS, int behavior)
{
zval * value,
* array,
* entry;
zend_ulong num_idx;
zend_string * str_idx;
zend_bool strict = 0 ;
ZEND_PARSE_PARAMETERS_START ( 2 , 3 )
Z_PARAM_ZVAL ( value)
Z_PARAM_ARRAY ( array)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL ( strict)
ZEND_PARSE_PARAMETERS_END ( ) ;
if ( strict) {
ZEND_HASH_FOREACH_KEY_VAL_IND ( Z_ARRVAL_P ( array) , num_idx, str_idx, entry) {
ZVAL_DEREF ( entry) ;
if ( fast_is_identical_function ( value, entry) ) {
if ( behavior == 0 ) {
RETURN_TRUE;
} else {
if ( str_idx) {
RETVAL_STR_COPY ( str_idx) ;
} else {
RETVAL_LONG ( num_idx) ;
}
return ;
}
}
} ZEND_HASH_FOREACH_END ( ) ;
} else {
if ( Z_TYPE_P ( value) == IS_LONG) {
ZEND_HASH_FOREACH_KEY_VAL_IND ( Z_ARRVAL_P ( array) , num_idx, str_idx, entry) {
if ( fast_equal_check_long ( value, entry) ) {
if ( behavior == 0 ) {
RETURN_TRUE;
} else {
if ( str_idx) {
RETVAL_STR_COPY ( str_idx) ;
} else {
RETVAL_LONG ( num_idx) ;
}
return ;
}
}
} ZEND_HASH_FOREACH_END ( ) ;
} else if ( Z_TYPE_P ( value) == IS_STRING) {
ZEND_HASH_FOREACH_KEY_VAL_IND ( Z_ARRVAL_P ( array) , num_idx, str_idx, entry) {
if ( fast_equal_check_string ( value, entry) ) {
if ( behavior == 0 ) {
RETURN_TRUE;
} else {
if ( str_idx) {
RETVAL_STR_COPY ( str_idx) ;
} else {
RETVAL_LONG ( num_idx) ;
}
return ;
}
}
} ZEND_HASH_FOREACH_END ( ) ;
} else {
ZEND_HASH_FOREACH_KEY_VAL_IND ( Z_ARRVAL_P ( array) , num_idx, str_idx, entry) {
if ( fast_equal_check_function ( value, entry) ) {
if ( behavior == 0 ) {
RETURN_TRUE;
} else {
if ( str_idx) {
RETVAL_STR_COPY ( str_idx) ;
} else {
RETVAL_LONG ( num_idx) ;
}
return ;
}
}
} ZEND_HASH_FOREACH_END ( ) ;
}
}
RETURN_FALSE;
}
static zend_always_inline int fast_equal_check_long ( zval * op1, zval * op2)
{
zval result;
if ( EXPECTED ( Z_TYPE_P ( op2) == IS_LONG) ) {
return Z_LVAL_P ( op1) == Z_LVAL_P ( op2) ;
}
compare_function ( & result, op1, op2) ;
return Z_LVAL ( result) == 0 ;
}
ZEND_API int ZEND_FASTCALL compare_function ( zval * result, zval * op1, zval * op2)
{
int ret;
int converted = 0 ;
zval op1_copy, op2_copy;
zval * op_free, tmp_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) < Z_LVAL_P ( op2) ? - 1 : 0 ) ) ;
return SUCCESS;
case TYPE_PAIR ( IS_DOUBLE, IS_LONG) :
Z_DVAL_P ( result) = Z_DVAL_P ( op1) - ( double ) Z_LVAL_P ( op2) ;
ZVAL_LONG ( result, ZEND_NORMALIZE_BOOL ( Z_DVAL_P ( result) ) ) ;
return SUCCESS;
case TYPE_PAIR ( IS_LONG, IS_DOUBLE) :
Z_DVAL_P ( result) = ( double ) Z_LVAL_P ( op1) - Z_DVAL_P ( op2) ;
ZVAL_LONG ( result, ZEND_NORMALIZE_BOOL ( Z_DVAL_P ( result) ) ) ;
return SUCCESS;
case TYPE_PAIR ( IS_DOUBLE, IS_DOUBLE) :
if ( Z_DVAL_P ( op1) == Z_DVAL_P ( op2) ) {
ZVAL_LONG ( result, 0 ) ;
} else {
Z_DVAL_P ( result) = Z_DVAL_P ( op1) - Z_DVAL_P ( op2) ;
ZVAL_LONG ( result, ZEND_NORMALIZE_BOOL ( Z_DVAL_P ( result) ) ) ;
}
return SUCCESS;
case TYPE_PAIR ( IS_ARRAY, IS_ARRAY) :
ZVAL_LONG ( result, zend_compare_arrays ( op1, op2) ) ;
return SUCCESS;
case TYPE_PAIR ( IS_NULL, IS_NULL) :
case TYPE_PAIR ( IS_NULL, IS_FALSE) :
case TYPE_PAIR ( IS_FALSE, IS_NULL) :
case TYPE_PAIR ( IS_FALSE, IS_FALSE) :
case TYPE_PAIR ( IS_TRUE, IS_TRUE) :
ZVAL_LONG ( result, 0 ) ;
return SUCCESS;
case TYPE_PAIR ( IS_NULL, IS_TRUE) :
ZVAL_LONG ( result, - 1 ) ;
return SUCCESS;
case TYPE_PAIR ( IS_TRUE, IS_NULL) :
ZVAL_LONG ( result, 1 ) ;
return SUCCESS;
case TYPE_PAIR ( IS_STRING, IS_STRING) :
if ( Z_STR_P ( op1) == Z_STR_P ( op2) ) {
ZVAL_LONG ( result, 0 ) ;
return SUCCESS;
}
ZVAL_LONG ( result, zendi_smart_strcmp ( Z_STR_P ( op1) , Z_STR_P ( op2) ) ) ;
return SUCCESS;
case TYPE_PAIR ( IS_NULL, IS_STRING) :
ZVAL_LONG ( result, Z_STRLEN_P ( op2) == 0 ? 0 : - 1 ) ;
return SUCCESS;
case TYPE_PAIR ( IS_STRING, IS_NULL) :
ZVAL_LONG ( result, Z_STRLEN_P ( op1) == 0 ? 0 : 1 ) ;
return SUCCESS;
case TYPE_PAIR ( IS_OBJECT, IS_NULL) :
ZVAL_LONG ( result, 1 ) ;
return SUCCESS;
case TYPE_PAIR ( IS_NULL, IS_OBJECT) :
ZVAL_LONG ( result, - 1 ) ;
return SUCCESS;
default :
if ( Z_ISREF_P ( op1) ) {
op1 = Z_REFVAL_P ( op1) ;
continue ;
} else if ( Z_ISREF_P ( op2) ) {
op2 = Z_REFVAL_P ( op2) ;
continue ;
}
if ( Z_TYPE_P ( op1) == IS_OBJECT && Z_OBJ_HANDLER_P ( op1, compare) ) {
ret = Z_OBJ_HANDLER_P ( op1, compare) ( result, op1, op2) ;
if ( UNEXPECTED ( Z_TYPE_P ( result) != IS_LONG) ) {
convert_compare_result_to_long ( result) ;
}
return ret;
} else if ( Z_TYPE_P ( op2) == IS_OBJECT && Z_OBJ_HANDLER_P ( op2, compare) ) {
ret = Z_OBJ_HANDLER_P ( op2, compare) ( result, op1, op2) ;
if ( UNEXPECTED ( Z_TYPE_P ( result) != IS_LONG) ) {
convert_compare_result_to_long ( result) ;
}
return ret;
}
if ( Z_TYPE_P ( op1) == IS_OBJECT && Z_TYPE_P ( op2) == IS_OBJECT) {
if ( Z_OBJ_P ( op1) == Z_OBJ_P ( op2) ) {
ZVAL_LONG ( result, 0 ) ;
return SUCCESS;
}
if ( Z_OBJ_HANDLER_P ( op1, compare_objects) == Z_OBJ_HANDLER_P ( op2, compare_objects) ) {
ZVAL_LONG ( result, Z_OBJ_HANDLER_P ( op1, compare_objects) ( op1, op2) ) ;
return SUCCESS;
}
}
if ( Z_TYPE_P ( op1) == IS_OBJECT) {
if ( Z_OBJ_HT_P ( op1) -> get) {
zval rv;
op_free = Z_OBJ_HT_P ( op1) -> get ( op1, & rv) ;
ret = compare_function ( result, op_free, op2) ;
zend_free_obj_get_result ( op_free) ;
return ret;
} else if ( Z_TYPE_P ( op2) != IS_OBJECT && Z_OBJ_HT_P ( op1) -> cast_object) {
ZVAL_UNDEF ( & tmp_free) ;
if ( Z_OBJ_HT_P ( op1) -> cast_object ( op1, & tmp_free, ( ( Z_TYPE_P ( op2) == IS_FALSE || Z_TYPE_P ( op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P ( op2) ) ) == FAILURE) {
ZVAL_LONG ( result, 1 ) ;
zend_free_obj_get_result ( & tmp_free) ;
return SUCCESS;
}
ret = compare_function ( result, & tmp_free, op2) ;
zend_free_obj_get_result ( & tmp_free) ;
return ret;
}
}
if ( Z_TYPE_P ( op2) == IS_OBJECT) {
if ( Z_OBJ_HT_P ( op2) -> get) {
zval rv;
op_free = Z_OBJ_HT_P ( op2) -> get ( op2, & rv) ;
ret = compare_function ( result, op1, op_free) ;
zend_free_obj_get_result ( op_free) ;
return ret;
} else if ( Z_TYPE_P ( op1) != IS_OBJECT && Z_OBJ_HT_P ( op2) -> cast_object) {
ZVAL_UNDEF ( & tmp_free) ;
if ( Z_OBJ_HT_P ( op2) -> cast_object ( op2, & tmp_free, ( ( Z_TYPE_P ( op1) == IS_FALSE || Z_TYPE_P ( op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P ( op1) ) ) == FAILURE) {
ZVAL_LONG ( result, - 1 ) ;
zend_free_obj_get_result ( & tmp_free) ;
return SUCCESS;
}
ret = compare_function ( result, op1, & tmp_free) ;
zend_free_obj_get_result ( & tmp_free) ;
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 || Z_TYPE_P ( op1) == IS_FALSE) {
ZVAL_LONG ( result, zval_is_true ( op2) ? - 1 : 0 ) ;
return SUCCESS;
} else if ( Z_TYPE_P ( op2) == IS_NULL || Z_TYPE_P ( op2) == IS_FALSE) {
ZVAL_LONG ( result, zval_is_true ( op1) ? 1 : 0 ) ;
return SUCCESS;
} else if ( Z_TYPE_P ( op1) == IS_TRUE) {
ZVAL_LONG ( result, zval_is_true ( op2) ? 0 : 1 ) ;
return SUCCESS;
} else if ( Z_TYPE_P ( op2) == IS_TRUE) {
ZVAL_LONG ( result, zval_is_true ( op1) ? 0 : - 1 ) ;
return SUCCESS;
} else {
op1 = zendi_convert_scalar_to_number ( op1, & op1_copy, result, 1 ) ;
op2 = zendi_convert_scalar_to_number ( op2, & op2_copy, result, 1 ) ;
if ( EG ( exception) ) {
if ( result != op1) {
ZVAL_UNDEF ( result) ;
}
return FAILURE;
}
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;
}
}
}
}