В данном тексе я лишь обращаю внимание на некоторые возможности языка PHP. Я не предлагаю их использовать, так как это в некоторых случаях существенно усложняет читабельность кода и приводит к сложностям при отладке. Однако описанные мной подходы в ряде случаев существенно позволяют сократить код.
Выражения — это краеугольный камень PHP. Почти все, что вы пишете в PHP, является выражением. Самое простое и точное определение выражения — «все что угодно, имеющее значение». (с сайта php.net)
UPD: Статья только о том, как МОЖНО делать в некоторых случаях, когда это оправданно. В большинстве случаях (и тем более повсеместно) описанную практику применять не стоит ни в коем случае, так как она сильно усложняет код. Цель статьи — расказать о возможностях языка, не более того.
Как правило 80-90% любого PHP-скрипта состоит из выражений:
Можно игнорировать присваивание значения выражения. Это все равно будет правильным кодом с точки зрения PHP:
Оператор присваивания в свою очередь может использоваться в выражениях многократно:
И вот какие выводы можно сделать из этого уже на первый взгляд:
Встретив в PHP-коде подобие последней строчки из данного примера, многие программисты впадут в ступор. Поэтому тут я остановлюсь поподробнее.
Дело в том, что выражения с логическими операторами вычисляются до получения однозначного значения. Этот момент может наступить раньше, нежели выражение будет целиком вычислено, например:
func1() никогда не будет вызван, так как при вычислении “true or” результатом уже однозначно будет true, не зависимо от того, что идет дальше. Аналогично с оператором and:
Замечу, что кроме операторов or и and существуют операторы || и &&. Разница между ними только в приоритете выполнения (or и and вычисляются позже). Для побитовых операторов | & и др. данное правило не действует, выражение вычисляется полностью.
Поэтому выражение:
Может быть трактовано как «выполнять до тех пор, пока какая-нибудь функция не вернет true», и аналогично с оператором and – false. Поэтому эту возможность можно использовать в качестве оператора if:
Аналогично:
Разница только в том, что пример ниже более компактен. Ну, и немного менее читабелен. Вот более реальный пример:
Всего одна строчка – выполнение соединения с БД, выбор БД, установка кодировки и вывод ошибки, если что-то пошло не так.
Это можно рассматривать и глубже, но тогда код становится абсолютно нечитаемым, и чтоб в нем разобраться другому разработчику потребуется серьезный мозговой штурм. Здесь (как и везде) действует правило «хорошо, но в меру».
Теперь о непосредственном практическом применении. Далее я приведу примеры со своими комментариями, т.к. в данном случае пример лучший учитель.
Как известно, наиболее часто используемыми циклами является for и while. В качестве аргументов они используют те же самые выражения. Например, вот такой код, характерный для новичков:
Вместо вот этого можно написать:
Не стоит забывать, что оператор цикла for имеет не строго заданную структуру for($i = 0; $i != $k; $i++) а принимает на вход максимум 3 выражения, первое вычисляется в момент старта, второе служит для проверки условия выполнения, и третье вычисляется в момент каждого прохода. Любое из этих выражений можно опустить (в прошлом примере третье выражение отсутствует). Тем самым, если наши «какие-то действия с массивом» не очень сложны, можно написать и так:
Кстати, у цикла for начальное и конечное выражение может состоять из многих выражений, которые перечисляются через запятую:
Другие случаи подобного синтаксиса в php мне не знакомы.
Интересные случаи использования оператора присваивания, при котором переменные, входящие в выражение изменяются в процессе его вычисления. Например, у нас есть некий файл, который может содержаться в одном из директориев DIR1 и DIR2 или отсутствовать. Требуется определить путь к этому файлу. Сходу можно написать вот такой код.
Но это можно написать и таким способом:
Выражение будет выполняться до тех пор, пока какой-то is_file не вернет true, причем именно в этом случае установится соответствующий $path. Кстати, к такому виду часто могут быть приведены большие конструкции if-elseif-elseif… и switch-case-case…
Ну, и наконец, как уже было сказано можно избавляться от небольших блоков if. Как это делается, я уже привел примеры, так что повторяться не буду.
Выражения — это краеугольный камень PHP. Почти все, что вы пишете в PHP, является выражением. Самое простое и точное определение выражения — «все что угодно, имеющее значение». (с сайта php.net)
UPD: Статья только о том, как МОЖНО делать в некоторых случаях, когда это оправданно. В большинстве случаях (и тем более повсеместно) описанную практику применять не стоит ни в коем случае, так как она сильно усложняет код. Цель статьи — расказать о возможностях языка, не более того.
Как правило 80-90% любого PHP-скрипта состоит из выражений:
$a = 2 + 1;
$a = isset($a) ? $a : false;
$a = func1($a) + func2($a);
$res = mysql_query($query);
Можно игнорировать присваивание значения выражения. Это все равно будет правильным кодом с точки зрения PHP:
2 + 1;
isset($a) ? $a : false;
func1($a) + func2($a);
mysql_query($query);
Оператор присваивания в свою очередь может использоваться в выражениях многократно:
$a = ($b = 2 + 1);
$a = isset($a) ? $b = $a : $b = false;
$a = ($b = func1($a)) + func2($a);
$a = mysql_query($query = ‘SELECT …’);
И вот какие выводы можно сделать из этого уже на первый взгляд:
// Если $a == true выполнится func1() в противном случае func2()
$a ? func1() : func2();
// func1() и func2() выполнятся в любом случае:
func1() + func2();
// func1() и func2() выполнятся случае если $a > 0
$a <= 0 or func1() + func2();
Встретив в PHP-коде подобие последней строчки из данного примера, многие программисты впадут в ступор. Поэтому тут я остановлюсь поподробнее.
Дело в том, что выражения с логическими операторами вычисляются до получения однозначного значения. Этот момент может наступить раньше, нежели выражение будет целиком вычислено, например:
$a = true or func1();
func1() никогда не будет вызван, так как при вычислении “true or” результатом уже однозначно будет true, не зависимо от того, что идет дальше. Аналогично с оператором and:
$a = false and func1();
Замечу, что кроме операторов or и and существуют операторы || и &&. Разница между ними только в приоритете выполнения (or и and вычисляются позже). Для побитовых операторов | & и др. данное правило не действует, выражение вычисляется полностью.
Поэтому выражение:
Func1() or func2() or func3();
Может быть трактовано как «выполнять до тех пор, пока какая-нибудь функция не вернет true», и аналогично с оператором and – false. Поэтому эту возможность можно использовать в качестве оператора if:
$res = mysql_connect(…);
if (!$res) die();
Аналогично:
$res = mysql_connect(…) or die();
Разница только в том, что пример ниже более компактен. Ну, и немного менее читабелен. Вот более реальный пример:
mysql_connect(…) and mysql_select_db (…) and mysql_query("SET NAMES utf8") or die(mysql_error());
Всего одна строчка – выполнение соединения с БД, выбор БД, установка кодировки и вывод ошибки, если что-то пошло не так.
Это можно рассматривать и глубже, но тогда код становится абсолютно нечитаемым, и чтоб в нем разобраться другому разработчику потребуется серьезный мозговой штурм. Здесь (как и везде) действует правило «хорошо, но в меру».
Теперь о непосредственном практическом применении. Далее я приведу примеры со своими комментариями, т.к. в данном случае пример лучший учитель.
Как известно, наиболее часто используемыми циклами является for и while. В качестве аргументов они используют те же самые выражения. Например, вот такой код, характерный для новичков:
$res = mysql_query(“SELECT …”);
If ($res) while ($v = mysql_fetch_assoc($res))
{
// тут какие-то действия с массивом.
}
Вместо вот этого можно написать:
for($res = mysql_query(“SELECT …”); $res&&($v = mysql_fetch_assoc($res));)
{
// тут какие-то действия с массивом.
}
Не стоит забывать, что оператор цикла for имеет не строго заданную структуру for($i = 0; $i != $k; $i++) а принимает на вход максимум 3 выражения, первое вычисляется в момент старта, второе служит для проверки условия выполнения, и третье вычисляется в момент каждого прохода. Любое из этих выражений можно опустить (в прошлом примере третье выражение отсутствует). Тем самым, если наши «какие-то действия с массивом» не очень сложны, можно написать и так:
for(
$res = mysql_query(“SELECT …”);
$res && ($v = mysql_fetch_assoc($res));
// тут какие-то действия с массивом, например
print_r($v)
);
Кстати, у цикла for начальное и конечное выражение может состоять из многих выражений, которые перечисляются через запятую:
for(
$res = mysql_query(“SELECT …”), $i = 0;
$res && ($v = mysql_fetch_assoc($res));
// тут какие-то действия с массивом, например
print_r($i++), print_r($v)
);
Другие случаи подобного синтаксиса в php мне не знакомы.
Интересные случаи использования оператора присваивания, при котором переменные, входящие в выражение изменяются в процессе его вычисления. Например, у нас есть некий файл, который может содержаться в одном из директориев DIR1 и DIR2 или отсутствовать. Требуется определить путь к этому файлу. Сходу можно написать вот такой код.
if (is_file(DIR1.$file)) $path = DIR1.$file;
elseif (is_file(DIR2.$file)) $path = DIR2.$file;
else $path = false;
Но это можно написать и таким способом:
is_file($path = DIR1.$file) || is_file($path = DIR2.$file) || $path = false;
Выражение будет выполняться до тех пор, пока какой-то is_file не вернет true, причем именно в этом случае установится соответствующий $path. Кстати, к такому виду часто могут быть приведены большие конструкции if-elseif-elseif… и switch-case-case…
Ну, и наконец, как уже было сказано можно избавляться от небольших блоков if. Как это делается, я уже привел примеры, так что повторяться не буду.