语言参考
在线手册:中文 英文
PHP手册

表达式

表达式是 PHP 最重要的基石。在 PHP 中,几乎所写的任何东西都是一个表达式。简单但却最精确的定义一个表达式的方式就是“任何有值的东西”。

最基本的表达式形式是常量和变量。当键入“$a = 5”,即将值“5”分配给变量 $a。“5”,很明显,其值为 5,换句话说“5”是一个值为 5 的表达式(在这里,“5”是一个整型常量)。

赋值之后,所期待情况是 $a 的值为 5,因而如果写下 $b = $a,期望的是它犹如 $b = 5 一样。换句话说,$a 是一个值也为 5 的表达式。如果一切运行正确,那这正是将要发生的正确结果。

稍微复杂的表达式例子就是函数。例如,考虑下面的函数:

<?php
function foo ()
{
    return 
5;
}
?>

假定已经熟悉了函数的概念(如果不是的话,请看一下函数的相关章节),那么键入 $c = foo() 从本质上来说就如写下 $c = 5,这没错。函数也是表达式,表达式的值即为它们的返回值。既然 foo() 返回 5,表达式“foo()”的值也是 5。通常函数不会仅仅返回一个静态值,而可能会计算一些东西。

当然,PHP 中的值常常并非是整型的。PHP 支持四种标量值(标量值不能拆分为更小的单元,例如和数组不同)类型:整型值(integer),浮点数值(float),字符串值(string)和布尔值(boolean)。PHP 也支持两种复合类型:数组和对象。这两种类型具可以赋值给变量或者从函数返回。

PHP 和其它语言一样在表达式的道路上发展,但推进得更深远。PHP 是一种面向表达式的语言,从这一方面来讲几乎一切都是表达式。考虑刚才已经研究过的例子,“$a = 5”。很显然这里涉及到两个值,整型常量 5 的值以及而且变量 $a 的值,它也被更新为 5。但是事实是这里还涉及到一个额外的值,即附值语句本身的值。赋值语句本身求值为被赋的值,即 5。实际上这意味着“$a = 5”,不必管它是做什么的,是一个值为 5 的表达式。因而,这样写“$b = ($a = 5)”和这样写“$a =5; $b=5”(分号标志着语句的结束)是一样的。因为赋值操作的顺序是由右到左的,也可以这么写“$b = $a =5”。

另外一个很好的面向表达式的例子就是前、后递增和递减。PHP 和多数其它语言的用户应该比较熟悉变量 ++ 和变量 -- 符号。即递增和递减运算符。在 PHP/FI 2 中,语句“$a++”没有值(不是表达式),这样的话你便不能为其赋值或者以任何其它方式来使用它。PHP 通过将其变为了表达式,类似 C 语言,增强了递增/递减的能力。在 PHP 和 C 语言 中,有两种类型的递增前递增和后递增,本质上来讲,前递增和后递增均增加了变量的值,并且对于变量的影响是相同的。不同的是递增表达式的值。前递增,写做“++$variable”,求增加后的值(PHP 在读取变量的值之前,增加变量的值,因而称之为“前递增”)。后递增,写做“$variable++”,求变量未递增之前的原始值(PHP 在读取变量的值之后,增加变量的值,因而叫做“后递增”)。

一个常用到表达式类型是比较表达式。这些表达式求值 FALSETRUE。PHP 支持 >(大于),>=(大于等于),==(等于),!=(不等于),<(小于),<= (小于等于)。PHP 还支持全等运算符 ===(值和类型均相同)和非全等运算符 !==(值或者类型不同)。这些表达式都是在条件判断语句,比如,if 语句中最常用的。

这里,将要研究的最后一个例子是组合的运算赋值表达式。已经知道如果想要为变量 $a 加1,可以简单的写“$a++”或者“++$a”。但是如果想为变量增加大于 1 的值,比如 3,该怎么做?可以多次写“$a++”,但这样明显不是一种高效舒适的方法,一个更加通用的做法是“$a = $a + 3”。“$a + 3”计算 $a 加上 3 的值,并且得到的值重新赋予变量 $a,于是 $a 的值增加了3。在 PHP 及其它几种类似 C 的语言中,可以以一种更加简短的形式完成上述功能,因而也更加清楚快捷。为 $a 的当前值加 3,可以这样写:“$a += 3”。这里的意思是“取变量 $a 的值,加 3,得到的结果再次分配给变量 $a”。除了更简略和清楚外,也可以更快的运行。“$a += 3”的值,如同一个正常赋值操作的值,是赋值后的值。注意它不是 3,而是 $a 的值加上3 之后的值(此值将被赋给 $a)。任何二元运算符都可以用运算赋值模式,例如“$a -= 5”(从变量 $a 的值中减去 5),“$b *= 7”(变量 $b 乘以 7),等等。

