PHP 7: Что нового. часть 1
Категория: / DEV Блог
/ PHP (LAMP)
Релиз PHP 7 запланирован на конец ноября 2015 года.
В новой версии PHP появились интересные синтаксические плюшки, новые функции
а также самые долгожданные изменения коснулись ядра интерпретатора - проект phpng, увеличивает скорость
обработки скриптов практически вдвое по сравнению с PHP 5.x, плюс более эффективный менеджер памяти.
бенчмарк PHP7
Итак, что изменилось?
Объединенный оператор сравнения (spaceship operator - корабль) - шоткат для операция трехстороннего сравнения двух операндов.
Записывается в форме x = a <=> b. Возвращает одно из трех значений:
Оператор имеет одинаковый приоритет с операциями сравнения (`==`, `!=`, `===`, `!==`) и работает также как и операторы (`<`, `>=`, ...).
Также корабль не ассоциативен, то есть вы НЕ МОЖЕТЕ связать его с предыдущим вызовом (например `1 <=> 2 <=> 3`).
Объекты данным оператором сравнивать нельзя.
RFC: Combined Comparison Operator
Оператор является сокращенным вариантом вызова isset в тернарном операторе ?:.
Пример
Null Coalesce Operator
Теперь в объявлениях переменных можно указывать их тип, даже если они являются скалярными (числа и строки).
По умолчанию используется кастинг для приведения к заданному типу, если вы хотите имееть более жесткий контроль,
можно включить strict режим, тогда при присвоении переменной значения, тип которого отличается от объявленного,
будет выброшено исключение TypeError.
Типы:
Пример
Чтобы включить строгий strict режим проверки, нужно в начале (каждого) файла, добавить вызов
declare(strict_types=1);
Этот режим помимо обработки параметров влияет на возвращаемые значения!
В строгом режиме запрещен любой кастинг кроме конвертации int => float (но не наоборот)
Важно: Strict mode работает только по месту вызова функции, то есть если описание функции находится в файле с объявлением strict_types=1,
а вызывается она из другого файла без strict_types, то никакой строгой типизации не будет!
Необратимые изменения
Классы с именами `int`, `string`, `float`, and `bool` теперь запрещены.
Любое использование классов с этими названиями приведет к фатальным ошибкам.
Scalar Type Declarations
Добавлена возможность указать тип переменной, возвращаемой функцией или методом или замыканием.
Следующие типы поддерживаются:
При использовании наследования в классах, дочерние методы должны соблюдать объявления возвращаемых типов
указанные в родительском классе / интерфейсе
Объявление метода `D::test() : B` вызовет `E_COMPILE_ERROR` потому что многовариантность не дозволена.
Для того чтобы метод `D::test()` заработал, нужно указать что он возвращает нечто типа `A`.
В этот раз выполнение закончится эксепшном `TypeError`, потому что `null` не валидный возвратный тип, валидацию пройдет только экземпляр клааса `A`.
Return Type Declarations
Аноимные классы подходят для небольших задач. Из часто используют в языках например C# или Java для выполнения колбэков.
Анонимные классы позволяют делать тоже самое что и обычные классы: передавать данные в конструктор, наследовать другие классы, использовать трейты и т.п.
Анонимные классы поддерживают вложенность. Вложенные классы не будут иметь доступа к private/protected свойствам внешнего класса.
Если такое необходимо, то нужно передать эти данные через конструктор вложенного класса.
Anonymous Classes
Теперь в "строках" и объявлениях heredoc можно использовать \uXXXX последовательности для описания символов юникод
Unicode Codepoint Escape Syntax
Новый метод `call()` - шоткат для выполнения лямбды с прикрепленным объектом выполнения.
Closure::call
Новый функционал направлен на обеспечение безопасности сериализации объектов, предотвращает возможные code injection атаки,
давая возможность разработчику указать какие классы могут обрабатываться, а какие игнорироваться.
Filtered unserialize()
Новый класс IntlChar расширяет функциональность ICU (библиотека для локализации приложений International Components for Unicode)
Класс содержит статические методы и константы для работы с юникодом.
Для использования должно быть установлено расширение Intl.
Необратимые изменения
Классы в глобальном пространстве не могут называться IntlChar.
IntlChar class
Обратно совместимое расширение для классической функции `утверждения` (assert).
Если первый параметр функции равен false, то бросается исключение / выводится ошибка с AssertionError (второй параметр).
Assert позволяет отлаживать скрипты, при этом в продакш окружении вызовы будут игнорировать интерпритатором, т.е. ничего не стоить в плане ресурсов.
Добавлены две настройки PHP.ini, по-умолчанию:
Expectations
Если у импортируемых классов общее пространство имен, можно объединить их импорт в группу
(это относится к классам, функциям, константам, интерфейсам)
Group use Declarations
Позволяет использовать `return (expression)` в генераторах.
Значение может быть получено вызовом метода `Generator::getReturn()`, только по завершении работы генератора.
Возможность явно вернуть последнее значение - хорошая возможность, которая упрощает работу с генераторами.
Теперь не нужно проверять является ли значение последним. просто вызываем getReturn.
Generator Return Expressions
Построено на основе возможности возврата выражений из генератора.
Используется новый синтаксис:
<expr> будет вызываться до тех пор, пока возвращает данные, затем выполнения продолжится в вызывающем генераторе.
Это позволяет разбить сложный генератор на несколько маленьких - что способствует более чистому коду и его реюзабельности.
Generator Delegation
Функция intdiv() позволяет делить числа на выходе получая целые числа.
Необратимые изменения
Ключевое слово `intdiv` зарезервировано для глобального контекста.
[purl=https://wiki.php.net/rfc/intdivintdiv()[/purl]
Теперь возможно передавать параметры функции session_start().
Опции - стандартные настройки сессий из php.ini.
Добавился новая настройка для сессий `session.lazy_write`, по-умолчанию включена.
Introduce session_start() Options
Альтернатива preg_replace_callback, когда требуется обработать несколько условий в коллбеке.
Позволяет передать в качестве обратной функции - массив ['/regex'/ => callback, ...].
Необратимые изменения
Имя `preg_replace_callback_array` зарезервировано.
Add preg_replace_callback_array Function
PHP7 Что нового - продолжение
@Ссылки
Оригинал статьи
В новой версии PHP появились интересные синтаксические плюшки, новые функции
а также самые долгожданные изменения коснулись ядра интерпретатора - проект phpng, увеличивает скорость
обработки скриптов практически вдвое по сравнению с PHP 5.x, плюс более эффективный менеджер памяти.
бенчмарк PHP7
Итак, что изменилось?
Combined Comparison Operator
Объединенный оператор сравнения (spaceship operator - корабль) - шоткат для операция трехстороннего сравнения двух операндов.
Записывается в форме x = a <=> b. Возвращает одно из трех значений:
1 (если a > b)
0 (a = b)
-1 (a < b)
Оператор имеет одинаковый приоритет с операциями сравнения (`==`, `!=`, `===`, `!==`) и работает также как и операторы (`<`, `>=`, ...).
Также корабль не ассоциативен, то есть вы НЕ МОЖЕТЕ связать его с предыдущим вызовом (например `1 <=> 2 <=> 3`).
var_dump('PHP' <=> 'Node'); // int(1)
var_dump(123 <=> 456); // int(-1)
// сравниваются элементы массива по порядку
var_dump(['a', 'b'] <=> ['a', 'b']); // int(0)
Объекты данным оператором сравнивать нельзя.
RFC: Combined Comparison Operator
?? - Оператор объединения со значением NULL
Оператор является сокращенным вариантом вызова isset в тернарном операторе ?:.
Пример
// до PHP7
$route = isset($_GET['route']) ? $_GET['route'] : 'index';
// или
$route = @$_GET['route']) ?: 'index';
// PHP 7+
$route = $_GET['route'] ?? 'index';
Null Coalesce Operator
Скалярные типы
Теперь в объявлениях переменных можно указывать их тип, даже если они являются скалярными (числа и строки).
По умолчанию используется кастинг для приведения к заданному типу, если вы хотите имееть более жесткий контроль,
можно включить strict режим, тогда при присвоении переменной значения, тип которого отличается от объявленного,
будет выброшено исключение TypeError.
Типы:
строки (`string`),
целые (`int`),
числа (`float`),
бульки (`bool`).
Типы аргументов, которые появились в php 5.x
названия классов,
интерфейсы,
массив `array`
и выполняемые `callable` аргументы.
Пример
// Coercive mode
function sumOfInts(int ...$ints)
{
return array_sum($ints);
}
var_dump(sumOfInts(2, '3', 4.1)); // int(9)
Чтобы включить строгий strict режим проверки, нужно в начале (каждого) файла, добавить вызов
declare(strict_types=1);
Этот режим помимо обработки параметров влияет на возвращаемые значения!
В строгом режиме запрещен любой кастинг кроме конвертации int => float (но не наоборот)
declare(strict_types=1);
function multiply(float $x, float $y)
{
return $x * $y;
}
function add(int $x, int $y)
{
return $x + $y;
}
var_dump(multiply(2, 3.5)); // float(7)
var_dump(add('2', 3)); // Fatal error: Uncaught TypeError: Argument 1 passed to add() must be of the type integer, string given...
Важно: Strict mode работает только по месту вызова функции, то есть если описание функции находится в файле с объявлением strict_types=1,
а вызывается она из другого файла без strict_types, то никакой строгой типизации не будет!
Необратимые изменения
Классы с именами `int`, `string`, `float`, and `bool` теперь запрещены.
Любое использование классов с этими названиями приведет к фатальным ошибкам.
Scalar Type Declarations
Объявления возращаемых типов
Добавлена возможность указать тип переменной, возвращаемой функцией или методом или замыканием.
Следующие типы поддерживаются:
`string`, `int`, `float`, `bool`, `array`, `callable`, `self` (в методах), `parent` (methods only) , `Closure`,
имя класса, имя интерфейса
function arraysSum(array ...$arrays): array
{
return array_map(function(array $array): int {
return array_sum($array);
}, $arrays);
}
print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));
// Выведет
Array
(
[0] => 6
[1] => 15
[2] => 24
)
При использовании наследования в классах, дочерние методы должны соблюдать объявления возвращаемых типов
указанные в родительском классе / интерфейсе
class A {}
class B extends A {}
class C
{
public function test() : A
{
return new A;
}
}
class D extends C
{
// overriding method C::test() : A
public function test() : B // Fatal error due to variance mismatch
{
return new B;
}
}
Объявление метода `D::test() : B` вызовет `E_COMPILE_ERROR` потому что многовариантность не дозволена.
Для того чтобы метод `D::test()` заработал, нужно указать что он возвращает нечто типа `A`.
class A {}
interface SomeInterface
{
public function test() : A;
}
class B implements SomeInterface
{
public function test() : A // Окей
{
return null; // Fatal error: Uncaught TypeError: Return value of B::test() must be an instance of A, null returned...
}
}
В этот раз выполнение закончится эксепшном `TypeError`, потому что `null` не валидный возвратный тип, валидацию пройдет только экземпляр клааса `A`.
Return Type Declarations
Анонимные классы. Да!
Аноимные классы подходят для небольших задач. Из часто используют в языках например C# или Java для выполнения колбэков.
// до PHP 7
class Logger
{
public function log($msg)
{
echo $msg;
}
}
$util->setLogger(new Logger());
// PHP 7+
$util->setLogger(new class {
public function log($msg)
{
echo $msg;
}
});
Анонимные классы позволяют делать тоже самое что и обычные классы: передавать данные в конструктор, наследовать другие классы, использовать трейты и т.п.
class SomeClass {}
interface SomeInterface {}
trait SomeTrait {}
var_dump(new class(10) extends SomeClass implements SomeInterface {
private $num;
public function __construct($num)
{
$this->num = $num;
}
use SomeTrait;
});
# выведет
object(class@anonymous)#1 (1) {
["Command line code0x104c5b612":"class@anonymous":private]=>
int(10)
}
Анонимные классы поддерживают вложенность. Вложенные классы не будут иметь доступа к private/protected свойствам внешнего класса.
Если такое необходимо, то нужно передать эти данные через конструктор вложенного класса.
<?php
class Outer
{
private $prop = 1;
protected $prop2 = 2;
protected function func1()
{
return 3;
}
public function func2()
{
return new class($this->prop) extends Outer {
private $prop3;
public function __construct($prop)
{
$this->prop3 = $prop;
}
public function func3()
{
return $this->prop2 + $this->prop3 + $this->func1();
}
};
}
}
echo (new Outer)->func2()->func3(); // 6
Anonymous Classes
Поддержка юникод управляющих (escape-) последовательностей
Теперь в "строках" и объявлениях heredoc можно использовать \uXXXX последовательности для описания символов юникод
echo "\u{aa}"; // ª
echo "\u{0000aa}"; // ª (ведущие ноли можно опустить)
echo "\u{9999}"; // 香
Unicode Codepoint Escape Syntax
Метод call() у замыканий
Новый метод `call()` - шоткат для выполнения лямбды с прикрепленным объектом выполнения.
class A {private $x = 1;}
// до PHP 7
$getXCB = function() {return $this->x;};
$getX = $getXCB->bindTo(new A, 'A'); // биндим А к лямбде
echo $getX(); // 1
// PHP 7+
$getX = function() {return $this->x;};
echo $getX->call(new A); // 1
Closure::call
Фильтрация `unserialize()`
Новый функционал направлен на обеспечение безопасности сериализации объектов, предотвращает возможные code injection атаки,
давая возможность разработчику указать какие классы могут обрабатываться, а какие игнорироваться.
// конвертирует все объекты в __PHP_Incomplete_Class
$data = unserialize($foo, ["allowed_classes" => false]);
// конвертирует все объекты в __PHP_Incomplete_Class object исключая MyClass и MyClass2
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]);
// поведение по-умолчанию, разрешает все классы
$data = unserialize($foo, ["allowed_classes" => true]);
Filtered unserialize()
Класс IntlChar
Новый класс IntlChar расширяет функциональность ICU (библиотека для локализации приложений International Components for Unicode)
Класс содержит статические методы и константы для работы с юникодом.
printf('%x', IntlChar::CODEPOINT_MAX); // 10ffff
echo IntlChar::charName('@'); // COMMERCIAL AT (sign)
var_dump(IntlChar::ispunct('!')); // bool(true)
Для использования должно быть установлено расширение Intl.
Необратимые изменения
Классы в глобальном пространстве не могут называться IntlChar.
IntlChar class
Ожидания - Expectations
Обратно совместимое расширение для классической функции `утверждения` (assert).
void assert (mixed $expression [, string|Exception $message]);
Если первый параметр функции равен false, то бросается исключение / выводится ошибка с AssertionError (второй параметр).
Assert позволяет отлаживать скрипты, при этом в продакш окружении вызовы будут игнорировать интерпритатором, т.е. ничего не стоить в плане ресурсов.
ini_set('assert.exception', 1);
class CustomError extends AssertionError {}
assert(false, new CustomError('Что-то пошло не так'));
Добавлены две настройки PHP.ini, по-умолчанию:
- zend.assertions = 1
- assert.exception = 0
#zend.assertions может быть равен:
1 = обрабатывать утверждения assert (режим разработки | development mode)
0 = генерировать код, но не выполнять
-1 = игнорировать код (0-стоимость, production mode)
#assert.exception
Включает возможность генерирования исключения вместо вывода ошибки и остановки скрипта,
выключена для обратной совместимости со старым `assert()`
Expectations
Группировка объявлений `use`
Если у импортируемых классов общее пространство имен, можно объединить их импорт в группу
(это относится к классам, функциям, константам, интерфейсам)
// до PHP 7
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;
use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;
use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;
// PHP 7+
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};
Group use Declarations
Возврат выражений в генераторах
Generator Return ExpressionsПозволяет использовать `return (expression)` в генераторах.
Значение может быть получено вызовом метода `Generator::getReturn()`, только по завершении работы генератора.
$gen = (function() {
yield 1;
yield 2;
return 3;
})();
foreach ($gen as $val) {
echo $val, PHP_EOL;
}
echo $gen->getReturn(), PHP_EOL;
// вывод:
1
2
3
Возможность явно вернуть последнее значение - хорошая возможность, которая упрощает работу с генераторами.
Теперь не нужно проверять является ли значение последним. просто вызываем getReturn.
Generator Return Expressions
Делегирование генераторов
Generator DelegationПостроено на основе возможности возврата выражений из генератора.
Используется новый синтаксис:
yield from <expr>
# где <expr> может быть объектом Traversable или массивом
<expr> будет вызываться до тех пор, пока возвращает данные, затем выполнения продолжится в вызывающем генераторе.
Это позволяет разбить сложный генератор на несколько маленьких - что способствует более чистому коду и его реюзабельности.
function gen()
{
yield 1;
yield 2;
return yield from gen2();
}
function gen2()
{
yield 3;
return 4;
}
$gen = gen();
foreach ($gen as $val)
{
echo $val, PHP_EOL;
}
echo $gen->getReturn();
// вывод
1
2
3
4
Generator Delegation
Целочисленное деление intdiv()
Функция intdiv() позволяет делить числа на выходе получая целые числа.
var_dump(intdiv(10, 3)); // int(3)
Необратимые изменения
Ключевое слово `intdiv` зарезервировано для глобального контекста.
[purl=https://wiki.php.net/rfc/intdivintdiv()[/purl]
Параметры session_start()
Теперь возможно передавать параметры функции session_start().
Опции - стандартные настройки сессий из php.ini.
session_start(['cache_limiter' => 'private']); // устанавливает <a href="/r.php?url=http://php.net/manual/ru/function.session-cache-limiter.php" title="session.cache_limiter (http://php.net/manual/ru/function.session-cache-limiter.php)" class="postlink" target="_blank">session.cache_limiter</a> в private
Добавился новая настройка для сессий `session.lazy_write`, по-умолчанию включена.
Introduce session_start() Options
Функция preg_replace_callback_array()
Альтернатива preg_replace_callback, когда требуется обработать несколько условий в коллбеке.
Позволяет передать в качестве обратной функции - массив ['/regex'/ => callback, ...].
string preg_replace_callback_array(array $regexesAndCallbacks, string $input);
$tokenStream = []; // [tokenName, lexeme] pairs
$input = <<<'end'
$a = 3; // variable initialisation
end;
// до PHP 7
preg_replace_callback(
[
'~\$[a-z_][a-z\d_]*~i',
'~=~',
'~[\d]+~',
'~;~',
'~//.*~'
],
function ($match) use (&$tokenStream) {
if (strpos($match[0], '$') === 0) {
$tokenStream[] = ['T_VARIABLE', $match[0]];
} elseif (strpos($match[0], '=') === 0) {
$tokenStream[] = ['T_ASSIGN', $match[0]];
} elseif (ctype_digit($match[0])) {
$tokenStream[] = ['T_NUM', $match[0]];
} elseif (strpos($match[0], ';') === 0) {
$tokenStream[] = ['T_TERMINATE_STMT', $match[0]];
} elseif (strpos($match[0], '//') === 0) {
$tokenStream[] = ['T_COMMENT', $match[0]];
}
},
$input
);
// PHP 7+
preg_replace_callback_array(
[
'~\$[a-z_][a-z\d_]*~i' => function ($match) use (&$tokenStream) {
$tokenStream[] = ['T_VARIABLE', $match[0]];
},
'~=~' => function ($match) use (&$tokenStream) {
$tokenStream[] = ['T_ASSIGN', $match[0]];
},
'~[\d]+~' => function ($match) use (&$tokenStream) {
$tokenStream[] = ['T_NUM', $match[0]];
},
'~;~' => function ($match) use (&$tokenStream) {
$tokenStream[] = ['T_TERMINATE_STMT', $match[0]];
},
'~//.*~' => function ($match) use (&$tokenStream) {
$tokenStream[] = ['T_COMMENT', $match[0]];
}
],
$input
);
Необратимые изменения
Имя `preg_replace_callback_array` зарезервировано.
Add preg_replace_callback_array Function
PHP7 Что нового - продолжение
@Ссылки
Оригинал статьи