Press "Enter" to skip to content

PHP运算符优先级的一个例外

今天在老王的技术手册看到一个问题:

<?php
if ($a = 100 && $b = 200) {
	var_dump($a, $b);
}

输出是什么?
这个问题, 咋一看或许觉得简单, 但其实仔细推敲并不简单,
如果说布尔与之前的部分, 是由于优先级的问题, 但是如果仅仅是优先级的问题的话, 那么结果应该是:

$a = (100 && $b) = 200

而实际上的结果, 确实高优先级的&&让步给次优先级的=, 让 $b = 200 先结合了.
究其原因, 是因为PHP并不完全遵守优先级的定义, 这个在PHP的手册中也有说明:

Note: Although = has a lower precedence than most other operators, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.

这样的设计, 个人不发表看法, 反正在C语言中, 这样类似的语句是判定为语法错的. PHP采用这样的设计, 很可能是历史原因,
有好奇的同学, 会想知道到底为什么, 之前jayeeliu网友也问过:

laruence你好:
问一个php运算符优先级的问题
$t == 1 && $tt = 2
按照php运算符优先级应该是
(($t == 1) && $tt) = 2
这个顺序执行,但实际上应该是
($t == 1) && ($tt = 2)
我有些不太理解。

其实也简单, 运算符优先级是在存在二义性文法的时候的一种规约规则选择的手段, 而PHP的语法分析文件定义中, 却让等号和T_BOOLEAN_AND(&&)之前不存在了规约冲突:

expr_without_variable:
  // 有隐规则存在, 相当于T_BOOLEAN_AND成为了"一元操作符".
  |   expr T_BOOLEAN_AND  { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } expr

最后, 顺便说一下, PHP对应于T_BOOLEAN_AND 还定义了 T_LOGICAL_AND(and) 和 T_LOGICAL_OR(or) , 这俩个的优先级都低于等号, 于是就会有了, 很多PHP入门教材示例代码中经典的:

$result = mysql_query(*)  or die(mysql_error());

类似的还可以用or来实现三元操作符(?:)的功能:

	$person = $who or $person = "laruence";
//等同于:
	$person = empty($who)? "laruence" : $who;

30 Comments

  1. qwe
    qwe December 7, 2019

    越看越糊涂

  2. mace
    mace June 26, 2017

    @DDDDemo
    个人感觉你这段
    !$a=false && $b=100
    实际执行效果应该是
    !($a = (false && ($b = 100)))

  3. nangua
    nangua August 8, 2016

    最后一个例子有些问题。对于who未定义的情况,这样会被发出警告信息的。
    Notice: Undefined variable: who 。而用empty则不会

  4. DDDDemo
    DDDDemo May 26, 2016

    大神您好,我现在有一个问题不太理解。
    if($a=true && $b=100){
    var_dump($a,$b);
    }
    我把代码改成上面这样,仍然是预期的结果
    但是我改成下面这样的时候
    if(!$a=false && $b=100){
    var_dump($a,$b);
    }
    不仅notice,$b也是null。
    是否我遗漏了什么知识点呢?

    • yinshiyionly
      yinshiyionly August 13, 2020

      $a && $b = $c 表示:如果$a为真,则执行$b = $c,否则不执行
      在你的第二段代码里,$a=false,所以$b不会被赋值,打印的时候,$b没有定义,所以报notice

  5. cctwl
    cctwl May 22, 2015

    $a = 1;
    $a = $a + $a + ($a = 2) ; //结果是4
    $a = $a + ($a = 2) ; //结果是4

  6. xonze
    xonze November 21, 2013

    $a = 1;
    $b = &$a;
    echo ++$a + $a++;
    //鸟哥,这里因为上一句$b = &$a;导致结果是5不是4,这是为什么?

  7. 秋风
    秋风 June 7, 2013

    受益匪浅,学习了!

  8. 胡小光
    胡小光 March 10, 2013

    php 手册上是有说明 php 运算符的优先级的,http://www.php.net/manual/zh/language.operators.precedence.php,哥不要在这里诱导人家好不

  9. bird
    bird April 4, 2012

    @azhun 而且,在js里 = 的优先级比 logical operator 低

  10. 雪候鸟
    雪候鸟 June 10, 2011

    @azhun 这个还不太一样, js的||返回的是变量本身, 而PHP的逻辑运算返回的是boolean

  11. azhun
    azhun June 9, 2011

    Javascript也类似于此,例如 var e = a || b;

  12. iterse
    iterse November 8, 2010

    看来以后还要多看看细节。

  13. toobull.com
    toobull.com October 3, 2010

    不错…以前都没刻意注意过..

  14. Bun Wong
    Bun Wong September 6, 2010

    恩,恩,确实是这样的

  15. Audio
    Audio August 31, 2010

    以前还一直没遇到过这种情况,受教了!以后写代码还是要多按标准写!

  16. 排头兵
    排头兵 July 31, 2010

    受教,呵呵。
    优先级 !!!

  17. 雪候鸟
    雪候鸟 July 27, 2010

    @anyharding 我们可以要求自己的代码易读, 但无法保证别人的代码. 🙂

  18. 火跃
    火跃 July 27, 2010

    不错!学习了!

  19. anyharding
    anyharding July 27, 2010

    为什么要写歧义代码,加上小括号不就好了吗?
    代码是让人读的,提高可读性的同时,也避免犯一些错误

  20. 雪候鸟
    雪候鸟 July 26, 2010

    @yyj 你想xss我? 太坏了..

  21. yyj
    yyj July 26, 2010

    alert(‘ddd’);

  22. liruqi
    liruqi July 26, 2010

    这种问题挺tricky
    还是尽量避免magic code比较方便。

  23. 半醒
    半醒 July 26, 2010

    mysql connect那语句的确很经典
    这种优先级的约束能不能认为是更符合人的自然思维?

Comments are closed.