php算法题,请路过的高人指点下

发布于 2022-09-06 03:32:51 字数 290 浏览 27 评论 0

图片描述

图片描述

两道PHP体算法题,不懂,请路过的大神帮忙阐述一下原理

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

北斗星光 2022-09-13 03:32:51

问题1 执行结果为:1
问题2 执行结果为:bool(true)

原理解释如下:
关键词:PHP 运算符的优先级 递增/递减运算符规则
演示版本:PHP-5.6
原理分析角度:PHP源码/++操作符源码

PHP 运算符的优先级

clipboard.png
如上所示, || 优先级 高于 = ,所以 || 返回的结果 true (boolean 类型) 复制给了变量左操作数(如题中的变量 $a)。
而赋值表达式的返回结果为左操作数的值,所以这两处可以满足 if 条件。
参考:运算符优先级

++ 运算符的计算规则

递增/递减运算符不影响布尔值。递减 NULL 值也没有效果,但是递增 NULL 的结果是 1。(参考:递增/递减运算符

PHP 手册 上我们可以看到 ++ 运算符对 boolean 类型变量无效,所以 问题1 中的 echo 结果为 1var_dump 结果为 bool(true)

至此,我们已经明白了这两段代码片段有这样结果的原因了。

PHP 源码角度分析 ++ 操作符实现逻辑

(以 问题1 为例)

1. 利用 vld 查看 此段代码的 opcode

➜  answer git:(master) ✗ cat -n question1.php
     1    <?php
     2
     3    $a = 1;
     4    $b = 1;
     5
     6    if ($a = 1 || $b = 1) {
     7        ++$a;
     8    }
     9
    10    echo $a;
    11    var_dump($a);
➜  answer git:(master) ✗ php  -dvld.active=1 -dvld.verbosity=3 question1.php

opcode 结果如下:
clipboard.png
定位第七行代码,我们可以看到 ++ 操作:

  • opcodePRE_INC
  • 操作数类型IS_CV(篮筐内容)

2. 从 PHP 源码 角度分析 ++ 操作符

参考:PHP-5.6 源码

2.1 词法分析

clipboard.png
文件:Zend/zend_language_scanner.l +1343
如图示:++ 操作符所对应的 Token 为:T_INC

2.2 语法分析

clipboard.png
文件:Zend/zend_language_parser.y +795
如图示:通过 T_INC 我们在语法解析文件中定位到了 ++ 操作符所对应的语法解析规则。
我们可以得到:

  • 语法处理函数:zend_do_pre_incdec
  • opcode : ZEND_PRE_INC

分析 zend_do_pre_incdec 方法,及根据 opcode 所对应的 zend_vm 处理方法,我们可以知道,最终 opcodezend_vm 中执行时,所调用的方法是 ZEND_PRE_INC_SPEC_CV_HANDLER (此处根据 opcode (ZEND_PRE_INC) 和 ++ 操作数类型 IS_CV 判断)。

查看 ZEND_PRE_INC_SPEC_CV_HANDLER 方法,源码如下:

static int ZEND_FASTCALL  ZEND_PRE_INC_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    zval **var_ptr;

    SAVE_OPLINE();
    var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC);

    if (IS_CV == IS_VAR && UNEXPECTED(var_ptr == NULL)) {
        zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
    }
    if (IS_CV == IS_VAR && UNEXPECTED(*var_ptr == &EG(error_zval))) {
        if (RETURN_VALUE_USED(opline)) {
            PZVAL_LOCK(&EG(uninitialized_zval));
            EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval);
        }

        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
    }

    SEPARATE_ZVAL_IF_NOT_REF(var_ptr);

    if (UNEXPECTED(Z_TYPE_PP(var_ptr) == IS_OBJECT)
       && Z_OBJ_HANDLER_PP(var_ptr, get)
       && Z_OBJ_HANDLER_PP(var_ptr, set)) {
        /* proxy object */
        zval *val = Z_OBJ_HANDLER_PP(var_ptr, get)(*var_ptr TSRMLS_CC);
        Z_ADDREF_P(val);
        fast_increment_function(val);
        Z_OBJ_HANDLER_PP(var_ptr, set)(var_ptr, val TSRMLS_CC);
        zval_ptr_dtor(&val);
    } else {
        fast_increment_function(*var_ptr); // 这里是重点
    }

    if (RETURN_VALUE_USED(opline)) {
        PZVAL_LOCK(*var_ptr);
        EX_T(opline->result.var).var.ptr = *var_ptr;
    }

    CHECK_EXCEPTION();
    ZEND_VM_NEXT_OPCODE();
}

