Heim  >  Artikel  >  Backend-Entwicklung  >  语法:IF判断的实现

语法:IF判断的实现

WBOY
WBOYOriginal
2016-07-29 08:55:341556Durchsuche

面试PHP时经常碰到一种判断各种类型的空值是否为true的题:

<code>$a = <span>''</span>;
$a = null
$a = false;

<span>if</span>($a){<span>...</span>}
<span>if</span>(isset($a)){<span>...</span>}
<span>if</span>(empty($a)){<span>...</span>}
<span>...</span></code>

由下面的例子我们来简单看下zend引擎中对if是怎么处理的:

<code><span><span><?php </span><span>$a</span> = <span>''</span>; <span>//array();</span><span>if</span>(<span>$a</span>){
    <span>echo</span><span>"Y"</span>;
}</span></span></code>

这里例子比较简单,结果将什么也不输出。(文中涉及代码均为php-7.0.4版本)

之前的文章介绍过zend执行阶段的入口zend_execute函数,我们直接从这里开始,不熟悉的可以翻一下前面的文章。
编译生成的opcodes如下:
语法:IF判断的实现
其中opcode=38是$a = ”的执行操作,opcode=43是if的操作,下面具体看这一步是如何执行的。
根据opcode及两个操作数类型可以找到对应的handler为:ZEND_JMPZ_SPEC_CV_HANDLER

<code><span>//zend_vm_execute.h #28307</span><span>static</span> ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{   
    USE_OPLINE

    zval *<span>val</span>;

    <span>val</span> = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);

    <span>if</span> (Z_TYPE_INFO_P(<span>val</span>) == IS_TRUE) { 
        ZEND_VM_SET_NEXT_OPCODE(opline + <span>1</span>);
        ZEND_VM_CONTINUE();
    } <span>else</span><span>if</span> (EXPECTED(Z_TYPE_INFO_P(<span>val</span>) if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(<span>val</span>) == IS_UNDEF)) {
            SAVE_OPLINE();
            GET_OP1_UNDEF_CV(<span>val</span>, BP_VAR_R);
            ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
        } <span>else</span> {
            ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op2));
            ZEND_VM_CONTINUE();
        }
    }

    SAVE_OPLINE();
    <span>if</span> (i_zend_is_true(<span>val</span>)) {
        opline++;
    } <span>else</span> {
        opline = OP_JMP_ADDR(opline, opline->op2);
    }

    <span>if</span> (UNEXPECTED(EG(<span>exception</span>) != NULL)) {
        HANDLE_EXCEPTION();
    }
    ZEND_VM_JMP(opline);
}</code>

从这个函数可以看出if的执行过程:如果条件为true的话则opline++,顺序执行下一条opcode(即if内语句),否则进行跳转,跳过if内语句直接执行if外语句。

i_zend_is_true这个函数就是用来判断各种类型的值是否为真,前面那部分是判断是否为bool型,是的话则直接处理。

<code><span>//</span>zend_operators.h <span>#283</span>
static zend_always_inline int i_zend_is_true(zval *op)
{   
    int result = <span>0</span>;

<span>again</span>:
    <span>switch</span> (Z_TYPE_P(op)) {
        <span>case</span><span>IS_TRUE</span>:
            result = <span>1</span>;
            <span>break</span>;
        <span>//</span>数值类型long、double直接判断即可,与c用法相同
        <span>case</span><span>IS_LONG</span>:
            <span>if</span> (Z_LVAL_P(op)) {
                result = <span>1</span>;
            }
            <span>break</span>;
        <span>case</span><span>IS_DOUBLE</span>:
            <span>if</span> (Z_DVAL_P(op)) {
                result = <span>1</span>;
            }
            <span>break</span>;
        <span>//</span>字符串类型根据长度判断:长度><span>1</span>,或=<span>1</span>且不为<span>'0'</span>为<span>true</span>,所以上面那个例子<span>''</span><span> =></span><span>false</span><span>case</span><span>IS_STRING</span>:
            <span>if</span> (Z_STRLEN_P(op) > <span>1</span> || (Z_STRLEN_P(op) && Z_STRVAL_P(op)[<span>0</span>] != <span>'0'</span>)) {
                result = <span>1</span>;
            }
            <span>break</span>;
        <span>//</span>数组类型根据数组元素的个数判断:大于<span>0</span>即为真
        <span>case</span><span>IS_ARRAY</span>:
            <span>if</span><span><span>(zend_hash_num_elements(Z_ARRVAL_P(op)))</span> { // <span>(Z_ARRVAL_P(op))</span>-></span>nNumOfElements
                result = <span>1</span>;
            }
            <span>break</span>;
        <span>case</span><span>IS_OBJECT</span>:
            result = zend_object_is_true(op);
            <span>break</span>;
        <span>//</span>资源类型实际就是整形(后续会专门介绍资源类型),所以直接判断即可
        <span>case</span><span>IS_RESOURCE</span>:
            <span>if</span> (EXPECTED(Z_RES_HANDLE_P(op))) {
                result = <span>1</span>;
            }
            <span>break</span>;
        <span>//</span>引用类型则根据指向的值判断
        <span>case</span><span>IS_REFERENCE</span>:
            op = Z_REFVAL_P(op);
            goto again;
            <span>break</span>;
        <span>default</span>:
            <span>break</span>;
    }
    <span>return</span> result;
}</code>

isset、empty函数后续补充……

').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i ').text(i)); }; $numbering.fadeIn(1700); }); });

以上就介绍了语法:IF判断的实现,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn