PHP

Конструкции echo и print выполняют одинаковую функцию - вывод строковой информации. В исходниках и книгах можно встретить как повсеместное использование print-а, так и echo. В чем же их отличие и чему лучше отдать предпочтение?

Обратимся к документации.

int print ( string $arg )
print() is not actually a real function (it is a language construct) so you are not required to use parentheses with its argument list.
void echo ( string $arg1 [, string $... ] )
echo() is not actually a function (it is a language construct), so you are not required to use parentheses with it. echo() (unlike some other language constructs) does not behave like a function, so it cannot always be used in the context of a function. Additionally, if you want to pass more than one parameter to echo(), the parameters must not be enclosed within parentheses.

Функции или нет?

И print и echo - это не функции как таковые, а языковые конструкции. Поэтому аргументы заключать в скобки не обязательно.

Однако работа print-a аналогична работе функций, а работа echo - нет. Таким образом, print, в отличии от echo, можно использовать в контексте использования функций. Например, в тернарном операторе:

  1. <?php
  2. $value ? print 'Yes' : print 'No';
  3. ?>

Использование в вышеприведенном примере вместо "print" конструкции "echo" приведет к ошибке, хотя никто не запрещает использоваться такую запись:
  1. <?php
  2. echo $value ? 'Yes' : 'No';
  3. ?>

Переписанный вариант для echo призван проиллюстрировать, что трудно найти ситуацию, где использование print-a было бы единственным возможным вариантом.

Возвращаемые значения.

Различаются print и echo и по возвращаемым значениям. Print возвращает единицу, причем всегда и именно единицу (int=1), а не булево true. Echo же не возвращает вообще ничего (не путать с return NULL;).

Аргументы.

Print может принимать только один аргумент, а echo - произвольное количество (при передачи более чем одного аргумента, разделенных запятыми, заключать аргументы в скобки запрещается).

Скорость.

Различие в скорости echo и print - минимально, и им можно пренебречь, особенно в силу последних тенденций к построению архитектуры программного обеспечения (MVC), где на странице часто присутствует или всего один вывод, или их ограниченное количество (по одному на каждый логический блок), реже больше.

Сравнение скоростей echo и print по результатам тестов на сайте phpbench.com:
сравнение скорости работы print и echo
Хотя о том, почему print работает медленнее echo и почему в разных ситуациях выигрыш в скоростях различный, стоит написать подробнее.

В самом простом варианте

  1. <?php
  2. print 'test';
  3. echo 'test';
  4. ?>

echo будет работать быстрее только за счет того, что не тратится время на возвращение значения (print-y всегда приходится возвращать '1'). Однако если нам необходимо вывести несколько строк, то здесь уже выигрыш будет более значительный, т. к. в случае с echo достаточно только перечислить через запятую аргументы:

  1. <?php
  2. echo 'string1', 'string2', ... , 'stringN';
  3. ?>

А при использовании print либо несколько раз вызывать функцию вывода:
  1. <?php
  2. print 'string1';
  3. print 'sting2';
  4. ...
  5. print 'sringN';
  6. ?>

Либо выполнять операцию конкатенации строк, чтобы получить один аргумент:
  1. <?php
  2. print 'string1'.'string2'. ... .'stringN';
  3. ?>

И в том и в другом случае - потери времени. Пусть и незначительные, но все-таки потери, которых при использовании echo просто нет.

Что популярней, print или echo?

Просмотрел пять лежащих под рукой учебников по php - везде используется для вывода исключительно echo.

Однако не лишним будет проверить соотношение популярности print и echo с помощью "Пульса Блогосферы" Яндекса:
упоминания в блогосфере конструкций print и echo по материалам сервиса Яндекса "Пульс Блогосферы"
и Google Trends:
Гугл Тренды: популярность использования print и echo.
Стоит признать, что графики мало отражают действительную картину (соотношение популярности использования print или echo для вывода), т. к. слово "print" может использоваться во многих контекстах (адресах, комментариях), в отличии от "echo".