我们可以看到,此次调用最终会执行 fast_increment_function 方法。
继续跟进 fast_increment_function 方法
clipboard.png
我们会发现调用了 increment_function,此方法源码如下:

ZEND_API int increment_function(zval *op1) /* {{{ */
{
    switch (Z_TYPE_P(op1)) {
        case IS_LONG:
            if (Z_LVAL_P(op1) == LONG_MAX) {
                /* switch to double */
                double d = (double)Z_LVAL_P(op1);
                ZVAL_DOUBLE(op1, d+1);
            } else {
            Z_LVAL_P(op1)++;
            }
            break;
        case IS_DOUBLE:
            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
            break;
        case IS_NULL:
            ZVAL_LONG(op1, 1);
            break;
        case IS_STRING: {
                long lval;
                double dval;

                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
                    case IS_LONG:
                        str_efree(Z_STRVAL_P(op1));
                        if (lval == LONG_MAX) {
                            /* switch to double */
                            double d = (double)lval;
                            ZVAL_DOUBLE(op1, d+1);
                        } else {
                            ZVAL_LONG(op1, lval+1);
                        }
                        break;
                    case IS_DOUBLE:
                        str_efree(Z_STRVAL_P(op1));
                        ZVAL_DOUBLE(op1, dval+1);
                        break;
                    default:
                        /* Perl style string increment */
                        increment_string(op1);
                        break;
                }
            }
            break;
        case IS_OBJECT:
            if (Z_OBJ_HANDLER_P(op1, do_operation)) {
                zval *op2;
                int res;
                TSRMLS_FETCH();

                MAKE_STD_ZVAL(op2);
                ZVAL_LONG(op2, 1);
                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC);
                zval_ptr_dtor(&op2);

                return res;
            }
            return FAILURE;
        default:
            return FAILURE;
    }
    return SUCCESS;
}

我们传入的操作数类型(boolean)不满足所有的 case,所以逻辑走到了 default 而最终执行了 return FAILURE;,再根据函数调用栈返回,我们发现没有对操作数做任何递增处理。

结论

此时,我们可以得出最开始的结论:

递增运算符不影响布尔值。

(当然 递减 操作符分析同理)

暮凉 2022-09-13 03:32:51

上下两张图片都是赋值=操作,赋值操作的结果为true,所以每次都能进入到if中,完毕

终止放荡 2022-09-13 03:32:51

$a = 1 || $b = 1 可以看成 $a = (1 || $b = 1),$a = true;
对PHP不熟,但是如果你自己实现过四则运算,这问题其实很简单。:)

写下不归期 2022-09-13 03:32:51

近似代码

$a = 1;
if ($a = true) {
    ++$a; // ++/–-运算符不影响布尔值
}
策马西风 2022-09-13 03:32:51

if中使用"="号的赋值操作
看等号左侧值最终的值来进行判断

if($a = $b) {
    // ...
}

若$b值为false、null、''、[]、0等值时,以上无法进入block代码块
你也可以把上面的代码理解为如下

$a = $b;
if($a) {
    // ...
}
如若梦似彩虹 2022-09-13 03:32:51

这道题还能难倒人的,我是出题者会在判断里面赋予变量b其他值然后让答题者回答变量b的值

×眷恋的温暖 2022-09-13 03:32:51

= 等运算优先级 比|| 低, 所以得到 $a=true

太阳哥哥 2022-09-13 03:32:51

这个不叫算法题
叫大家来找茬
输出2

何以畏孤独 2022-09-13 03:32:51

写这代码的是不是写错了?这个判断根本没有意义。
两张图里的if中的参数等于全是赋值为1了,不进行比较。直接输出if中的值,第一张图输出为2,第二张图输出为bool(true)

苏璃陌 2022-09-13 03:32:51

$a = 1,$b = 1

不再见 2022-09-13 03:32:51

脑筋急转弯?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文