php手册阅读之惑类型转换

结合源码看一遍PHP手册吧。。
看到BOOL类型这里:

当转换为 boolean 时,以下值被认为是 FALSE:

布尔值 FALSE 本身
整型值 0(零)
浮点型值 0.0(零)
空字符串,以及字符串 "0"
不包括任何元素的数组
不包括任何成员变量的对象(仅 PHP 4.0 适用)
特殊类型 NULL(包括尚未赋值的变量)
从空标记生成的 SimpleXML 对象

打个疑问。为什么是这样。PHP内部是怎么做的。。咱从源码入手吧。。强制类型转换是(bool)符号。好。那么搜一下源码

root@hackers365-HP-Compaq-Elite-8300-SFF:/data/software/php-5.5.14/Zend# g '(bool)'
...
zend_language_parser.y:119:%token T_BOOL_CAST   "(bool) (T_BOOL_CAST)"
...

好。看到他将(bool)转换为T_BOOL_CAST这样的token符号了。继续搜’T_BOOL_CAST’

root@hackers365-HP-Compaq-Elite-8300-SFF:/data/software/php-5.5.14/Zend# g 'T_BOOL_CAST'
zend_language_parser.c:194:     T_BOOL_CAST = 291,
zend_language_parser.c:327:#define T_BOOL_CAST 291
.....
...
zend_language_parser.y:802:	|	T_BOOL_CAST expr	{ zend_do_cast(&$$, &$2, IS_BOOL TSRMLS_CC); }
....

好。看到他是用zend_do_cast来执行的。再搜一下zend_do_cast是做什么的。

root@hackers365-HP-Compaq-Elite-8300-SFF:/data/software/php-5.5.14/Zend# g 'zend_do_cast('
zend_compile.c:6057:void zend_do_cast(znode *result, const znode *expr, int type TSRMLS_DC) /* {{{ */
zend_compile.h:597:void zend_do_cast(znode *result, const znode *expr, int type TSRMLS_DC);
zend_language_parser.c:4889:    { zend_do_cast(&(yyval), &(yyvsp[(2) - (2)]), IS_LONG TSRMLS_CC); }
zend_language_parser.c:4894:    { zend_do_cast(&(yyval), &(yyvsp[(2) - (2)]), IS_DOUBLE TSRMLS_CC); }
zend_language_parser.c:4899:    { zend_do_cast(&(yyval), &(yyvsp[(2) - (2)]), IS_STRING TSRMLS_CC); }
zend_language_parser.c:4904:    { zend_do_cast(&(yyval), &(yyvsp[(2) - (2)]), IS_ARRAY TSRMLS_CC); }

root@hackers365-HP-Compaq-Elite-8300-SFF:/data/software/php-5.5.14/Zend# vi zend_compile.c +6057
.....

void zend_do_cast(znode *result, const znode *expr, int type TSRMLS_DC) /* {{{ */
{
        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

        opline->opcode = ZEND_CAST;
        opline->result_type = IS_TMP_VAR;
        opline->result.var = get_temporary_variable(CG(active_op_array));
        SET_NODE(opline->op1, expr);
        SET_UNUSED(opline->op2);
        opline->extended_value = type;
        GET_NODE(result, opline->result);
}

看opline->opcode = ZEND_CAST这行。它的opcode是ZEND_CAST。继续搜ZEND_CAST

root@hackers365-HP-Compaq-Elite-8300-SFF:/data/software/php-5.5.14/Zend# g 'ZEND_CAST'
zend_compile.c:6061:	opline->opcode = ZEND_CAST;
匹配到二进制文件 zend_execute.o
zend_vm_def.h:3674:ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY)
zend_vm_execute.h:2581:static int ZEND_FASTCALL  ZEND_CAST_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_vm_execute.h:7893:static int ZEND_FASTCALL  ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_vm_execute.h:13210:static int ZEND_FASTCALL  ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_vm_execute.h:30804:static int ZEND_FASTCALL  ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_vm_execute.h:41386:  	ZEND_CAST_SPEC_CONST_HANDLER,
zend_vm_execute.h:41387:  	ZEND_CAST_SPEC_CONST_HANDLER,
zend_vm_execute.h:41388:  	ZEND_CAST_SPEC_CONST_HANDLER,
zend_vm_execute.h:41389:  	ZEND_CAST_SPEC_CONST_HANDLER,
zend_vm_execute.h:41390:  	ZEND_CAST_SPEC_CONST_HANDLER,
zend_vm_execute.h:41391:  	ZEND_CAST_SPEC_TMP_HANDLER,
zend_vm_execute.h:41392:  	ZEND_CAST_SPEC_TMP_HANDLER,
zend_vm_execute.h:41393:  	ZEND_CAST_SPEC_TMP_HANDLER,