Но все-таки картина достаточно ясна - "echo" однозначно популярней. Чтобы подтвердить этот факт, возьмем три популярных CMS, распространяемых по лицензии GNU GPL, и посмотрим, какая конструкция вывода в них преобладает.
Использование print или echo в популярных CMS Drupal, Joomla, WP.
Что и требовалось доказать - 2/3 используют echo. В случае с Drupal, использование print обусловлено скорее всего привычкой и нежеланием отходить от ранее принятых стандартов оформления кода, нежели какими-то весомыми аргументами. Хотя явного указания, что использовать надо именно print, я в официальной документации (стандарты оформления кода) не нашел. В обсуждениях, почему используется именно print, а не echo, все сходятся во мнении - It's simply a coding habit. Просто привычка и ничего более.

Что использовать?

Однозначного ответа дать нельзя. Но при прочих равных - echo явно выигрывает. Даже скорость набора выше, всего четыре удобно расположенных на клавиатуре буквы.

Единственной же реальной причиной использования print я вижу только написание кода под проект, где исторически используется именно "print", а не "echo", чтобы не выбиваться из стиля. Хотя признаюсь - программируя под тот же Drupal, я частенько использую все-таки "echo", т. к. мне так просто привычней.

На днях задался вопросом целесообразности хранение строковых данных в БД вместо файлов с точки зрения скорости поиска.

Хотя, конечно, вопрос правильней поставить так — чем быстрее осуществлять поиск в массиве строк, средствами языка программирования (в данном случае php) или средствами РСУБД (MySQL)? А сравнение «MySQL vs файлы» только для наглядности, ведь данные в базах тоже хранятся в файлах (а в чем же еще?) и используется все та же файловая система.

Решил провести небольшой тест. Сгенерировал 100к строк вида

MP0bWDXN1AxhI9yCZiGpKUZObSBOSrFv6vxTYkxPLUXjUmLJui
Z53PK4xcJgteCqAZ9p9w5LhTU15wBqFrlz6VtuX3Bg83xzSwOS
Tjt0seSoBkE6BPvyBPSoJjvHcS6VfLDYlXPD1ySsImp91Lxsrg

Каждая строка при генерации писалась одновременно в файл (*.txt) и в четыре таблицы — таблицу типа MyISAM, тип данных «text», таблицу MyISAM, тип данных «varchar(100)», таблицу InnoDB, тип данных «text» и таблицу InnoDB, тип данных «varchar(100)».

При генерации 100к строк из каждой тысячной строки из середины копировалось 10 символов, которые писались в отдельный файл. Таким образом получилось 100 подстрок, по которым и осуществляется поиск полной строки в файле и базе данных.

Суть теста заключается в следующем — берем первую подстроку, ищем ее вхождение в строках, сохраненных в файле и БД, потом берем вторую подстроку и так далее сто раз. При каждом поиске засекаем время, необходимое для нахождения строки по ее подстроке, потом вычисляем среднее и сравниваем.

Поиск при хранении строк в текстовом файле осуществлялся четырьмя способами:

1. При каждом поиске (которых всего, как говорилось выше, сто) происходит чтение файла в массив функцией file(), потом осуществляется проход по получившемуся массиву конструкцией foreach(), где ищется вхождение подстроки в строку строковой функцией strpos().

2. Аналогично, только для поиска подстроки вместо строковой функции используются регулярные выражения, функция preg_match().

Третий и четвертый способы повторяют первые два, за исключением того, что при подсчете времени, затраченного на каждый поиск, не учитывается время формирования массива из файла. т.е. считается только время, необходимое на поиск по уже находящемуся в оперативке массиву.

Поиск по каждой из четырех созданных таблиц осуществлялся восемью способами:

1. Открытие соединения с БД. Поиск подстроки с использованием в SQL запросе операции сравнения LIKE. Закрытие соединения.

2. Открытие соединения с БД. Поиск подстроки с использованием в SQL запросе операции сравнения REGEXP. Закрытие соединения.

Третий и четвертый способы аналогичны предыдущим двум, но в них не учитывается время, необходимое на открытие и закрытие соединения с БД. Точнее, соединение с БД не закрывается до тех пор, пока не будут выполнены все сто запросов.

