Как многие из вас, вероятно, знают, было принято RFC о согласовании названия следующей основной версии PHP, которая будет называться PHP7. Вы можете почитать об этом в моем
PHP5 timeline.
Независимо от ваших чувств по поводу этой темы, PHP7 — это свершившийся факт, и он придет в этом году! RFC с
таймлайном выпуска PHP7.0 прошло практически единогласно (32 к 2), сейчас разработчики подошли к стадии заморозки фич, а первый релиз-кандидат (RC) мы увидим уже в середине июня.
Но что все это значит для нас, обычных разработчиков? Сейчас мы видим огромное нежелание веб-хостеров двигаться в направлении новых версий 5.x. Не приведет ли крупное обновление, ломающее обратную совместимость, к еще более медленному движению?
Ответ: посмотрим. Продолжайте читать и узнаете подробности.
Большая часть проблем с некорректным поведением в нестандартных ситуациях была исправлена. Кроме того, производительность и устранение несоответствия — основные направления для этой версии.
Давайте углубимся в детали.
Исправления несоответствий
К сожалению, тикеты про
needle/haystack так и не были решены. Тем не менее, прошли два очень важных RFC. Так что не стоит терять надежды на приход столь необходимой последовательности и ожидаемого синтаксиса.
Крупнейшим (и самым незаметным) стало добавление
абстрактного синтаксического дерева (Abstract Syntax Tree — AST), являющегося промежуточным представлением кода во время компиляции. С AST core-разработчики смогут лучше обрабатывать пограничные случаи, устранять несоответствия в поведении, а также проложить путь для удивительных вещей в будущем, например, можно будет создавать еще более производительные акселераторы.
Также был введен
единый синтаксис переменных, который может причинить много проблем с миграцией на PHP7. Он решает многочисленные несоответствия в вычислении выражений. Например, возможность вызывать анонимные функции, привязанные к параметрам через
($object->closureProperty)(), а также добавляет возможность вызывать цепочки статических методов:
PHP Code:
class foo { static $bar = 'baz'; }
class baz { static $bat = 'Hello World'; }
baz::$bat = function () { echo "Hello World"; };
$foo = 'foo';
($foo::$bar::$bat)();
Однако, кое-что все же поменялось. В частности, семантика использования переменных переменных/свойств.
До PHP7,
$obj->$properties['name'] было доступом к свойству, имя которого входило в значение, хранящегося по ключу name массива
$properties. Теперь же, доступ будет осуществляться к значению по ключу name массива, который, в свою очередь, определяется значением параметра $properties в объекте.
Или, чтобы быть более кратким, если мы принимаем это утверждение:
PHP Code:
$obj->$properties['name']
То в PHP5.6, оно будет интерпретировано как:
PHP Code:
$obj->{$properties['name']}
А в PHP 7:
PHP Code:
{$obj->$properties}['name']
Хотя и использование переменных-переменных, как правило, является пограничным случаем, и весьма неодобряемый сообществом, переменные-параметры — гораздо большая редкость в моей практике. Однако, вы можете легко обойтись без проблем с миграцией, если будете использовать фигурные скобки (как в примерах выше) для обеспечение аналогичного поведения между PHP5.6 и PHP7.
Производительность
Самой большой причиной для перехода на PHP7 является его производительность, которая своими характеристиками в первую очередь обязана
phpng. Увеличение производительности может стать решающим фактором для быстрого перехода на 7ю версию маленькими хостерами, ведь им удастся разместить больше клиентов на том же оборудовании.
На текущий момент дела обстоят следующим образом: PHP7 находится на одном уровне с HHVM, написанным фейсбуком, который работает в качестве Just In Time (JIT) компилятора, переводящего PHP-код в машинные инструкции.
PHP7 не имеет JIT-компилятора, хотя было много дискуссий о нем. Непонятно какой прирост производительности даст этот шаг, но уверен, будет интересно посмотреть, если кто-то все же решится его сделать!
В дополнение к производительности, приятным побочным эффектом оптимизации внутренней структуры данных будет и значительная экономия памяти.
Изменения, ломающие обратную совместимость
Конечно же, core-разработчики очень старались не сломать обратную совместимость с предыдущими версиями, но, к сожалению, это не всегда возможно сделать при движении языка вперед,
обязательно будут те, кто недоволен.
Однако, также как и изменение поведения в связи с вводом Uniform Variable Syntax, большая часть нововведений являются незначительными, например,
отлавливаемые фатальные ошибки при вызове метода у не-объекта:
PHP Code:
set_error_handler(function($code, $message) {
var_dump($code, $message);
});
$var = null;
$var->method();
echo $e->getMessage(); // Fatal Error: Call to a member function method() on null
echo "Hello World"; // Still runs
Кроме того, APS и теги
script были удалены, вы больше не сможете использовать
<% и
<%=, или
`<script language="php”>` и их закрывающие теги
%>,
</script>.
Другие, гораздо более серьезные изменения, находятся в RFC об
удалении ВСЕЙ устаревшей (deprecated) функциональности.
Особо стоит отметить исключение из стандартной поставки расширения posix-совместимых регулярных выражений ext/ereg (не рекомендовано к использованию в 5.3) и старого ext/mysql расширения (заменено на новое в 5.5).
Одним из других минорных изменений является запрет на использование множественного
default в операторе
switch. PHP до версии 7 разрешал делать так:
PHP Code:
switch ($expr) {
default:
echo "Hello World";
break;
default:
echo "Goodbye Moon!";
break;
}
Это приведет к выполнению только последнего. PHP7 же выдаст ошибку:
Code:
Fatal error: Switch statements may only contain one default clause
Новые Возможности
Конечно же, мы справимся с последствиями изменений, ломающими обратную совместимость. Мы ценим производительность. Но еще больше мы наслаждаемся новыми возможностями! Новый функционал — вот что делает каждый релиз удовольствием, и PHP7 не исключение.
Скалярный type-hint и возвращаемые значения
Я собираюсь начать с наиболее спорного момента, который был добавлен в PHP7:
Scalar Type Hints. RFC на добавлении этой функции почти прошло голосование, но на автора настолько повлияли споры об этом, что он решил покинуть PHP-разработку, а также снял RFC с голосования. За этим последовало еще несколько, с конкурирующими реализациями. Было много общественных волнений, которые в конечном счете закончились (положительно) и оригинальная версия RFC была принята.
Для вас, конечных пользователей, это означает, что вы можете использовать type-hint со скалярными значениями. А именно: int, float, string и bool. По умолчанию функция работает в нестрогом режиме, а значит они будут просто приводить исходный тип в значение, указанное в подсказке типа. Например, если вы передали в функцию
int(1), которая требует нецелочисленное число, то оно будет приводиться к
float(1.0). И наоборот: передавая в функцию, требующую целого числа,
float(1.5), то будет приходить значение
int(1). Пример:
PHP Code:
function sendHttpStatus(int $statusCode, string $message) {
header('HTTP/1.0 ' .$statusCode. ' ' .$message);
}
sendHttpStatus(404, "File Not Found"); // integer and string passed
sendHttpStatus("403", "OK"); // string "403" coerced to int(403)
Вы можете включить режим строгой типизации
declare(strict_types=1); в верхней части файла и он гарантирует вам, что любой вызов функций, сделанный в этом файле, будет строго придерживаться определенного типа. Это произойдет именно в том файле, где вызван
declare, а не в том файле, где была определена вызываемая функция.
Если типы не совпадут, это приведет к выбросу отлавливаемой фатальной ошибки:
PHP Code:
declare(strict_types=1); // должно быть на первой строчке
sendHttpStatus(404, "File Not Found"); // integer и string переданы
sendHttpStatus("403", "OK");
// Catchable fatal error: Argument 1 passed to sendHttpStatus() must be of the type integer, string given
PHP7 также поддерживает
тип возвращаемого значения, который может принимать все те же типы в качестве аргументов. Синтаксис будет как и в
hack, двоеточие с аргументом-суффиксом перед скобкой:
PHP Code:
function isValidStatusCode(int $statusCode): bool {
return isset($this->statuses[$statusCode]);
}
В данном примере
: bool указывает на то, что функция вернет булево значение.
Те же правила, которые применяются к type-hint, работают и здесь в случае объявления строгого режима.
Комбинированный оператор сравнения
Моим любимым дополнением в PHP7 является добавление
комбинированного оператора сравнения, <=>, также известного как Spaceship-оператор. Я могу казаться пристрастным, но он действительно крут, и хорошо сочетается с операторами > и <.
Эффективно работает как
strcmp() или же
version_compare(), возвращая -1, если левый операнд меньше правого, 0 — если они равны, и 1, если левый больше правого. Основным его отличием от функций является то, что его можно использовать на любых двух операндах, а не только на примитивах.
Наиболее распространенное его использование заключается в callback'ах сортировок:
PHP Code:
// Pre Spacefaring^W PHP 7
function order_func($a, $b) {
return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
}
// Post PHP 7
function order_func($a, $b) {
return $a <=> $b;
}
Мы проанализировали некоторые из наиболее важных исправлений несоответствий поведения и посмотрели на две новые возможности PHP7.