Deep into PHP kernel in_array, php kernel in_array
I accidentally saw a piece of code
1. a.php
<?php $y="12"; $x = array(); for($j=0;$j<50000;$j++){ $x[]= "{$j}"; } for($i=0;$i<30000;$i++){ if(in_array($y,$x,true)){ continue; } } ?>
Test
[root@dev tmp]# time php a.php real 0m0.101s user 0m0.080s sys 0m0.013s
2.b.php
<?php $y="1800"; $x = array(); for($j=0;$j<50000;$j++){ $x[]= "{$j}"; } for($i=0;$i<30000;$i++){ if(in_array($y,$x)){ continue; } }
Test
[root@dev tmp]# time php b.php real 0m9.517s user 0m4.486s sys 0m0.015s
Requires 9s
There are serious efficiency issues with b.php, please follow up and test it
[root@dev tmp]# ltrace -c php b.php % time seconds usecs/call calls function ------ ----------- ----------- --------- -------------------- 52.92 175.486683 224 780155 strtol 33.34 110.550182 55275091 2 __libc_start_main 6.33 20.999979 177 118479 memcpy 3.56 11.819558 234 50394 __ctype_b_loc 1.66 5.510564 285 19294 free 1.42 4.704605 156820 30 dlopen 0.43 1.416750 76 18430 malloc 0.13 0.422050 76 5510 strlen 0.08 0.258620 76 3375 __ctype_tolower_loc 0.04 0.137245 77 1770 strrchr 0.02 0.067158 76 880 strcasecmp 0.02 0.059222 76 776 calloc 0.01 0.034591 17295 2 getprotobyname 0.01 0.031099 76 407 realloc 0.01 0.021277 77 276 memset 0.00 0.011502 383 30 dlclose 0.00 0.010671 85 125 0.00 0.006806 73 93 fileno 0.00 0.006095 76 80 strncasecmp 0.00 0.005397 77 70 strchr 0.00 0.005139 160 32 ftell 0.00 0.004405 137 32 fclose 0.00 0.003644 104 35 __fxstat 0.00 0.003432 107 32 fopen 0.00 0.003103 107 29 munmap 0.00 0.003062 78 39 getenv 0.00 0.003031 104 29 mmap 0.00 0.003027 104 29 isatty 0.00 0.002825 104 27 __xstat 0.00 0.002468 82 30 dlsym 0.00 0.002167 74 29 sysconf 0.00 0.001956 75 26 _setjmp 0.00 0.001419 109 13 __lxstat 0.00 0.001294 76 17 memchr 0.00 0.001125 1125 1 SYS_clone 0.00 0.001099 1099 1 tzset 0.00 0.001098 1098 1 exit 0.00 0.001075 1075 1 ERR_load_crypto_strings 0.00 0.000986 986 1 using_history 0.00 0.000837 837 1 SYS_exit_group 0.00 0.000606 75 8 __strdup 0.00 0.000596 74 8 strcmp 0.00 0.000591 73 8 __memcpy_chk 0.00 0.000457 76 6 fflush 0.00 0.000326 108 3 getcwd 0.00 0.000309 77 4 __errno_location 0.00 0.000271 271 1 setlocale 0.00 0.000271 271 1 scandir 0.00 0.000238 79 3 __sprintf_chk 0.00 0.000222 111 2 signal 0.00 0.000206 206 1 SSL_library_init 0.00 0.000186 186 1 fgetc 0.00 0.000155 155 1 ERR_load_ERR_strings 0.00 0.000154 77 2 xmlSetGenericErrorFunc 0.00 0.000151 75 2 __strtok_r 0.00 0.000151 75 2 xmlParserInputBufferCreateFilenameDefault 0.00 0.000148 148 1 xmlInitParser 0.00 0.000147 73 2 xmlOutputBufferCreateFilenameDefault 0.00 0.000130 130 1 OpenSSL_add_all_ciphers 0.00 0.000122 122 1 EVP_cleanup 0.00 0.000112 112 1 access 0.00 0.000109 109 1 rewind 0.00 0.000106 106 1 OPENSSL_add_all_algorithms_noconf 0.00 0.000105 105 1 sigprocmask 0.00 0.000093 93 1 gnu_get_libc_version 0.00 0.000090 90 1 OpenSSL_add_all_digests 0.00 0.000084 84 1 xmlCleanupParser 0.00 0.000081 81 1 xmlRelaxNGCleanupTypes 0.00 0.000079 79 1 xmlSetStructuredErrorFunc 0.00 0.000078 78 1 SSL_get_ex_new_index 0.00 0.000077 77 1 __gmp_set_memory_functions 0.00 0.000076 76 1 ERR_load_EVP_strings 0.00 0.000076 76 1 pcre_version 0.00 0.000075 75 1 X509_get_default_cert_area 0.00 0.000075 75 1 strstr 0.00 0.000074 74 1 sigemptyset 0.00 0.000074 74 1 __xmlParserVersion 0.00 0.000074 74 1 time 0.00 0.000074 74 1 xmlResetLastError 0.00 0.000074 74 1 strncmp 0.00 0.000073 73 1 sigaddset ------ ----------- ----------- --------- -------------------- 100.00 331.614442 1000662 total
We found that strtol takes up a lot of time
Check the library functions
/* 函数名: strtol 功 能: 将串转换为长整数 用 法: long strtol(char *str, char **endptr, int base); 程序例: */ #include <stdlib.h> #include <stdio.h> int main(void) { char *string = "87654321", *endptr; long lnumber; /* strtol converts string to long integer */ lnumber = strtol(string, &endptr, 10); printf("string = %s long = %ld\n", string, lnumber); return 0; }
So there should be a lot of type conversions in the source code
About in_array
in_array looks like this
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
Searches for haystack
within needle
, using a relaxed comparison if strict
is not set.
needle
The value to search for. If needle
is a string, the comparison is case-sensitive.
haystack
This array.
strict
If the value of the third parameter strict
is TRUE
, then the in_array() function will also check whether the type of needle
is the same as the one in haystack
.
Then let me take a look at the source code
The first step is in the ext/standard/array.c file
/* }}} */ /* {{{ 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); } /* }}} */
By the way, I saw array_search, which turns out to be basically the same as the internal implementation of in_array
The parameters of the function are in ./zend.h
#define INTERNAL_FUNCTION_PARAM_PASSTHRU ht, return_value, return_value_ptr, this_ptr, return_value_used TSRMLS_CC
The second step is to view the php_search_array prototype in the ext/standard/array.c file
/* 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 */
We found that there are two comparison methods for the difference in the value of strict. Let’s take a look at the difference between the two functions
is_identical_function Check if the types are the same
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 does not check whether the types are the same, so implicit conversion is required
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)<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): zend_compare_arrays(result, op1, op2 TSRMLS_CC); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_NULL): ZVAL_LONG(result, 0); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_BOOL): ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0); return SUCCESS; case TYPE_PAIR(IS_BOOL, IS_NULL): ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0); return SUCCESS; case TYPE_PAIR(IS_BOOL, IS_BOOL): ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2))); return SUCCESS; case TYPE_PAIR(IS_STRING, IS_STRING): zendi_smart_strcmp(result, op1, op2); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_STRING): ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2))); return SUCCESS; case TYPE_PAIR(IS_STRING, IS_NULL): ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0)); 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; case TYPE_PAIR(IS_OBJECT, IS_OBJECT): /* If both are objects sharing the same comparision handler then use is */ if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) { if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) { /* object handles are identical, apparently this is the same object */ ZVAL_LONG(result, 0); return SUCCESS; } ZVAL_LONG(result, Z_OBJ_HT_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; } } } } /* }}} */
Let’s take a look at how array and string compare
==》zend_hash_compare in Zend/zend_hash.c
ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC) { Bucket *p1, *p2 = NULL; int result; void *pData2; IS_CONSISTENT(ht1); IS_CONSISTENT(ht2); HASH_PROTECT_RECURSION(ht1);. HASH_PROTECT_RECURSION(ht2);. result = ht1->nNumOfElements - ht2->nNumOfElements; if (result!=0) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return result; } p1 = ht1->pListHead; if (ordered) { p2 = ht2->pListHead; } while (p1) { if (ordered && !p2) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return 1; /* That's not supposed to happen */ } if (ordered) { if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */ result = p1->h - p2->h; if (result!=0) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return result; } } else { /* string indices */ result = p1->nKeyLength - p2->nKeyLength; if (result!=0) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return result; } result = memcmp(p1->arKey, p2->arKey, p1->nKeyLength); if (result!=0) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return result; } } pData2 = p2->pData; } else { if (p1->nKeyLength==0) { /* numeric index */ if (zend_hash_index_find(ht2, p1->h, &pData2)==FAILURE) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return 1; } } else { /* string index */ if (zend_hash_quick_find(ht2, p1->arKey, p1->nKeyLength, p1->h, &pData2)==FAILURE) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return 1; } } } result = compar(p1->pData, pData2 TSRMLS_CC); if (result!=0) { HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return result; } p1 = p1->pListNext; if (ordered) { p2 = p2->pListNext; } } HASH_UNPROTECT_RECURSION(ht1);. HASH_UNPROTECT_RECURSION(ht2);. return 0; }
==》There is also a zendi_smart_strcmp in Zend/zend_operators.c
ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */ { int ret1, ret2; int oflow1, oflow2; long lval1, lval2; double dval1, dval2; if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) && (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) { #if ULONG_MAX == 0xFFFFFFFF if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. && ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/) (oflow1 == -1 && dval1 < -9007199254740991.))) { #else if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) { #endif /* both values are integers overflown to the same side, and the * double comparison may have resulted in crucial accuracy lost */ goto string_cmp; } if ((ret1==IS_DOUBLE) (ret2==IS_DOUBLE)) { if (ret1!=IS_DOUBLE) { if (oflow2) { /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */ ZVAL_LONG(result, -1 * oflow2); return; } dval1 = (double) lval1; } else if (ret2!=IS_DOUBLE) { if (oflow1) { ZVAL_LONG(result, oflow1); return; } dval2 = (double) lval2; } else if (dval1 == dval2 && !zend_finite(dval1)) { /* Both values overflowed and have the same sign, * so a numeric comparison would be inaccurate */ goto string_cmp; } Z_DVAL_P(result) = dval1 - dval2; ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result))); } else { /* they both have to be long's */ ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0)); } } else { string_cmp: Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2); ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result))); } } /* }}} *
Our type conversion function is_numeric_string_ex is in Zend/zend_operators.h
Continue to follow
==》is_numeric_string_ex
static inline zend_uchar is_numeric_string_ex(const char *str, int length, long *lval, double *dval, int allow_errors, int *oflow_info) { const char *ptr; int base = 10, digits = 0, dp_or_e = 0; double local_dval; zend_uchar type; if (!length) { return 0; } if (oflow_info != NULL) { *oflow_info = 0; } /* Skip any whitespace * This is much faster than the isspace() function */ while (*str == ' ' *str == '\t' *str == '\n' *str == '\r' *str == '\v' *str == '\f') { str++; length--; } ptr = str; if (*ptr == '-' *ptr == '+') { ptr++; } if (ZEND_IS_DIGIT(*ptr)) { /* Handle hex numbers * str is used instead of ptr to disallow signs and keep old behavior */ if (length > 2 && *str == '0' && (str[1] == 'x' str[1] == 'X')) { base = 16; ptr += 2; } /* Skip any leading 0s */ while (*ptr == '0') { ptr++; } /* Count the number of digits. If a decimal point/exponent is found, * it's a double. Otherwise, if there's a dval or no need to check for * a full match, stop when there are too many digits for a long */ for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval allow_errors == 1)); digits++, ptr++) { check_digits: if (ZEND_IS_DIGIT(*ptr) (base == 16 && ZEND_IS_XDIGIT(*ptr))) { continue; } else if (base == 10) { if (*ptr == '.' && dp_or_e < 1) { goto process_double; } else if ((*ptr == 'e' *ptr == 'E') && dp_or_e < 2) { const char *e = ptr + 1; if (*e == '-' *e == '+') { ptr = e++; } if (ZEND_IS_DIGIT(*e)) { goto process_double; } } } break; } if (base == 10) { if (digits >= MAX_LENGTH_OF_LONG) { if (oflow_info != NULL) { *oflow_info = *str == '-' ? -1 : 1; } dp_or_e = -1; goto process_double; } } else if (!(digits < SIZEOF_LONG * 2 (digits == SIZEOF_LONG * 2 && ptr[-digits] <= '7'))) { if (dval) { local_dval = zend_hex_strtod(str, &ptr); } if (oflow_info != NULL) { *oflow_info = 1; } type = IS_DOUBLE; } } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { process_double: type = IS_DOUBLE; /* If there's a dval, do the conversion; else continue checking * the digits if we need to check for a full match */ if (dval) { local_dval = zend_strtod(str, &ptr); } else if (allow_errors != 1 && dp_or_e != -1) { dp_or_e = (*ptr++ == '.') ? 1 : 2; goto check_digits; } } else { return 0; } if (ptr != str + length) { if (!allow_errors) { return 0; } if (allow_errors == -1) { zend_error(E_NOTICE, "A non well formed numeric value encountered"); } } if (type == IS_LONG) { if (digits == MAX_LENGTH_OF_LONG - 1) { int cmp = strcmp(&ptr[-digits], long_min_digits); if (!(cmp < 0 (cmp == 0 && *str == '-'))) { if (dval) { *dval = zend_strtod(str, NULL); } if (oflow_info != NULL) { *oflow_info = *str == '-' ? -1 : 1; } return IS_DOUBLE; } } if (lval) { *lval = strtol(str, NULL, base); } return IS_LONG; } else { if (dval) { *dval = local_dval; } return IS_DOUBLE; } }
There is indeed this code when type == IS_LONG
Intercept this piece of code
…… if (type == IS_LONG) { if (digits == MAX_LENGTH_OF_LONG - 1) { int cmp = strcmp(&ptr[-digits], long_min_digits); if (!(cmp < 0 (cmp == 0 && *str == '-'))) { if (dval) { *dval = zend_strtod(str, NULL); } if (oflow_info != NULL) { *oflow_info = *str == '-' ? -1 : 1; } return IS_DOUBLE; } } if (lval) { *lval = strtol(str, NULL, base); } return IS_LONG; } ……
That’s it strtol here