И 5-8 способы повторяют 1-4, но только в настройках MySQL отключается кэширование запросов (по умолчанию кэширование осуществляется). При использовании кэширования, поиск фактически происходит не по базе данных, а по кэшу (запрос хэшируется и ищется в кэше, если совпадения найдены - результат запроса возвращается из кэша, а сам запрос не делается).

Ниже представлена таблица с полученными в ходе теста данными.

Хранение данных Способ поиска Учет времени на чтение файла или открытие/закрытие соединения с БД Среднее время поиска, с
Файл, *.txt Строковые функции, strpos() Да 0.252027
Файл, *.txt Регулярные выражения, preg_match() Да 0.334894
Файл, *.txt Строковые функции, strpos() Нет 0.129508
Файл, *.txt Регулярные выражения, preg_match() Нет 0.303539
БД, MyISAM, text, без кэширования запросов Операция сравнения like "%pattern%" Да 0.202112
БД, InnoDB, text, без кэширования запросов Операция сравнения like "%pattern%" Да 0.335769
 БД, MyISAM, varchar(100) , без кэширования запросов Операция сравнения like "%pattern%" Да 0.194496
БД, InnoDB, varchar(100), без кэширования запросов Операция сравнения like "%pattern%" Да 0.261031
БД, MyISAM, text, без кэширования запросов Операция сравнения regexp ".*pattern.*" Да 1.074974
БД, InnoDB, text, без кэширования запросов Операция сравнения regexp ".*pattern.*" Да 1.225922
БД, MyISAM, varchar(100), без кэширования запросов Операция сравнения regexp ".*pattern.*" Да 1.070542
БД, InnoDB, varchar(100), без кэширования запросов Операция сравнения regexp ".*pattern.*" Да 1.143679
БД, MyISAM, text, без кэширования запросов Операция сравнения like "%pattern%" Нет 0.190953
БД, InnoDB, text, без кэширования запросов Операция сравнения like "%pattern%" Нет 0.333155
БД, MyISAM, varchar(100), без кэширования запросов Операция сравнения like "%pattern%" Нет 0.189853
БД, InnoDB, varchar(100), без кэширования запросов Операция сравнения like "%pattern%" Нет 0.262696
БД, MyISAM, text, без кэширования запросов Операция сравнения regexp ".*pattern.*" Нет 1.070554
БД, InnoDB, text, без кэширования запросов Операция сравнения regexp ".*pattern.*" Нет 1.231657
БД, MyISAM, varchar(100), без кэширования запросов Операция сравнения regexp ".*pattern.*" Нет 1.063102
БД, InnoDB, varchar(100), без кэширования запросов Операция сравнения regexp ".*pattern.*" Нет 1.139206
БД, MyISAM, text, кэширование запросов Операция сравнения like "%pattern%" Да 0.000332
БД, InnoDB, text, кэширование запросов Операция сравнения like "%pattern%" Да 0.000357
 БД, MyISAM, varchar(100) , кэширование запросов Операция сравнения like "%pattern%" Да 0.000294
БД, InnoDB, varchar(100), кэширование запросов Операция сравнения like "%pattern%" Да 0.000377
БД, MyISAM, text, кэширование запросов Операция сравнения regexp ".*pattern.*" Да 0.000332
БД, InnoDB, text, кэширование запросов Операция сравнения regexp ".*pattern.*" Да 0.000349
БД, MyISAM, varchar(100), кэширование запросов Операция сравнения regexp ".*pattern.*" Да 0.000335
БД, InnoDB, varchar(100), кэширование запросов Операция сравнения regexp ".*pattern.*" Да 0.000365
БД, MyISAM, text, кэширование запросов Операция сравнения like "%pattern%" Нет 0.000071
БД, InnoDB, text, кэширование запросов Операция сравнения like "%pattern%" Нет 0.000126
БД, MyISAM, varchar(100), кэширование запросов Операция сравнения like "%pattern%" Нет 0.000071
БД, InnoDB, varchar(100), кэширование запросов Операция сравнения like "%pattern%" Нет 0.000108
БД, MyISAM, text, кэширование запросов Операция сравнения regexp ".*pattern.*" Нет 0.000072
БД, InnoDB, text, кэширование запросов Операция сравнения regexp ".*pattern.*" Нет 0.000070
БД, MyISAM, varchar(100), кэширование запросов Операция сравнения regexp ".*pattern.*" Нет 0.000071
БД, InnoDB, varchar(100), кэширование запросов Операция сравнения regexp ".*pattern.*" Нет 0.000109

