Home Backend Development PHP Tutorial PHP date string comparison example

PHP date string comparison example

Jul 25, 2016 am 09:13 AM

There is a function in the project that compares whether members have expired. I reviewed my colleague’s code and found that the writing method was rather strange, but there were no bugs online.

Achievement:

  1. $expireTime = "2014-05-01 00:00:00";
  2. $currentTime = date('Y-m-d H:i:s', time());
  3. if($currentTime < $expireTime) {
  4. return false;
  5. } else {
  6. return true;
  7. }
Copy code

If two times need to be compared, it is usually converted to a unix timestamp, using two int numbers. Compare. This implementation specifically expresses time as a string, and then performs a comparison operation on the two strings.

Writing aside, I am very curious about how comparison is performed internally in PHP.

Without further ado, let’s start tracking from the source code.

Compilation period Syntax similar to the following can be found in zend_language_parse.y: =expr === Expr {Zend_do_binary_op (ZEND_IS_IDENTICAL, & $ 1, & $ 3 TSRMLS_CC); Identical, & $ $, & $ 1, & $ 3 TSRMLS_CC ); }

expr == expr { zend_do_binary_op(ZEND_IS_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }
expr != expr { zend_do_binary_op(ZEND_IS_NOT_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }
expr < expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$1, &$3 TSRMLS_CC); }
    expr <= expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }
  1. expr > expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); }
  2. expr >= expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); }
  3. Copy code
  4. Obviously, zend_do_binary_op is used to compile opcode here.
void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */

{

zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC );
opline->opcode = op;
    opline->result.op_type = IS_TMP_VAR;
  1. opline->result.u.var = get_temporary_variable(CG(active_op_array));
  2. opline->op1 = *op1;
  3. opline->op2 = *op2;
  4. *result = opline->result;
  5. }
  6. Copy code
  7. This function does not do any special processing, it just simply saves the opcode and operands 1 and operand 2.
