A case_php tutorial for comparing a "date" string

Source: Internet
Author: User
There is a function of the project is to compare whether the membership expires, review colleague's code, found that its writing is more wonderful, but the line unexpectedly also did not appear bug.

The implementation is broadly as follows:

$expireTime = "2014-05-01 00:00:00"; $currentTime = Date (' y-m-d h:i:s ', Time ()); if ($currentTime < $expireTime) {    return false;} else {    return true;}

If a comparison is required for two times, it is usually converted to a Unix timestamp, compared to a number of two int. The implementation deliberately represents the time as a string and then compares the two strings.

Apart from the wording, I am curious about how internal PHP is compared.

Gossip less, or from the source to start tracking.

Compile time

A syntax similar to the following can be found in zend_language_parse.y:

= = = Expr {zend_do_binary_op (zend_is_identical, &$$, &$, &$!=={Zend_do_binary_op (zend_is_not_identical, &$$, &$, &$=={Zend_do_binary_op (zend_is_equal, &$$, &$, &$! =  {zend_do_binary_op (zend_is_not_equal, &$$, &$, &$ <  {Zend _do_binary_op (Zend_is_smaller, &$$, &$, &$ <=  {zend_do_binary_op (zend_is_smaller_or_equal, &$$, &$, &$ >  {zend_do_binary_op (ZEND_IS _smaller, &$$, &$, &$ >= Span expr< span> {zend_do_binary_op (zend_is_smaller_or_equal, &$$, &$, &$ TSRMLS_CC); } 

It is obvious that zend_do_binary_op is used to compile the opcode here.

void Zend_do_binary_op (Zend_uchar op, Znode *result, const znode *OP1, const znode *OP2 tsrmls_dc)/* {{*/{zend_op *opli NE = Get_next_op (CG (Active_op_array) tsrmls_cc); Opline->opcode = Op;opline->result.op_type = IS_TMP_VAR;opline- >result.u.var = get_temporary_variable (CG (Active_op_array)); opline->op1 = *op1;opline->op2 = *op2;*result = Opline->result;}

The function doesn't do anything special, it simply saves the opcode, operand 1, and operand 2.

Implementation period

According to OpCode, jump to the corresponding handler function: Zend_is_smaller_spec_const_const_handler.

static int Zend_fastcall  Zend_is_smaller_spec_const_const_handler (Zend_opcode_handler_args) {Zend_op *opline = EX (opline); Zval *result = &ex_t (Opline->result.u.var). Tmp_var;compare_function (result,&opline-> Op1.u.constant,&opline->op2.u.constant tsrmls_cc); Zval_bool (Result, (z_lval_p (Result) < 0)); Zend_vm_next_opcode ();}

Note that the comparison of two zval is handled using Compare_function.

Zend_api int compare_function (zval *result, Zval *op1, Zval *op2 tsrmls_dc)/* {{*/{int ret;int converted = 0;zval Op1_c Opy, 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): ... case Type_pair (is_double, Is_long): ... case Type_pair (is_double, is_double): ...//two strings to compare case Type_pair (Is_string, is_string): zendi_smart_strcmp (result, OP1, OP2); return SUCCESS; ...}}

This function is an example of a number of cases, according to the case of this article, enter zendi_smart_strcmp a glimpse:

Zend_api void zendi_smart_strcmp (Zval *result, Zval *s1, Zval *s2)/* {{*/{int ret1, Ret2;long lval1, lval2;double dval1 , dval2;//attempts to convert the string to a numeric type if (Ret1=is_numeric_string (z_strval_p (S1), Z_strlen_p (S1), &lval1, &dval1, 0)) & & (Ret2=is_numeric_string (z_strval_p (S2), z_strlen_p (S2), &lval2, &dval2, 0)) {//Comparison between numbers ...} else { //    cannot all turn into    a number//call ZEND_BINARY_ZVAL_STRCMP    //The MEMCMP layer package z_lval_p (Result) = ZEND_BINARY_ZVAL_STRCMP ( S1, S2); Zval_long (Result, Zend_normalize_bool (z_lval_p (result)));}}

So can "2014-05-01 00:00:00" be converted into numbers?

Still need to look at the implementation of is_numeric_string rules.

Static inline Zend_uchar is_numeric_string (const char *STR, int length, long *lval, double *dval, int allow_errors) {const Char *ptr;int base = ten, digits = 0, Dp_or_e = 0;double Local_dval;zend_uchar type;if (!length) {return 0;} /* Trim off the blank section at the beginning of the string */while (*str = = "| | *str = = ' \ t ' | | *str = = ' \ \ ' | | *str = ' \ r ' | | *str = ' \v ' | | *str = ' \f ') { str++;length--;} ptr = str;if (*ptr = = '-' | | *ptr = = ' + ') {ptr++;} if (Zend_is_digit (*ptr)) {/* is determined to be 16 binary */if (length > 2 && *str = = ' 0 ' && (str[1] = = ' X ' | | str[1] = = ' X ') {base = 16;ptr + = 2;} /* Ignore subsequent several 0 */while (*ptr = = ' 0 ') {ptr++;} /* Calculates the number of digits and determines whether it is an integer or a floating-point */for (type = Is_long;! Digits >= max_length_of_long && (dval | | allow_errors = 1)); digits++, ptr++) {check_digits:if (Zend_is_digit (*ptr) | | (Base = = && Zend_is_xdigit (*ptr))) {continue;} else if (base = =) {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 = =) {if (digits >= max_length_of_long) {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, (char * *) &ptr);} Type = is_double;}} else if (*ptr = = '. ' && zend_is_digit (ptr[1])) {//handle floating-point number} else {return 0;} If fault tolerance is not allowed, the error exits if (ptr! = str + length) {if (!allow_errors) {return 0;} if (allow_errors = =-1) {Zend_error (E_notice, "A non well formed numeric value encountered");}} Allow fault tolerance, try to turn Str into a number if (type = = Is_long) {if (digits = = max_length_of_long-1) {int cmp = strcmp (&ptr[-digits], long_m In_digits); if (!) ( CMP < 0 | | (CMP = = 0 && *str = = '-'))) {if (dval) {*dval = Zend_strtod (str, NULL);} return is_double;}} if (lval) {*lval = Strtol (str, NULL, base);} return Is_long;} else {if (dval) {*dval = Local_dval;} RetuRN is_double;}} 

The code is long, but the rules for STR to NUM are clear, but read carefully.

It is particularly important to note that the Allow_errors parameter, which directly determines that "2014-05-01 00:00:00" cannot be converted to a number in this case.

Thus finally in fact "2014-04-17 00:00:00" < "2014-05-01 00:00:00" Run is the memcmp branch of the walk.

Since it is a memcmp, it is not difficult to understand why the article began to write the wording can also run correctly.

Fault Tolerant Conversions

When is allow_errors true? An excellent example is that the implementation of Zend_parse_parameters,zend_parse_parameters is no longer detailed, and interested readers can study it on their own. Where is_numeric_string is called, the allow_errors is set to-1.

As an example:

static void Php_date (internal_function_parameters, int localtime) {char   *format;int     format_len;long    ts; Char   *string;//expects the second parameter to be timestamp, and for long//to assume that the upper call was mistakenly passed to string, then Zend_parse_ Parameters will still try to parse string as Longif (Zend_parse_parameters (Zend_num_args () tsrmls_cc, S|l, &format, & Format_len, &ts) = = FAILURE) {return_false;} if (Zend_num_args () = = 1) {ts = time (NULL);} string = php_format_date (format, Format_len, TS, localtime tsrmls_cc); Retval_string (STRING, 0);}

This is the internal implementation of the date function of PHP.

When we call date, if we pass the second argument to a string, the effect is as follows:

echo Date (' y-m-d ', ' 0-1-2 ');//Output PHP Notice:  A Non well formed numeric value encountered in Command line code on line 11970-01-01

Although reported the notice level of error, but still succeeded in turning ' 0-1-2 ' into 0

http://www.bkjia.com/PHPjc/755938.html www.bkjia.com true http://www.bkjia.com/PHPjc/755938.html techarticle there is a function of the project is to compare whether the membership expires, review colleague's code, found that its writing is more wonderful, but the line unexpectedly also did not appear bug. The implementation is roughly as follows: $expireTime = "2014-05 ...

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.