Исходя из полученных данных, можно сделать несколько выводов, банальных и не очень.

Открытие или закрытие какого-то ресурса (будь то файл или соединение с БД) — очень времязатратная процедура. Оформлять кусок кода в функцию, где что-то открывается, пишется, закрывается, и потом эту функцию вызывать несколько раз в разных местах программы или даже в цикле — неправильное решение с точки зрения производительности.

Строковые функции работают быстрее, чем регулярные выражения. Поэтому то, что можно сделать строковыми функциями, надо делать именно строковыми функциями, а не регулярками.

Скорость поиска строковых данных в таблицах типа MyISAM быстрее, чем в таблицах типа InnoDB. Поэтому если при выборе таблицы того или иного типа основным критерием является скорость чтения и не требуется каких-то специфичных свойств (механизм транзакций, работа с внешними ключами), то использовать следует MyISAM.

Скорость поиска по данным типа text и varchar при использовании таблиц типа MyISAM примерно сопоставима. При использовании же таблиц типа InnoDB, скорость поиска по данным text осуществляется медленнее, чем по данным типа varchar.

Поиск с использованием в SQL запросах операции сравнения «REGEXP» работает в разы медленнее, чем с использованием операции сравнения «LIKE». Что еще раз подтверждает тот факт, что регулярными выражениями надо пользоваться только при отсутствии альтернатив.

В MySQL очень мощная система кэширования (которая по умолчанию включена). Если вы делаете какой-то запрос более одного раза, то повторный поиск не происходит, а вам отдаются данные из кэша со скорость в десяти-стотысячные доли секунды.

Вывод из сравнения можно сделать такой: без учета времени на открытие файла/соединение с БД, поиск средствами php по данным, находящимся в оперативной памяти, осуществляется в среднем в два раза быстрее, чем средствами MySQL по данным, находящимся в БД. Однако MySQL имеет систему кэширования запросов, поэтому если требуется регулярно обращаться к одним и тем же данным и делать одинаковые выборки, то выигрыш в скорости при использовании баз данных становится весьма значительным.

Я сторонник красивого и оптимизированного кода, хоть и не всегда у меня получается следовать всем правилам «хорошего тона» в программировании.

Сейчас же речь пойдет о правильном использовании двойных и одинарных кавычек в php. Перед тем, как начать писать пост, я бегло просмотрел имеющиеся у меня книги по php, и, что странно, ни в одной не увидел правильного использования кавычек. Почему – для меня загадка. Обвинять авторов в дилетантстве нет ни малейшей возможности, книги далеко не для «чайников». Может быть просто не хотели акцентировать на этом внимание, дескать кому надо, тот сам разберется.

Кавычки, что логично, бывают одинарными и двойными. Различие их использования в php заключается в следующем. Строку, заключенную в одинарные кавычки, интерпретатор php выводит как есть, заключенную же в двойные кавычки парсит на наличие в ней переменных и, найдя таковые, подставляет их значения.

  1. <?php
  2. $var = 1;
  3. echo '$var'; //на экран выведется "$var"
  4. echo "$var"; /*на экран выведется цифра 1, т.к. вместо переменной подставляется ее значение*/
  5. ?>

Следовательно, если нам надо вывести текст «как есть», то используем одинарные кавычки. Если необходимо подставить вместо переменной ее значение – двойные (если переменная только одна, то кавычки можно и вовсе опустить). Часто можно встретить такой код:

  1. <?php
  2. echo "Какой-то текст";
  3. ?>

Выводится просто текст. Но в коде он по какой-то неведомой причине заключен в двойные кавычки, что заставляет интерпретатор парсить его на наличие переменных. Правильным будет заключить текст в одинарные кавычки.

Рассмотрим тривиальную задачу вывода переменной в составе текста, в том числе и с использованием html кода.

  1. <?php
  2. $date;
  3. echo "Сегодняшняя дата: <strong>$date</strong>";
  4. ?>