还有一个表达式,如果没有在别的语言中看到过的话,可能看上去很奇怪,即三元条件运算符:

$first ? $second : $third
如果第一个子表达式的值是 TRUE(非零),那么计算第二个子表达式的值,其值即为整个表达式的值。否则,将是第三个子表达式的值。

下面的例子一般来说应该有助于理解前、后递增和表达式:

<?php
function double($i)
{
    return 
$i*2;
}
$b $a 5;        /* assign the value five into the variable $a and $b */
$c $a++;          /* post-increment, assign original value of $a
                       (5) to $c */
$e $d = ++$b;     /* pre-increment, assign the incremented value of
                       $b (6) to $d and $e */

/* at this point, both $d and $e are equal to 6 */

$f double($d++);  /* assign twice the value of $d before
                       the increment, 2*6 = 12 to $f */
$g double(++$e);  /* assign twice the value of $e after
                       the increment, 2*7 = 14 to $g */
$h $g += 10;      /* first, $g is incremented by 10 and ends with the
                       value of 24. the value of the assignment (24) is
                       then assigned into $h, and $h ends with the value
                       of 24 as well. */
?>

一些表达式可以被当成语句。这时,一条语句的形式是 'expr' ';',即一个表达式加一个分号结尾。在“$b=$a=5;”中,$a=5 是一个有效的表达式,但它本身不是一条语句。“$b=$a=5;”是一条有效的语句。

最后一件值得提起的事情就是表达式的真值。在许多事件中,大体上主要是在条件执行和循环中,不要专注于表达式中明确的值,反而要注意表达式的值是否是 TRUE 或者 FALSE。常量 TRUEFALSE(大小写无关)是两种可能的 Boolean 值。如果有必要,一个表达式将自动转换为 Boolean。参见类型强制转换一节。

PHP 提供了一套完整强大的表达式,而为它提供完整的文件资料已经超出了本手册的范围。上面的例子应该为你提供了一个好的关于什么是表达式和怎样构建一个有用的表达式的概念。在本手册的其余部分,我们将始终使用 expr 来表示一个有效的 PHP 表达式。


语言参考
在线手册:中文 英文
PHP手册
PHP手册 - N: 表达式

用户评论:

antickon at gmail dot com (27-Feb-2012 03:29)

evaluation order of subexpressions is not strictly defined for all operators

<?php
function a() {echo 'a';}
function
b() {echo 'b';}
a() == b(); // outputs "ab", ie evaluates left-to-right

$a = 3;
var_dump( $a == $a = 4 ); // outputs bool(true), ie evaluates right-to-left
?>

this is not a bug: "we [php developers] make no guarantee about the order of evaluation".
See https://bugs.php.net/bug.php?id=61188

Lukasz web dot creating dot design at gmail dot com (27-Jan-2012 05:43)

@Magnus Deininger
You are not 100% right.
You can separate variables by comma inside classes. For example

<?php

class Foo
{
    public
$a, $b;
    public
$c = 1, $d = 2;
}

$o = new Foo();
echo
$o->a.PHP_EOL;
echo
$o->b.PHP_EOL;
echo
$o->c.PHP_EOL;
echo
$o->d.PHP_EOL;

?>

Magnus Deininger, dma05 at web dot de (16-Apr-2009 04:04)

Note that even though PHP borrows large portions of its syntax from C, the ',' is treated quite differently. It's not possible to create combined expressions in PHP using the comma-operator that C has, except in for() loops.

Example (parse error):

<?php

$a
= 2, $b = 4;

echo
$a."\n";
echo
$b."\n";

?>

Example (works):
<?php

for ($a = 2, $b = 4; $a < 3; $a++)
{
  echo
$a."\n";
  echo
$b."\n";
}

?>

This is because PHP doesn't actually have a proper comma-operator, it's only supported as syntactic sugar in for() loop headers. In C, it would have been perfectly legitimate to have this:

int f()
{
  int a, b;
  a = 2, b = 4;

  return a;
}

or even this:

int g()
{
  int a, b;
  a = (2, b = 4);

  return a;
}

In f(), a would have been set to 2, and b would have been set to 4.
In g(), (2, b = 4) would be a single expression which evaluates to 4, so both a and b would have been set to 4.

phpsourcecode at blogspot dot com (02-Jul-2008 02:37)

The ternary conditional operator is a useful way of avoiding
http://phpsourcecode.blogspot.com

inconvenient if statements.  They can even be used in the middle of a string concatenation, if you use parentheses.

Example:

if ( $wakka ) {
  $string = 'foo' ;
} else {
  $string = 'bar' ;
}

The above can be expressed like the following:

$string = $wakka ? 'foo' : 'bar' ;

If $wakka is true, $string is assigned 'foo', and if it's false, $string is assigned 'bar'.

To do the same in a concatenation, try:

$string = $otherString . ( $wakka ? 'foo' : 'bar' ) ;

denzoo at gmail dot com (16-Mar-2008 12:52)

To jvm at jvmyers dot com:
Your first two if statements just check if there's anything in the string, if you wish to actually execute the code in your string you need eval().

jvm at jvmyers dot com (24-Feb-2008 08:20)

<?php
// Compound booleans expressed as string args in an 'if' statement don't work as expected:
//
//    Context:
//        1.  I generate an array of counters
//        2.  I dynamically generate a compound boolean based on selected counters in the array
//                Note: since the real array is sparse, I must use the 'empty' operator
//        3.  When I submit the compound boolean as the expression of an 'if' statement,
//            the 'if' appears to resolve ONLY the first element of the compound boolean.
//    Conclusion: appears to be a short-circuiting issue

$aArray = array(1,0);

// Case 1: 'if' expression passed as string:

$sCondition = "!empty($aArray[0]) && !empty($aArray[1])";
if (
$sCondition)
{
    echo
"1. Conditions met<br />";
}
else
{
    echo
"1. Conditions not met<br />";
}

// Case 1 output:  "1. Conditions met"

// Case 2: same as Case 1, but using catenation operator

if ("".$sCondition."")
{
    echo
"2. Conditions met<br />";
}
else
{
    echo
"2. Conditions not met<br />";
}

// Case 2 output:  "2. Conditions met"

// Case 3: same 'if' expression but passed in context:

if (!empty($aArray[0]) && !empty($aArray[1]))
{
    echo
"3. Conditions met<br />";
}
else
{
    echo
"3. Conditions not met<br />";
}

// Case 3 output:  "3. Conditions not met"

// jvm@jvmyers.com
?>

PS: the bug folks say this "does not imply a bug in PHP itself."  Sure bugs me!

petruzanauticoyahoo?com!ar (20-Oct-2007 04:41)

Regarding the ternary operator, I would rather say that the best option is to enclose all the expression in parantheses, to avoid errors and improve clarity:

<?php
  
print ( $a > 1 ? "many" : "just one" );
?>

PS: for php, C++, and any other language that has it.

winks716 (23-Aug-2007 09:42)

reply to egonfreeman at gmail dot com
04-Apr-2007 07:45

the second example u mentioned as follow:
=====================================

$n = 3;
$n * $n++

from 3 * 3 into 3 * 4. Post- operations operate on a variable after it has been 'checked', but it doesn't necessarily state that it should happen AFTER an evaluation is over (on the contrary, as a matter of fact).

===========================================

everything works correctly but one sentence should be modified:

"from 3 * 3 into 3 * 4"  should be "from 3 * 3 into 4 * 3"

best regards~ :)

george dot langley at shaw dot ca (20-Jul-2007 07:01)

Here's a quick example of Pre and Post-incrementation, in case anyone does feel confused (ref anonymous poster 31 May 2005)

<?PHP
echo "Using Pre-increment ++\$a:<br>";
$a = 1;
echo
"\$a = $a<br>";
$b = ++$a;
echo
"\$b = ++\$a, so \$b = $b and \$a = $a<br>";
echo
"<br>";
echo
"Using Post-increment \$a++:<br>";
$a = 1;
echo
"\$a = $a<br>";
$b = $a++;
echo
"\$b = \$a++, so \$b = $b and \$a = $a<br>";
?>

HTH