看这一行
zend_vm_execute.h:7893:static int ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)

static int ZEND_FASTCALL  ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
        USE_OPLINE
        zend_free_op free_op1;
        zval *expr;
        zval *result = &EX_T(opline->result.var).tmp_var;

        SAVE_OPLINE();
        expr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);

        if (opline->extended_value != IS_STRING) {
                ZVAL_COPY_VALUE(result, expr);
                if (!1) {
                        zendi_zval_copy_ctor(*result);
                }
        }
        switch (opline->extended_value) {
                case IS_NULL:
                        convert_to_null(result);
                        break;
                case IS_BOOL:
                        convert_to_boolean(result);
                        break;
                case IS_LONG:
                        convert_to_long(result);
                        break;
                case IS_DOUBLE:
                        convert_to_double(result);
                        break;
                case IS_STRING: {
                        zval var_copy;
                        int use_copy;

                        zend_make_printable_zval(expr, &var_copy, &use_copy);
                        if (use_copy) {
                                ZVAL_COPY_VALUE(result, &var_copy);
                                if (1) {
                                        zval_dtor(free_op1.var);
                                }
                        } else {
                                ZVAL_COPY_VALUE(result, expr);
                                if (!1) {
                                        zendi_zval_copy_ctor(*result);
                                }
                        }
                        break;
                }
                case IS_ARRAY:
                        convert_to_array(result);
                        break;
                case IS_OBJECT:
                        convert_to_object(result);
                        break;
        }

        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
}

好了。看着位置了。。opline->extended_value这行在
zend_language_parser.y:802: | T_BOOL_CAST expr { zend_do_cast(&$$, &$2, IS_BOOL TSRMLS_CC); }
定义为IS_BOOL。所以这里继续看convert_to_boolean这个函数

root@hackers365-HP-Compaq-Elite-8300-SFF:/data/software/php-5.5.14/Zend# g 'convert_to_boolean('
zend_execute.h:135:						convert_to_boolean(tmp);
zend_operators.c:292:#define zendi_convert_to_boolean(op, holder, result)				\
zend_operators.c:294:		convert_to_boolean(op);										\
zend_operators.c:321:				convert_to_boolean(&(holder));						\
zend_operators.c:511:ZEND_API void convert_to_boolean(zval *op) /* {{{ */

找着了。在zend_operators.c:511行这里。。


ZEND_API void convert_to_boolean(zval *op) /* {{{ */
{
        int tmp;

        switch (Z_TYPE_P(op)) {
                case IS_BOOL:
                        break;
                case IS_NULL:
                        Z_LVAL_P(op) = 0;
                        break;
                case IS_RESOURCE: {
                                TSRMLS_FETCH();

                                zend_list_delete(Z_LVAL_P(op));
                        }
                        /* break missing intentionally */
                case IS_LONG:
                        Z_LVAL_P(op) = (Z_LVAL_P(op) ? 1 : 0);
                        break;
                case IS_DOUBLE:
                        Z_LVAL_P(op) = (Z_DVAL_P(op) ? 1 : 0);
                        break;
                case IS_STRING:
                        {
                                char *strval = Z_STRVAL_P(op);

                                if (Z_STRLEN_P(op) == 0
                                        || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) {
                                        Z_LVAL_P(op) = 0;
                                } else {
                                        Z_LVAL_P(op) = 1;
                                }
                                STR_FREE(strval);
                        }
                        break;
                case IS_ARRAY:
                        tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
                        zval_dtor(op);
                        Z_LVAL_P(op) = tmp;
                        break;
                case IS_OBJECT:
                        {
                                zend_bool retval = 1;
                                TSRMLS_FETCH();

                                convert_object_to_type(op, IS_BOOL, convert_to_boolean);

                                if (Z_TYPE_P(op) == IS_BOOL) {
                                        return;
                                }

                                zval_dtor(op);
                                ZVAL_BOOL(op, retval);
                                break;
                        }
                default:
                        zval_dtor(op);
                        Z_LVAL_P(op) = 0;
                        break;
        }
        Z_TYPE_P(op) = IS_BOOL;
}