Все выводится хорошо, текст и выделенная жирным дата, которая подставляется вместо переменной. Но необходимо помнить две вещи. Первое, это особенность интерпретатора: конкатенация строк происходим намного быстрее и требует меньше ресурсов, нежели синтаксический анализ строк. И второе - не стоит забывать про парадигму программирования «разделяй и властвуй». Не надо мешать все в одно, гораздо правильнее будет разделить текст на две части – требующую и не требующую парсинга интерпретатором. Таким образом, пример выше стоит записать так:

  1. <?php
  2. $date;
  3. echo  'Сегодняшняя дата: <strong>'.$date.'</strong>';
  4. ?>

Естественно, следовать этому правилу (заключать все, что не требует парсинга, в одинарные кавычки) надо не только при выводе текста, но и при присвоении значений строковым переменным:

  1. <?php
  2. $svar = 'Значение переменной';
  3. ?>

Или, например, при использовании строк при передаче аргументов функции:

  1. <?php
  2. function sum_str($first_string, $second_string) {
  3.     return $first_string.' - '.$second_string;
  4. }
  5. $var = 'Параметр';
  6. echo sum_str($var, 'значение'); /*на экран выведется строчка "Параметр - значение"*/
  7. ?>

И хотя на современных компьютерах выигрыш во времени интерпретирования кода в зависимости от использования одинарных или двойных кавычек будет фактически незаметен, особенно в небольших скриптах, стоит все-таки изначально приучать себя писать грамотный код, это намного легче, чем потом переучиваться.

Приятно иногда покопаться в грамотно оформленных исходниках, однако часто стал замечать, что разобраться в самописном коде трудно уже на следующий день. Видимо сказывалось отсутствие единого стиля программирования, что приводило код к бессмысленному нагромождению из скобок, непонятных переменных, функций. Постепенно пришло осознание того, что все-таки стоит вогнать организацию кода в некие рамки, а не писать как попало. К сожалению, каких-либо подробных инструкций не попадалось, и я продолжал кодить в «свободном» стиле. И вот с неделю назад наткнулся в одной книге по php в разделе “Полезные советы” на достаточно хорошую статью. Изначально хотел перепечатать себе в блог, но потом нашел оригинал в интернете, поэтому просто скопипащу. Тем, кто еще не выработал свой стиль программирования, читать обязательно.

Расстановка фигурных скобок и отступы

Существует несколько стилей расстановки фигурных скобок, все они диктуются существующими стилями в других C-подобных языках программирования.

1) Рациональный стиль

Это один из наиболее распространенных стилей, так как им пользовались Керниген (Kernighan) и Ричи (Ritchie), авторы языка C.

  1. <?php
  2.   if($flag){
  3.     echo "Hello world!";
  4.   }
  5. ?>

Преимущество этого подхода заключается в экономии вертикального пространства, жизненно важного при отладке большого блока кода. Оборотной стороной такого подхода является то, что может оказаться трудным найти символ {, спрятанный в конце строки. Этого стиля придерживаются и Java-программисты, как-то приписывает Sun.

2) Стиль Алмена

Эрик Алемен (Eric Allman) написал утилиты BSD в этом стиле, поэтому этот стиль часто называют "стиль BSD":

  1. <?php
  2.   if($flag)
  3.   {
  4.     echo "Hello world!";
  5.   }
  6. ?>

Аргументом в поддержку такого стиля является тот факт, что область видимости блочного оператора ясна и визуально ассоциируется с управляющим оператором.

3) Стиль Whitesmith

Данный стиль предписывает использование следующей расстановки фигурных скобок

  1. <?php
  2.   if($flag)
  3.     {
  4.     echo "Hello world!";
  5.     }
  6. ?>

Этот стиль имеет преимущество в том, что скобки более тесно ассоциируются с кодом, который они включают и разграничивают, однако при визуальном просмотре текста отыскать скобки оказывается чуть более сложно.

4) Стиль GNU

Программисты GNU фонда Free Software Foundation используют следующий стиль расстановки фигурных скобок

  1. <?php
  2.   if($flag)
  3.     {
  4.       echo "Hello world!";
  5.     }
  6. ?>

