Это вторая часть нашей минисерии статей «Чего ждать от PHP7». Читать часть 1
Как вы наверное уже знаете, PHP7 придет в этом году! И сейчас самое время узнать что же нового он нам принесет.
В первой части данной серии мы рассмотрели некоторые наиболее важные изменения в PHP7 и две крупные новые возможности. В этой статье рассмотрим еще шесть, о которых вы точно захотите узнать.
Новый экранирующий символ для Unicode
Добавление нового escape-символа
\u позволяет нам указывать специфические unicode символы внутри PHP-строк (да-да, те самые emoji и не только).Синтаксис выглядит так —
\u{CODEPOINT}, например, зеленое сердце,
, может быть выражено как PHP-строка: "\u{1F49A}".Оператор объединения со значением NULL (Null Coalesce Operator)
Еще один новый оператор —
??. Он возвращает левый операнд, если он не имеет значение NULL; в противном случае возвращается правый операнд.Самое главное, что не генерирует
notice, если левый операнд является несуществующей переменной. В отличии от короткого тернарного оператора ?:, он работает как isset().Вы также можете использовать цепочки операторов, чтобы вернуть первый ненулевой из данного набора:
$config = $config ?? $this->config ?? static::$defaultConfig;
Привязка замыканий во время вызова
С PHP5.4 к нам пришли нововведения
Closure->bindTo() и Closure::bind(), которые позволяют изменить привязку $this и области вызова, вместе, или по отдельности, создавая дубликат замыкания.PHP7 теперь добавляет легкий способ сделать это прямо во время вызова, связывая
$this и область вызова с помощью Closure->call(). Этот метод принимает объект в качестве своего первого аргумента, а затем любые другие аргументы, которые пойдут в замыкание:class HelloWorld {
private $greeting = "Hello";
}
$closure = function($whom) { echo $this->greeting . ' ' . $whom; }
$obj = new HelloWorld();
$closure->call($obj, 'World'); // Hello World
Группировка деклараций use
Если вам когда-либо приходилось импортировать много классов из одного и того же пространства имен, вы, наверное, были очень счастливы, когда IDE делала всю основную работу за вас. Для всех остальных, и для краткости, в PHP7 теперь есть возможность группировать декларирование операторов
use. Это позволит быстрее и удобнее работать с большим количеством импортов и сделает код читаемее:// Original
use Framework\Component\SubComponent\ClassA;
use Framework\Component\SubComponent\ClassB as ClassC;
use Framework\Component\OtherComponent\ClassD;
// With Group Use
use Framework\Component\{
SubComponent\ClassA,
SubComponent\ClassB as ClassC,
OtherComponent\ClassD
};
Группировка может использоваться с константами и импортируемыми функциями, вы можете смешивать все вместе:
use Framework\Component\{
SubComponent\ClassA,
function OtherComponent\someFunction,
const OtherComponent\SOME_CONSTANT
};
Улучшение генераторов
return в генераторах
В генераторах появились две очень интересные возможности. Первая — Generator Return Expressions, позволяющая возвращать значение после (успешного) завершения работы генератора.
До PHP7, если вы пытались что-нибудь вернуть в генераторе, это приводило к ошибке. Однако, теперь вы можете вызвать
$generator->getReturn(), чтобы получить возвращаемое значение.Если генератор еще не завершился или выбросил непойманное исключение, вызов
$generator->getReturn() сгенерирует исключение.Если же генератор завершен, но не объявлен
return, то метод вернет NULL.Пример:
function gen() {
yield "Hello";
yield " ";
yield "World!";
return "Goodbye Moon!";
}
$gen = gen();
foreach ($gen as $value) {
echo $value;
}
// Outputs "Hello" on iteration 1, " " on iterator 2, and "World!" on iteration 3
echo $gen->getReturn(); // Goodbye Moon!
Делегирование генератора
Вторая особенность является гораздо более захватывающей: делегирование генератора. Это позволяет вернуть другую итерабельную структуру — будь то массив, итератор или другой генератор.
Важно понимать, что итерации суб-структур осуществляются именно через самую внешнюю петлю, как если бы это была одна плоская структура, а не рекурсивный вызов.
Это утверждение также справедливо при отправке данных в генератор или выбросе исключений. Они передаются в суб-структуру, как если бы это был ее непосредственный вызов.
Синтаксис такой —
yield from <expression>. Посмотрим на примере:function hello() {
yield "Hello";
yield " ";
yield "World!";
yield from goodbye();
}
function goodbye() {
yield "Goodbye";
yield " ";
yield "Moon!";
}
$gen = hello();
foreach ($gen as $value) {
echo $value;
}
При каждой итерации будет выводиться:
- «Hello»
- " "
- «World!»
- «Goodbye»
- " "
- «Moon!»
Стоит упомянуть еще один нюанс: поскольку суб-структуры привносят свои собственные ключи, вполне возможно, что один и тот же ключ будет возвращен за несколько итераций. Недопущение подобного — это ваша ответственность, конечно же, если для вас это важно.
\EngineException
Обработка фатальный и catchable фатальных ошибок в PHP традиционна была невозможна, или по крайней мере очень сложна. Но с добавлением Engine исключений, многие из этих ошибок будут теперь выбрасывать исключение вместо самой ошибки.
Теперь, когда фатальная или catchable фатальная неустранимая ошибка возник��ут, выбросится исключение, позволяющее обработать ошибку корректно. Если его не трогать, то это приведет к традиционной фатальной ошибке необработанного исключения.
Эти исключения являются
\EngineException объектами, и в отличии от всех пользовательских исключений, они не наследуются от базового класса \Exception. Это сделано специально, чтобы существующий код, который ловит класс \Exception не отлавливал и фатальные ошибки, изменяя свое поведение. Таким образом сохраняется обратная совместимость.В будущем, если вы хотите поймать как традиционные исключения, так и engine исключения, вам нужно будет отлавливать их новый общий родительский класс
\BaseException.Кроме того, ошибки парсинга в выполняемом функцией
eval() коде теперь будут выбрасывать \ParseException, а несоответствие типов приведет к \TypeException.Пример:
try {
nonExistentFunction();
} catch (\EngineException $e) {
var_dump($e);
}
object(EngineException)#1 (7) {
["message":protected]=>
string(32) "Call to undefined function nonExistantFunction()"
["string":"BaseException":private]=>
string(0) ""
["code":protected]=>
int(1)
["file":protected]=>
string(17) "engine-exceptions.php"
["line":protected]=>
int(1)
["trace":"BaseException":private]=>
array(0) {
}
["previous":"BaseException":private]=>
NULL
}
Скоро!
РНР 7.0.0 исполнилось всего восемь месяцев, и, вполне возможно, это будет самым быстрым релизом мажорной версии в истории PHP. Пока все еще в альфа-версии, но уже сейчас все складывается очень хорошо.
И вы можете помочь сделать еще лучше.
Проверь свой код
Возьмите PHP7 vagrant box от Расмуса и запустите ваши тесты или проверьте по своему чек-листу ваше приложение. Сообщите о багах в проект, повторяйте регулярно :)
Помоги GoPHP7-ext
Одним из основных препятствий для PHP7 является большое количество работы по обновлению всех расширений для работы с новым Zend Engine 3.
Если вы используете расширение, которое не слишком популярно и известно, и вам не нравится уровень его поддержки, или же у вас есть свои собственные расширения — посмотрите на проект GoPHP7-ext и примите участие, перенеся свои расширения на новый движок.
Документация
Каждая новая фича PHP7 имеет свой RFC. Все они могут быть найдены в вики PHP.net и являются хорошей отправной точкой для написания новой документации. Вы можете сделать это онлайн в GUI среде, в том числе и закоммитить (если у вас есть карма) или отправить патч на проверку.
Заключение
РНР 7 будет великим!
Протестируйте ваши приложения. Помогите перенести расширения.
P.S. вы уже пробовали PHP7? Как вы относитесь к нововведениям? Есть ли что-то, с чем не согласны? Когда вы планируете перейти на новую версию? Напишите свои мысли по этому поводу в комментариях.