终于看着核心位置了。。这里就是做转换的函数。。那么我们接着上边手册的看

布尔值 FALSE 本身
整型值 0(零)
浮点型值 0.0(零)
空字符串,以及字符串 "0"
不包括任何元素的数组
不包括任何成员变量的对象(仅 PHP 4.0 适用)
特殊类型 NULL(包括尚未赋值的变量)
从空标记生成的 SimpleXML 对象

1. 布尔值本身。这就不用说了。

             case IS_BOOL:
                   break;

直接break了。。

2. 整型值/浮点值

                case IS_LONG:
                        Z_LVAL_P(op) = (Z_LVAL_P(op) ? 1 : 0);
                        break;

跟c语言的定义一样。如果表达式的值为真就是1(即bool的true),如果为假就是0(false)

3. 空字符串

                 if (Z_STRLEN_P(op) == 0
                         || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) {
                         Z_LVAL_P(op) = 0;
                  } else {
                         Z_LVAL_P(op) = 1;
                  }

如果字符串长度为空或只有一个值’0’就为假。。否则为真

4. 不包括任何元素的数组

                case IS_ARRAY:
                        tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
                        zval_dtor(op);
                        Z_LVAL_P(op) = tmp;

只看数组元素为不为空。为空就为假。否则为真

5. 特殊类型 NULL(包括尚未赋值的变量)

                case IS_NULL:
                        Z_LVAL_P(op) = 0;
                        break;

不用解释。。。

好了。到这里已经完整的从源码来解释了强制类型转换到bool的各种情况。。

php编译时出现的几个问题

编译参数

‘./configure’  ‘–prefix=/usr/local/php.5.3.10′

‘–enable-fpm’

‘–with-openssl’

‘–with-pcre-regex’

‘–with-zlib’

‘–with-bz2′

‘–with-curl’

‘–with-gd’

‘–with-gettext’

‘–enable-mbstring’

‘–with-mcrypt’

‘–with-mysql=/usr/local/mysql’

‘–with-pdo-mysql’

‘–enable-zip’

‘–with-pear’

‘–with-libdir=lib64′

‘–enable-exif’

‘–enable-sockets’

‘–enable-ftp’

‘–with-gmp’

‘–with-mhash’

‘–with-mysqli=/usr/local/mysql/bin/mysql_config’

‘–enable-pcntl’

‘–with-snmp’

‘–enable-soap’

‘–enable-sysvmsg’

‘–with-tidy’

‘–enable-wddx’

‘–with-kerberos’

‘–with-jpeg-dir’

‘–with-png-dir’

‘–with-freetype-dir’

‘–with-readline’

–enable-bcmath

–with-mysql-sock=/tmp/mysql.sock

1. configure: error: Cannot find libmysqlclient under /usr/local/mysql

原因是因为我编译是64位系统。而mysql二进制分发包里是lib。。

解决方法:

ln -s /usr/local/mysql/lib /usr/local/mysql/lib64

2. checking for mysql_config… not found

ln -s /usr/local/mysql/bin/mysql_config /usr/bin/mysql_config

3. /usr/bin/ld: cannot find -lltdl

wget http://mirrors.ustc.edu.cn/gnu/libtool/libtool-2.4.tar.gz

make

make install

PHP Warning: Xdebug MUST be loaded as a Zend extension in Unknown on line 0 解决办法

;extension=php_xdebug.dll
zend_extension_ts= “X:\php\ext\php_xdebug.dll”

另:根据 PHP 版本,zend_extension 指令可以是以下之一:

zend_extension (non ZTS, non debug build)
zend_extension_ts ( ZTS, non debug build)
zend_extension_debug (non ZTS, debug build)
zend_extension_debug_ts ( ZTS, debug build)

ZTS:ZEND Thread Safety

可通过phpinfo()查看ZTS是否启用,从而决定用zend_extension还是zend_extension_ts。

extension意为基于php引擎的扩展

zend_extension意为基于zend引擎的扩展

注:php是基于zend引擎的

不同的扩展安装后,在php.ini里是用extension还是zend_extension,是取决于该扩展,有的扩展可能只能用 zend_extension,如xdebug,也有的扩展可以用extension或zend_extension,如mmcache。

注:上面的结论不保证准确。

zend_extension加载php扩展时需用全路径,而extension加载时可以用相对extension_dir的路径。

 

 

转自:http://blog.163.com/lgh_2002/blog/static/440175262010910103342213/