一. 字符串连接符

<?php
$x = 4;
echo "x minus one equals " . $x-1 . ", or so I hope";
?>

打印出来:

"-1, or so I hope"

二. and/or
嗯.php也有and/or这样的逻辑运算符.但是…

$bool = true && false;
var_dump($bool); // false, that's expected

$bool = true and false;
var_dump($bool); // true, ouch!
?>

原来’=’比’and/or’优先级高.

php类型比较表

最近在家又在看php手册。发现对类型转换还是没有那么精通..总是有疑惑..为什么这样.为什么那样..死记是记不住的..还是从源码来动手吧.最终比较函数是zend_operators.c的1599行:

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)&gt;Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)&lt;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;                         default:                                 if (Z_TYPE_P(op1) == IS_OBJECT &amp;&amp; Z_OBJ_HANDLER_P(op1, compare)) {                                         return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC);                                 } else if (Z_TYPE_P(op2) == IS_OBJECT &amp;&amp; Z_OBJ_HANDLER_P(op2, compare)) {                                         return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC);                                 }                                 if (Z_TYPE_P(op1) == IS_OBJECT &amp;&amp; Z_TYPE_P(op2) == IS_OBJECT) {                                         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;                                         }                                         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 TSRMLS_CC));                                                 return SUCCESS;                                         }                                 }                                 if (Z_TYPE_P(op1) == IS_OBJECT) {                                         if (Z_OBJ_HT_P(op1)-&gt;get) {
                                                op_free = Z_OBJ_HT_P(op1)-&gt;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 &amp;&amp; Z_OBJ_HT_P(op1)-&gt;cast_object) {
                                                ALLOC_INIT_ZVAL(op_free);
                                                if (Z_OBJ_HT_P(op1)-&gt;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)-&gt;get) {
                                                op_free = Z_OBJ_HT_P(op2)-&gt;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 &amp;&amp; Z_OBJ_HT_P(op2)-&gt;cast_object) {
                                                ALLOC_INIT_ZVAL(op_free);
                                                if (Z_OBJ_HT_P(op2)-&gt;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;
                                }
                }
        }
}
/* }}} */

省略object类型
代码逻辑如下:

while(1) {
	1. long和double都转为double进行比较;break;
	2. 相同类型的进行比较;break;
	3. string,object和null进行比较;break;
	if (!converted) {
		4. 其它与null,bool比较的都转换为bool再比较;break;
		5. 其它的情况都转换为整形
	} else {
		6. 数组都大于其它类型的值;break;
		7. object都大于其它类型的值;break;
		8. 其它情况的比较都是true;break;
	}
};

好了.这就是PHP各种不同类型比较的逻辑..所以的问题都遵循这个逻辑.

一次诡异的问题处理

话说一位实习生同学把环境部署好。但是登陆不上系统。总是被自动logout

一顿var_export();exit;之后。定位到用户信息存不到memcache中。但是set方法也返回true。
1. 有可能是memcache客户端版本问题?
2. 其它

抓包之后。发现set命令参数为timestamp。刚开始没在意。。然后顺手在机器上date了一下。发现系统时间不正确。。回想起刚才抓包的timestamp。猜测有可能是这个导致的。修改完系统时间马上就好了。。

php调用memcache函数set中。使用的是当前时间偏移。被yii框架自动转为当前机器的ts + 设置的秒数。。导致设置的时间总是落后于memcache服务器时间。

好了。问题解决。