What’s still popular is the ease of use, flexibility and a strong ecosystem. 1) Ease of use and simple syntax make it the first choice for beginners. 2) Closely integrated with web development, excellent interaction with HTTP requests and database. 3) The huge ecosystem provides a wealth of tools and libraries. 4) Active community and open source nature adapts them to new needs and technology trends.

PHP and Python are both high-level programming languages that are widely used in web development, data processing and automation tasks. 1.PHP is often used to build dynamic websites and content management systems, while Python is often used to build web frameworks and data science. 2.PHP uses echo to output content, Python uses print. 3. Both support object-oriented programming, but the syntax and keywords are different. 4. PHP supports weak type conversion, while Python is more stringent. 5. PHP performance optimization includes using OPcache and asynchronous programming, while Python uses cProfile and asynchronous programming.

PHP is mainly procedural programming, but also supports object-oriented programming (OOP); Python supports a variety of paradigms, including OOP, functional and procedural programming. PHP is suitable for web development, and Python is suitable for a variety of applications such as data analysis and machine learning.

PHP originated in 1994 and was developed by RasmusLerdorf. It was originally used to track website visitors and gradually evolved into a server-side scripting language and was widely used in web development. Python was developed by Guidovan Rossum in the late 1980s and was first released in 1991. It emphasizes code readability and simplicity, and is suitable for scientific computing, data analysis and other fields.

PHP is suitable for web development and rapid prototyping, and Python is suitable for data science and machine learning. 1.PHP is used for dynamic web development, with simple syntax and suitable for rapid development. 2. Python has concise syntax, is suitable for multiple fields, and has a strong library ecosystem.

PHP remains important in the modernization process because it supports a large number of websites and applications and adapts to development needs through frameworks. 1.PHP7 improves performance and introduces new features. 2. Modern frameworks such as Laravel, Symfony and CodeIgniter simplify development and improve code quality. 3. Performance optimization and best practices further improve application efficiency.

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP type prompts to improve code quality and readability. 1) Scalar type tips: Since PHP7.0, basic data types are allowed to be specified in function parameters, such as int, float, etc. 2) Return type prompt: Ensure the consistency of the function return value type. 3) Union type prompt: Since PHP8.0, multiple types are allowed to be specified in function parameters or return values. 4) Nullable type prompt: Allows to include null values and handle functions that may return null values.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SublimeText3 English version
Recommended: Win version, supports code prompts!

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Mac version
God-level code editing software (SublimeText3)

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

Atom editor mac version download
The most popular open source editor