egonfreeman at gmail dot com (04-Apr-2007 03:45)

It is worthy to mention that:

$n = 3;
$n * --$n

WILL RETURN 4 instead of 6.

It can be a hard to spot "error", because in our human thought process this really isn't an error at all! But you have to remember that PHP (as it is with many other high-level languages) evaluates its statements RIGHT-TO-LEFT, and therefore "--$n" comes BEFORE multiplying, so - in the end - it's really "2 * 2", not "3 * 2".

It is also worthy to mention that the same behavior will change:

$n = 3;
$n * $n++

from 3 * 3 into 3 * 4. Post- operations operate on a variable after it has been 'checked', but it doesn't necessarily state that it should happen AFTER an evaluation is over (on the contrary, as a matter of fact).

So, if you ever find yourself on a 'wild goose chase' for a bug in that "impossible-to-break, so-very-simple" piece of code that uses pre-/post-'s, remember this post. :)

(just thought I'd check it out - turns out I was right :P)

shawnster (15-Feb-2007 12:56)

An easy fix (although intuitively tough to do...) is to reverse the comparison.

if (5 == $a) {}

If you forget the second '=', you'll get a parse error for trying to assign a value to a non-variable.

nabil_kadimi at hotmail dot com (30-Jan-2007 03:46)

Attention! php will not warn you if you write (1) When you mean (2)

(1)
<?
if($a=0)
    echo "condition is true";
else
    echo "condition is false";
//output: condition is false
?>

(2)
<?
if($a==0)
    echo "condition is true";
else
    echo "condition is false";
//output: condition is true
?>

richard at phase4 dot ie (19-Jan-2006 08:00)

Follow up on Martin K. There are no hard and fast rules regarding operator precedence. Newbies should definitely learn them, but if their use results in code that is not easy to read you should use parentheses. The two important things are that it works properly AND is maintainable by you and others.

Martin K (21-Oct-2005 02:28)

At 04-Feb-2005 05:13, tom at darlingpet dot com said:
> It's also a good idea to use parenthesis when using something SIMILAR to:
>
> <?php
> echo (trim($var)=="") ? "empty" : "not empty";
>
?>

No, it's a BAD idea.

All the short-circuiting operators, including the ternary conditional operator, have LOWER precedence than the comparison operators, so they almost NEVER need parentheses around their subexpressions.

Inserting the parentheses suggested above does not change the meaning of the code, but their use misleads inexperienced programmers to expect that things like this will work in a similar manner:

<?php
function my_print($a) { print($a); }
my_print (trim($var)=="") ? "empty" : "not empty";
?>

when of course it doesn't.

Rather than worrying that code doesn't work as expected, simply learn the precedence rules (http://www.php.net/manual/en/language.operators.php) so that one expects the right things.

stochnagara at hotmail dot com (19-Aug-2005 01:06)

12345alex at gmx dot net 's case is actually handled by the === operator. That's what he needs.

There is also another widely used function. I call it myself is_nil which is true for NULL,FALSE,array() and '', but not for 0 and "0".

function is_nil ($value) {
 return !$value && $value !== 0 && $value !== '0';
}

Another useful function is "get first argument if it is not empty or get second argument otherwise". The code is:

function def ($value, $defaultValue) {
 return is_nil ($value) ? $defaultValue : $value;
}

12345alex at gmx dot net (14-Aug-2005 03:00)

this code:
    print array() == NULL ? "True" : "False";
    print " (" . (array() == NULL) . ")\n";

    $arr = array();
    print array() == $arr ? "True" : "False";
    print " (" . (array() == $arr) . ")\n";

    print count(array()) . "\n";
    print count(NULL) . "\n";

will output (on php4 and php5):
    True (1)
    True (1)
    0
    0

so to decide wether i have NULL or an empty array i will also have to use gettype(). this seems some kind of weird for me, although if is this is a bug, somebody should have noticed it before.

alex

sabinx at gmail dot com (26-Jun-2005 07:25)

Pre- and Post-Incrementation, I believe, are important to note and in the correct place. The section deals with the value of an expression. ++$a and $a++ have different values, and both forms have valid uses.

And, because it can be confusing, it is that much more important to note. Although it could be worded better, it does belong.

(31-May-2005 08:07)

I don't see why it is necessary here to explain pre- and post- incrementing.

This is something that will confuse new users of PHP, even longer time programmers will sometimes miss a the fine details of a construct like that.

If something has a side-effect it should be on a line of it's own, or at least be an expression of it's own and not part of an assignment, condition or whatever.

tom at darlingpet dot com (04-Feb-2005 10:13)

Something I've noticed with ternary expressions is if you do something like :

<?= $var=="something" ? "is something" : "not something"; ?>

It will give wacky results sometimes...

So be sure to enclose the ternary expression in parenthesis when ever necessary (such as having multiple expressions or nested ternary expressions)

The above could look like:

<?= ($var=="something") ? "is something" : "not something"; ?>

It's also a good idea to use parenthesis when using something SIMILAR to:

<?php
echo (trim($var)=="") ? "empty" : "not empty";
?>

In some cases other than the <?= ?> example, not placing the entire expression in appropriate parenthesis might yield undesirable results as well.. but I'm not quite sure.

stian at datanerd dot net (25-Feb-2003 10:37)

The short-circuit feature is indeed intended, and there are two types of evaluators, those who DO short-circuit, and those who DON'T, || / && and | / & respectively.
The latter method is the bitwise operators, but works great with the usual boolean values ( 0/1 )

So if you don't want short-circuiting, try using the | and & instead.

Read more about the bitwise operators here:
http://www.php.net/manual/en/language.operators.bitwise.php

oliver at hankeln-online dot de (07-Aug-2002 02:06)

The short-circuiting IS a feature. It is also available in C, so I suppose the developers wont remove it in future PHP versions.

It is rather nice to write:

$file=fopen("foo","r") or die("Error!");

Greets,
Oliver

php at cotest dot com (17-Jul-2002 07:08)

It should probably be mentioned that the short-circuiting of expressions (mentioned in some of the comments above) is often called "lazy evaluation" (in case someone else searches for the term "lazy" on this page and comes up empty!).

Mattias at mail dot ee (25-May-2002 11:29)

A note about the short-circuit behaviour of the boolean operators.

1. if (func1() || func2())
Now, if func1() returns true, func2() isn't run, since the expression
will be true anyway.

2. if (func1() && func2())
Now, if func1() returns false, func2() isn't run, since the expression
will be false anyway.

The reason for this behaviour comes probably from the programming
language C, on which PHP seems to be based on. There the
short-circuiting can be a very useful tool. For example:

int * myarray = a_func_to_set_myarray(); // init the array
if (myarray != NULL && myarray[0] != 4321) // check
    myarray[0] = 1234;

Now, the pointer myarray is checked for being not null, then the
contents of the array is validated. This is important, because if
you try to access an array whose address is invalid, the program
will crash and die a horrible death. But thanks to the short
circuiting, if myarray == NULL then myarray[0] won't be accessed,
and the program will work fine.

yasuo_ohgaki at hotmail dot com (12-Mar-2001 07:14)

Manual defines "expression is anything that has value", Therefore, parser will give error for following code.

<?php
($val) ? echo('true') : echo('false');
Note: "? : " operator has this syntax  "expr ? expr : expr;"
?>

since echo does not have(return) value and ?: expects expression(value).

However, if function/language constructs that have/return value, such as include(), parser compiles code.

Note: User defined functions always have/return value without explicit return statement (returns NULL if there is no return statement). Therefore, user defined functions are always valid expressions.
[It may be useful to have VOID as new type to prevent programmer to use function as RVALUE by mistake]

For example,

<?php
($val) ? include('true.inc') : include('false.inc');
?>

is valid, since "include" returns value.

The fact "echo" does not return value(="echo" is not a expression), is less obvious to me.

Print() and Echo() is NOT identical since print() has/returns value and can be a valid expression.

anthony at n dot o dot s dot p dot a dot m dot trams dot com (24-Nov-2000 07:01)

The ternary conditional operator is a useful way of avoiding inconvenient if statements.  They can even be used in the middle of a string concatenation, if you use parentheses. 

Example:

if ( $wakka ) {
  $string = 'foo' ;
} else {
  $string = 'bar' ;
}

The above can be expressed like the following:

$string = $wakka ? 'foo' : 'bar' ;

If $wakka is true, $string is assigned 'foo', and if it's false, $string is assigned 'bar'.

To do the same in a concatenation, try:

$string = $otherString . ( $wakka ? 'foo' : 'bar' ) ;