Это первая часть нашей минисерии статей «Чего ждать от PHP7». Читать часть 2

Как многие из вас, вероятно, знают, было принято 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)(), а также добавляет возможность вызывать цепочки статических методов:

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 в объекте.

Или, чтобы быть более кратким, если мы принимаем это утверждение:

$obj->$properties['name']

То в PHP5.6, оно будет интерпретировано как:

$obj->{$properties['name']}

А в PHP 7:

{$obj->$properties}['name']

Хотя и использование переменных-переменных, как правило, является пограничным случаем, и весьма неодобряемый сообществом, переменные-параметры — гораздо большая редкость в моей практике. Однако, вы можете легко обойтись без проблем с миграцией, если будете использовать фигурные скобки (как в примерах выше) для обеспечение аналогичного поведения между PHP5.6 и PHP7.

Производительность


Самой большой причиной для перехода на PHP7 является его производительность, которая своими характеристиками в первую очередь обязана phpng. Увеличение производительности может стать реша��щим фактором для быстрого перехода на 7ю версию маленькими хостерами, ведь им удастся разместить больше клиентов на том же оборудовании.

На текущий момент дела обстоят следующим образом: PHP7 находится на одном уровне с HHVM, написанным фейсбуком, который работает в качестве Just In Time (JIT) компилятора, переводящего PHP-код в машинные инструкции.

PHP7 не имеет JIT-компилятора, хотя было много дискуссий о нем. Непонятно какой прирост производительности даст этот шаг, но уверен, будет интересно посмотреть, если кто-то все же решится его сделать!

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

Изменения, ломающие обратную совместимость


Конечно же, core-разработчики очень старались не сломать обратную совместимость с предыдущими версиями, но, к сожалению, это не всегда возможно сделать при движении языка вперед, обязательно будут те, кто недоволен.

Однако, также как и изменение поведения в связи с вводом Uniform Variable Syntax, большая часть нововведений являются незначительными, например, отлавливаемые фатальные ошибки при вызове метода у не-объекта:

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”>` и их закрывающие теги %>, .

Другие, гораздо более серьезные изменения, находятся в RFC об удалении ВСЕЙ устаревшей (deprecated) функциональности.

Особо стоит отметить исключение из стандартной поставки расширения posix-совместимых регулярных выражений ext/ereg (не рекомендовано к использованию в 5.3) и старого ext/mysql расширения (заменено на новое в 5.5).

Одним из других минорных изменений является запрет на использование множественного default в операторе switch. PHP до версии 7 разрешал делать так:

switch ($expr) {
    default:
         echo "Hello World";
         break;
    default:
         echo "Goodbye Moon!";
         break;
}

Это приведет к выполнению только последнего. PHP7 же выдаст ошибку:

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). Пример:

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, а не в том файле, где была определена вызываемая функция.

Если типы не совпадут, это приведет к выбросу отлавливаемой фатальной ошибки:

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, двоеточие с аргументом-суффиксом перед скобкой:

function isValidStatusCode(int $statusCode): bool {
    return isset($this->statuses[$statusCode]);
}

В данном примере : bool указывает на то, что функция вернет булево значение.

Те же правила, которые применяются к type-hint, работают и здесь в случае объявления строгого режима.

Комбинированный оператор сравнения


Моим любимым дополнением в PHP7 является добавление комбинированного оператора сравнения, <=>, также известного как Spaceship-оператор. Я могу казаться пристрастным, но он действительно крут, и хорошо сочетается с операторами > и <.

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

Наиболее распространенное его использование заключается в callback'ах сортировок:

// 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.

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

P.S. А пока вы ждете, почему бы не поделиться своими мыслями по поводу того, что будет самым ожидаемым в PHP7? Или может быть есть вещи, которые не хотелось бы видеть в языке?