Внутри любых управляющих конструкций операторы следует располагать с отступом на одинаковое число пробелов, например для операторов if-then-else код должен выглядеть следующим образом:

  1. <?php
  2.   $flag = true;
  3.   if($flag)
  4.   {
  5.     echo "Переменная равна true";
  6.     exit();
  7.   }
  8.   else
  9.   {
  10.     echo "Переменная равна false";
  11.     exit();
  12.   }
  13. ?>

Число может быть любым, обычно используют 2, 4 или 8 пробелов. Наиболее оптимальным является использование 2 пробелов, так как при их большем числе вложенные блоки становятся "растянутыми" и их становится сложно воспринимать.

Пробелы вокруг символов

Бинарные операторы следует обрамлять пробелами:

  1. <?php
  2.   // Неправильно
  3.   $a=$b+$c*$d;
  4.   // Правильно
  5.   $a = $b + $c * $d;
  6. ?>

Символ пробела ассоциируется с новым словом, поэтому формула читается не как непонятный набор символов, а как нечто осмысленное.

Комментарии

Расставляйте комментарии по принципу “чем больше, тем лучше” — пройдёт некоторое время и вы забудете, что делал тот или иной программный блок.

PHP собрал в себе практически все комментарии современных языков программирования, наряду с однострочными комментариями в стиле shell-скриптов (#)

  1. <?php
  2.   # Программный модуль index.php
  3.   echo "Hello world!";
  4. ?>

и С++ (//)

  1. <?php
  2.   // Программный модуль index.php
  3.   echo "Hello world!";
  4. ?>

можно использовать многострочный комментарий в стиле C:

  1. <?php
  2.   /* Это многострочный комментарий в стиле С
  3.      он охватывает несколько строк – не допускается
  4.      вложенных комментариев
  5.   */
  6.   echo "Hello world!";
  7. ?>

К хорошему тону относится использование однострочных комментариев для короткого комментария, а многострочного — для комментария, охватывающего несколько строк. Не возбраняется использовать однострочные комментарии для большого текста, особенно в начале файла или важного блока кода

  1. <?php
  2.   //////////////////////////////////////////////////////
  3.   // Гостевая книга
  4.   //////////////////////////////////////////////////////
  5. ?>

Как и при работе с отступами и фигурными скобками, основным требованием является необходимость придерживаться одного стиля во всех программных блоках.
При расстановке однострочных комментариев возможно два варианта: непосредственно перед выполняемым оператором

  1. <?php
  2.   // Вывод текстовой строки в окно браузера
  3.   echo "Hello world!";  
  4. ?>

и после точки с запятой

  1. <?php
  2.     echo "Hello world!"; // Вывод текстовой строки в окно браузера
  3. ?>

Лучше придерживаться первого правила, так как строка получается длинной и плохо воспринимается читающим. Единственным оправданием использования такого комментария является комментирование закрывающейся скобки длинного программного блока, содержащего много вложенных блоков.

  1. <?php
  2.   if($tot)
  3.   {
  4.      while($position = next($tot))
  5.      {
  6.         /* Очень длинный код
  7.            содержащий много  
  8.            вложенных блоков
  9.            ...  
  10.         */
  11.         if($flag)
  12.         {
  13.           echo "Ошибка";
  14.           exit();
  15.         }
  16.      } // Конец while($position = next($tot))
  17.   }
  18. ?>

Имена переменных и функций

Существует несколько стилей названия переменных

$var_bell — стиль C: нижний регистр, знак подчёркивания.

$VarBell — стиль Pascal: каждая подстрока в названии начинается с большой буквы.

$varBell — стиль Java: первая строка начинается с маленькой буквы, все последующие с большой.

Не имеет значения, какой стиль будет вами выбран — главное придерживаться в коде одного стиля.

Замечание
В программировании константы традиционно записываются в верхнем регистре YANDEX_BOT. Если вы хотите, чтобы другие программисты могли легко воспринимать ваш код, придерживайтесь этого правила.

При названии переменных и функций старайтесь давать им осмысленные имена. Иногда ничего не приходит в голову, и появляется назвать переменную как попало — остерегайтесь этого.

(c) Симдянов И.В.