Execution period According to the opcode, jump to the corresponding processing 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;
  1. compare_function( result,
  2. &opline->op1.u.constant,
  3. &opline->op2.u.constant TSRMLS_CC);
  4. ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
  5. ZEND_VM_NEXT_OPCODE();
  6. }
  7. Copy the code
  8. Notice that the comparison of two zvals is handled by 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;
  1. while (1) {
  2. switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
  3. case TYPE_PAIR(IS_LONG, IS_LONG):
  4. ...
  5. case TYPE_PAIR(IS_DOUBLE, IS_LONG):
  6. ...
  7. case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
  8. ...
  9. ...
  10. // Compare two strings
  11. case TYPE_PAIR(IS_STRING, IS_STRING):
  12. zendi_smart_strcmp(result, op1, op2);
  13. return SUCCESS;
  14. ...
  15. }
  16. }
  17. }
  18. Copy code
  19. This function exemplifies several situations. According to the case in this article, enter zendi_smart_strcmp to get a closer look:

    1. ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
    2. {
    3. int ret1, ret2;
    4. long lval1, lval2;
    5. double dval1, dval2;
    6. // Try to convert the string to a numeric type
    7. if ((ret1=is_numeric_string(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0)) &&
    8. (ret2=is_numeric_string(Z_STRVAL_P(s2), Z_STRLEN_P( s2), &lval2, &dval2, 0))) {
    9. // Compare numbers
    10. ...
    11. } else {
    12. // All cannot be converted into numbers
    13. // Then call zend_binary_zval_strcmp
    14. // Essentially memcmp One layer of encapsulation
    15. Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
    16. ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
    17. }
    18. }
    Copy code

    Then "2014-05-01 Can 00:00:00" be converted into a number?

    You still have to look at the implementation rules of is_numeric_string.

    1. static inline zend_uchar is_numeric_string(const char *str, int length, long *lval, double *dval, int allow_errors)
    2. {
    3. const char *ptr;
    4. int base = 10, digits = 0, dp_or_e = 0;
    5. double local_dval;
    6. zend_uchar type;
    7. if (!length) {
    8. return 0;
    9. }
    10. /* trim out the blank part at the beginning of the string*/
    11. while (*str == ' ' || * str == 't' || *str == 'n' || *str == 'r' || *str == 'v' || *str == 'f') {
    12. str++;
    13. length- -;
    14. }
    15. ptr = str;
    16. if (*ptr == '-' || *ptr == '+') {
    17. ptr++;
    18. }
    19. if (ZEND_IS_DIGIT(*ptr)) {
    20. /* Determine whether it is hexadecimal */
    21. if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
    22. base = 16;
    23. ptr += 2;
    24. }
    25. /* Ignore the following 0s */
    26. while (*ptr == '0') {
    27. ptr++;
    28. }
    29. /* Calculate the number of digits in the number, and Determine whether it is integer or floating point*/
    30. for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
    31. check_digits:
    32. if (ZEND_IS_DIGIT(*ptr ) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) {
    33. continue;
    34. } else if (base == 10) {
    35. if (*ptr == '.' && dp_or_e < 1) {
    36. goto process_double;
    37. } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
    38. const char *e = ptr + 1;
    39. if (*e == '-' || *e == '+') {
    40. ptr = e++;
    41. }
    42. if (ZEND_IS_DIGIT(*e)) {
    43. goto process_double;
    44. }
    45. }
    46. }
    47. break;
    48. }
    49. if (base == 10) {
    50. if (digits >= MAX_LENGTH_OF_LONG) {
    51. dp_or_e = -1;
    52. goto process_double;
    53. }
    54. } else if (!(digits < SIZEOF_LONG * 2 || (digits == SIZEOF_LONG * 2 && ptr[-digits] <= '7'))) {
    55. if (dval) {
    56. local_dval = zend_hex_strtod(str, (char **)&ptr);
    57. }
    58. type = IS_DOUBLE;
    59. }
    60. } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
    61. // Process floating point numbers
    62. } else {
    63. return 0;
    64. }
    65. // If fault tolerance is not allowed, exit with an error
    66. if ( ptr != str + length) {
    67. if (!allow_errors) {
    68. return 0;
    69. }
    70. if (allow_errors == -1) {
    71. zend_error(E_NOTICE, "A non well formed numeric value encountered");
    72. }
    73. }
    74. // To allow fault tolerance, try to convert str into numbers
    75. if (type == IS_LONG) {
    76. if (digits == MAX_LENGTH_OF_LONG - 1) {
    77. int cmp = strcmp(&ptr[-digits], long_min_digits);
    78. if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
    79. if (dval) {
    80. *dval = zend_strtod(str, NULL);
    81. }
    82. return IS_DOUBLE;
    83. }
    84. }
    85. if (lval) {
    86. *lval = strtol(str, NULL, base);
    87. }
    88. return IS_LONG;
    89. } else {
    90. if (dval) {
    91. *dval = local_dval;
    92. }
    93. return IS_DOUBLE;
    94. }
    95. }
    Copy code

    The code is relatively long, but if you read it carefully, the rules for converting str to num are still very clear.

    Pay special attention to the allow_errors parameter, which directly determines that "2014-05-01 00:00:00" cannot be converted into a number in this example.

    So in the end, the operation of "2014-04-17 00:00:00"

    Since it is memcmp, it is not difficult to understand why the writing method mentioned at the beginning of the article can also run correctly.

    Fault-tolerant conversion When is allow_errors true? An excellent example is zend_parse_parameters. The implementation of zend_parse_parameters will not be described in detail. Interested readers can study it by themselves. When calling is_numeric_string, allow_errors is set to -1.

    For example:

    1. static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
    2. {
    3. char *format;
    4. int format_len;
    5. long ts;
    6. char *string;
    7. // The expected second parameter is timestamp, which is long
    8. // Assuming that the string is mistakenly passed in when the upper layer is called, zend_parse_parameters will still try to parse the string into long as much as possible
    9. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) = = FAILURE) {
    10. RETURN_FALSE;
    11. }
    12. if (ZEND_NUM_ARGS() == 1) {
    13. ts = time(NULL);
    14. }
    15. string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
    16. RETVAL_STRING( string, 0);
    17. }
    Copy code

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

    When calling date, if the second parameter is passed into string, the effect is as follows:

    1. echo date('Y-m-d', '0-1-2');
    2. // Output
    3. PHP Notice: A non well formed numeric value encountered in Command line code on line 1
    4. 1970- 01-01
    Copy code

    Although a notice level error was reported, '0-1-2' was still successfully converted to 0



Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

Describe the SOLID principles and how they apply to PHP development. Describe the SOLID principles and how they apply to PHP development. Apr 03, 2025 am 12:04 AM

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

How to automatically set permissions of unixsocket after system restart? How to automatically set permissions of unixsocket after system restart? Mar 31, 2025 pm 11:54 PM

How to automatically set the permissions of unixsocket after the system restarts. Every time the system restarts, we need to execute the following command to modify the permissions of unixsocket: sudo...

Explain the concept of late static binding in PHP. Explain the concept of late static binding in PHP. Mar 21, 2025 pm 01:33 PM

Article discusses late static binding (LSB) in PHP, introduced in PHP 5.3, allowing runtime resolution of static method calls for more flexible inheritance.Main issue: LSB vs. traditional polymorphism; LSB's practical applications and potential perfo

How to send a POST request containing JSON data using PHP's cURL library? How to send a POST request containing JSON data using PHP's cURL library? Apr 01, 2025 pm 03:12 PM

Sending JSON data using PHP's cURL library In PHP development, it is often necessary to interact with external APIs. One of the common ways is to use cURL library to send POST�...

Framework Security Features: Protecting against vulnerabilities. Framework Security Features: Protecting against vulnerabilities. Mar 28, 2025 pm 05:11 PM

Article discusses essential security features in frameworks to protect against vulnerabilities, including input validation, authentication, and regular updates.

How to debug CLI mode in PHPStorm? How to debug CLI mode in PHPStorm? Apr 01, 2025 pm 02:57 PM

How to debug CLI mode in PHPStorm? When developing with PHPStorm, sometimes we need to debug PHP in command line interface (CLI) mode...

See all articles