Выражения

Выражения — самые важные строительные элементы 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 поддерживает четыре типа скалярных значений: целочисленные значения (int), значения с плавающей точкой (float), строковые (string) и логические (bool) значения (скалярные значения это те, которые нельзя «разбить» на меньшие части, в отличие, например, от массивов). PHP поддерживает также два сложных (составных, композитных — нескалярных) типа: массивы и объекты. Каждое из этих типов значений разрешено присваивать переменной или возвращать функцией.

Однако PHP использует выражения значительно шире, точно так же, как это делают другие языки. PHP — язык с ориентацией на выражения, который почти всё в коде рассматривает как выражение. Вернёмся к тому примеру, с которым уже имели дело: $a = 5. Легко заметить, что здесь содержится два значения — значение целочисленной константы 5 и значение переменной $a, которая также принимает значение 5. Но, хотя это неочевидно, здесь содержится ещё одно значение — значение самого присваивания. Само присваивание вычисляется в значение, которое присваивется переменной, в приведённом примере — в значение 5. Поэтому выражение $a = 5 независимо от того, что оно делает, — это выражение со значением 5. Поэтому запись $b = ($a = 5) равносильна записи $a = 5; $b = 5; (точка с запятой означает конец инструкции). Поскольку операции присваивания анализируются справа налево, разрешается также написать $b = $a = 5.

Другой хороший пример ориентированности на выражения — префиксный и постфиксный инкремент и декремент. Пользователи PHP и других языков возможно уже знакомы с формой записи variable++ и variable--. Это операторы инкремента и декремента. Как и язык Си, язык PHP поддерживает два типа инкремента — префиксный и постфиксный. Они оба инкрементируют значение переменной и эффект их действия на неё одинаков. Разница состоит в значении выражения инкремента. Префиксный инкремент, записываемый как ++$variable, вычисляется в инкрементированное значение (PHP инкрементирует переменную до того как прочесть её значение, отсюда название «преинкремент»). Постфиксный инкремент, записываемый как $variable++, вычисляется в первоначальное значение переменной $variable до её приращения (PHP вначале читает значение переменной и только потом инкрементирует её, отсюда название «постинкремент»).

Распространённые типы выражений — выражения сравнения. Эти выражения вычисляются либо как false (ложь), либо как true (истина). PHP поддерживает операции сравнения > (больше), >= (больше либо равно), == (равно), != (не равно), < (меньше) и <= (меньше либо равно). Он также поддерживает операторы строгого равенства: === (равно и одного типа) и !== (не равно или не одного типа). Обычно этими выражениями пользуются в операторах условного выполнения, например, инструкции if.

Последний пример выражений, который здесь рассматривается, это смешанные выражения операции и присваивания. Уже известно, что когда требуется увеличить значение переменной $a на 1, записывают $a++ или ++$a. Но что, если потребуется прибавить больше единицы, например 3? Можно было бы написать $a++ много раз, однако, очевидно, это нерационально и неудобно. Наиболее распространённая практика — запись вида $a = $a + 3. Выражение $a + 3 вычисляется в значение переменной $a, к которому прибавляется 3 и снова присваивается значение переменной $a, увеличивая в результате значение переменной $a на 3. В PHP, как и в ряде других языков, например Си, это же присваивание записывается короче, что увеличит очевидность смысла и скорость понимания кода по прошествии времени. Тройку к текущему значению переменной $a прибавляют так: $a += 3. Это означает дословно «взять значение переменной $a, прибавить к нему значение 3 и снова присвоить результат сложения переменной $a». Кроме большей понятности и краткости, это быстрее работает. Значением выражения $a += 3, как и стандартного присваивания, станет значение, которое присвоилось переменной. Обратите внимание, что это НЕ 3, а суммированное значение переменной $a плюс 3 (то, что присвоилось перменной $a). Поэтому разрешается использовать любой бинарный оператор, например, $a -= 5 (вычесть 5 из значения переменной $a), $b *= 7 (умножить значение переменной $b на 7) и т. д.

Ещё одно выражение, которое выглядит необычно, если читатель не встречал такое выражение в других языках, — тернарный условный оператор:

<?php

$first
? $second : $third
?>

Если значение первого подвыражения — true (ненулевое значение), то выполняется второе подвыражение, которое и будет результатом условного выражения. Или выполняется третье подвыражение и его значение будет результатом.

Задача следующего примера — помочь немного улучшить понимание префиксного и постфиксного инкремента и выражений:

<?php

function double($i)
{
return
$i*2;
}

$b = $a = 5; /* присвоить значение пять переменным $a и $b */
$c = $a++; /* постфиксный инкремент, присвоить значение переменной
$a (5) — переменной $c */
$e = $d = ++$b; /* префиксный инкремент, присвоить увеличенное
значение переменной $b (6) — переменным $d и $e */

/* в этой точке и переменная $d, и переменная $e равны 6 */

$f = double($d++); /* присвоить удвоенное значение перменной $d перед
инкрементом (2 * 6 = 12) — переменной $f */
$g = double(++$e); /* присвоить удвоенное значение перменной $e после
инкремента (2 * 7 = 14) — переменной $g */
$h = $g += 10; /* сначала переменная $g увеличивается на 10,
приобретая, в итоге, значение 24. Затем значение
присваивания (24) присваивается переменной $h,
которая в итоге также становится равной 24. */
?>

Иногда PHP рассматривает выражения как инструкции. В этом случае у инструкции следующий вид — «expr ;», то есть выражение, за которым следует точка с запятой. В записи $b = $a = 5;, часть $a = 5 — допустимое выражение, но оно само — не инструкция. Тогда как запись $b = $a = 5; — допустимая инструкция.

Последнее, что вспомним, — истинность значения выражений. Обычно в условных операторах и циклах может интересовать не конкретное значение выражения, а только его истинность (значение true или false). Константы true и false (регистронезависимые) — два возможных логических значения. Выражения разрешено автоматически преобразовать в логическое значение. Подробнее о том, как это сделать, рассказано в разделе о приведении типов.

Язык PHP со всей полнотой и мощностью реализует выражения, и их полное документирование выходит за рамки этого руководства. Примеры выше дают представление о выражениях, о том, что они из себя представляют, и как можно создавать полезные выражения. Для обозначения любого верного выражения PHP в этой документации будет использовано сокращение expr.

Добавить

Примечания пользователей 12 notes

up
55
Magnus Deininger, dma05 at web dot de
16 years ago
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):<?phpfor ($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.
up
47
yasuo_ohgaki at hotmail dot com
24 years ago
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.
up
20
chriswarbo at gmail dot com
12 years ago
Note that there is a difference between a function and a function call, and bothare expressions. PHP has two kinds of function, "named functions" and "anonymousfunctions". Here's an example with both:<?php// A named function. Its name is "double".function double($x) {  return 2 * $x;}// An anonymous function. It has no name, in the same way that the string// "hello" has no name. Since it is an expression, we can give it a temporary// name by assigning it to the variable $triple.$triple = function($x) {  return 3 * $x;};?>We can "call" (or "run") both kinds of function. A "function call" is anexpression with the value of whatever the function returns. For example:<?php// The easiest way to run a function is to put () after its name, containing its// arguments (if any)$my_numbers = array(double(5), $triple(5));?>$my_numbers is now an array containing 10 and 15, which are the return values ofdouble and $triple when applied to the number 5.Importantly, if we *don't* call a function, ie. we don't put () after its name,then we still get expressions. For example:<?php$my_functions = array('double', $triple);?>$my_functions is now an array containing these two functions. Notice that namedfunctions are more awkward than anonymous functions. PHP treats them differentlybecause it didn't use to have anonymous functions, and the way named functionswere implemented didn't work for anonymous functions when they were eventuallyadded.This means that instead of using a named function literally, like we can withanonymous functions, we have to use a string containing its name instead. PHPmakes sure that these strings will be treated as functions when it'sappropriate. For example:<?php$temp      = 'double';$my_number = $temp(5);?>$my_number will be 10, since PHP has spotted that we're treating a string as ifit were a function, so it has looked up that named function for us.Unfortunately PHP's parser is very quirky; rather than looking for genericpatterns like "x(y)" and seeing if "x" is a function, it has lots ofspecial-cases like "$x(y)". This makes code like "'double'(5)" invalid, so wehave to do tricks like using temporary variables. There is another way aroundthis restriction though, and that is to pass our functions to the"call_user_func" or "call_user_func_array" functions when we want to call them.For example:<?php$my_numbers = array(call_user_func('double', 5), call_user_func($triple, 5));?>$my_numbers contains 10 and 15 because "call_user_func" called our functions forus. This is possible because the string 'double' and the anonymous function$triple are expressions. Note that we can even use this technique to call ananonymous function without ever giving it a name:<?php$my_number = call_user_func(function($x) { return 4 * $x; }, 5);?>$my_number is now 20, since "call_user_func" called the anonymous function,which quadruples its argument, with the value 5.Passing functions around as expressions like this is very useful whenever weneed to use a 'callback'. Great examples of this are array_map and array_reduce.
up
19
Mattias at mail dot ee
23 years ago
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 expressionwill be true anyway.2. if (func1() && func2())Now, if func1() returns false, func2() isn't run, since the expressionwill be false anyway.The reason for this behaviour comes probably from the programminglanguage C, on which PHP seems to be based on. There theshort-circuiting can be a very useful tool. For example:int * myarray = a_func_to_set_myarray(); // init the arrayif (myarray != NULL && myarray[0] != 4321) // check    myarray[0] = 1234;Now, the pointer myarray is checked for being not null, then thecontents of the array is validated. This is important, because ifyou try to access an array whose address is invalid, the programwill crash and die a horrible death. But thanks to the shortcircuiting, if myarray == NULL then myarray[0] won't be accessed,and the program will work fine.
up
13
egonfreeman at gmail dot com
18 years ago
It is worthy to mention that:$n = 3;$n * --$nWILL 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)
up
15
winks716
17 years ago
reply to egonfreeman at gmail dot com04-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~ :)
up
9
petruzanauticoyahoo?com!ar
17 years ago
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.
up
7
oliver at hankeln-online dot de
23 years ago
The short-circuiting IS a feature. It is also available in C, so I suppose the developers won?t remove it in future PHP versions.It is rather nice to write:$file=fopen("foo","r") or die("Error!");Greets,Oliver
up
6
denzoo at gmail dot com
17 years ago
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().
up
6
shawnster
18 years ago
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.
up
2
Bichis Paul
8 years ago
Regarding 12345alex at gmx dot net's example:I think you miss the identical equal documentation line from: http://php.net/manual/en/language.operators.comparison.php $a == $b     Equal     TRUE if $a is equal to $b after type juggling.$a === $b     Identical     TRUE if $a is equal to $b, and they are of the same type. Try: print array() === NULL ? "True" : "False";Check this:var_dump(is_null(array()));
up
2
antickon at gmail dot com
13 years ago
evaluation order of subexpressions is not strictly defined for all operators<?phpfunction 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
To Top