- PVSM.RU - https://www.pvsm.ru -
На Хабре уже был перевод с обзором несколько месяцев назад, но недавно вышел первый релиз-кандидат PHP 7.1, а значит никаких существенных изменений больше не будет и можно сказать, какие точно изменения будут в релизе. Я решил немного оживить сухой “changelog” своим вольным переводом изменений, которые принесет нам новая минорная версия 7.х ветки.
Теперь функции и методы, которые не должны ничего возвращать, можно помечать возвращаемым типом void:
function someNethod(): void {
// работает если return отсутсвует
// работает с return;
// не работает если return null;
// не работает если return 123;
}
Возврат какого-то значения из метода/функции, который помечен как void, будет генерировать исключение уровня Fatal Error. Обратите внимание, что NULL значение не приравнивается к void (отсутствию значения), то есть возращать NULL нельзя.
Кстати, это не значит что $x = someNethod(); не вернет ничего. Как и прежде в $x будет значение NULL. Так же void нельзя использовать как тип к параметру.
function bar(void $foo) {}
// Выбросит: Fatal error: void cannot be used as a parameter type in....
function walkList(iterable $list): iterable {
foreach ($list as $value) {
yield $value[‘id’];
}
}
Этот тип по сути объединяет примитивный тип array и интерфейс Traversable (а значит и его производные: Iterator, Generator, etc). Проблема возникла на почве того, что к примеру, foreach может работать с обоими типами, но функция с типом array не примет объект с интерфейсом Traversable и наоборот.
Так же в рамках этого RFC была добавлена новая функция is_iterable(), которая работает аналогично другим is_* функциям.
function callMethod(?Bar $bar): ?Bar {}
$this->callMethod($bar); // Работает
$this->callMethod(null); // Работает
$this->callMethod(); // НЕ работает
Обратите внимание, что использование "?" и значение null по умолчанию не одно и тоже что
function callMethod(int $bar = null) {}
$this->callMethod(1); // Работает
$this->callMethod(null); // Работает
$this->callMethod(); // Тоже работает
Причем добавление "?" оставляет поведение обратно совместимым
function callMethod(?Bar $bar = null) {}
// Работает так же как и без “?”
Также важный момент по наследованию:
interface Fooable {
function foo(int $i): ?Fooable;
}
interface StrictFooable extends Fooable {
function foo(?int $i): Fooable; // valid
}
В наследнике можно делать «строже» возвращаемый тип (то есть запрещать nullable), а параметр наоборот расширять до nullable, НО не наоборот!
echo $msg[-1]; // вернет последний символ
echo $msg{-3}; // Причем RFC явно рекомендует использовать способ $str{} так как $str[] может сбивать с толку И в будущем может быть объявлен как устаревшим.
Отрицательные значения так же стали разрешены в некоторых строковых функциях: strpos, stripos, substr_count, grapheme_strpos, grapheme_stripos, grapheme_extract, iconv_strpos, file_get_contents, mb_strimwidth, mb_ereg_search_setpos, mb_strpos, mb_stripos.
Везде это означает считать смещение с конца строки.
Так же был добавлен короткий синтаксис для list (RFC [6]).
["test" => $a, "name" => $b] = ["name" => "Hello", "test" => "World!"];
var_dump($a); // World!
var_dump($b); // Hello
Особенности:
// Parse error: syntax error, ...
["a" => $a, $b] = ["a" => 1, 2]
// Parse error: syntax error, ...
list(,,,, "key" => $keyed) = $array;
$points = [
["x" => 1, "y" => 2],
["x" => 2, "y" => 1]
];
[["x" => $x1, "y" => $y1], ["x" => $x2, "y" => $y2]] = $points;
Closure::fromCallable(callable $calback);
Вот наглядный пример применения:
class A {
public function getValidator(string $name = 'byDefault') {
return Closure::fromCallable([$this, $name]);
}
private function byDefault(...$options) {
echo "Private default with:".print_r($options, true);
}
public function __call ( string $name , array $args ) {
echo "Call $name with:".print_r($args, true);
}
}
$a = new A();
$a->getValidator("test")(1,2,3);
// Call test with: Array ( [0] => 1 [1] => 2 [2] => 3 )
$a->getValidator()(‘p1’, ‘p2’);
// Private default with: Array ( [0] => ‘p1’, [1] => ‘p2’)
// Внимание Closure::fromCallable передает контекст ($this) в момент вызова внутрь замыкания, тем самым разрешая обращаться к приватным методам
// если оставить только return [$this, $name]; то
$a->getValidator()(‘p1’, ‘p2’);
// вернет
// Call byDefault with:Array ( [0] => p1 [1] => p2 )
// то есть вызовет только публичный метод и не будет иметь доступа к приватным методам объекта
class Token {
// Константа без модификатора по умолчанию “public”
const PUBLIC_CONST = 0;
// Константы с различной областью видимости
private const PRIVATE_CONST = 0;
protected const PROTECTED_CONST = 0;
public const PUBLIC_CONST_TWO = 0;
// Весь список имеет одну область видимости
private const FOO = 1, BAR = 2;
}
try {
echo "OK";
} catch (Exception | DomainException $e) {
// ... обработка 2ух типов исключений сразу
} catch (TypeError $e) {
// ...
}
$numberOfApples = "10 apples" + "5 pears";
// Выбросит
// Notice: A non well formed numeric string encountered in example.php on line 3
// Notice: A non well formed numeric string encountered in example.php on line 3
$numberOfPears = 5 * "orange";
// Warning: A non-numeric string encountered in example.php on line 3
Это довольно важное изменение, которое теоритически может сломать обратную совместимость приложения если используются свои error handlers для перехвата предупреждений.
Причем есть интересная особенность: пробел в начале строк “ 5” + “ 3” — не даст ошибок. А вот “5 ” + “3 ” — пробел в конце уже даст выдаст предупреждения.
Для обхода последствий неявного преобразования и выброса предупреждений можно явно указывать “cast” в нужный тип: (int)“5 ” + (int)“3 ” или подавлять все принудительно @(“5 ” + “3 ”).
function foo($a) {
var_dump($a); // теперь исполнение сюда не дойдет и в $a не будет NULL
}
foo();
// Fatal error: Uncaught ArgumentCountError: Too few arguments to function foo(), 0 passed in...
Скорость до: Requests per second: 899.36 [#/sec] Скорость после: Requests per second: 2278.59 [#/sec]
function foo($this) { // Fatal error: Cannot use $this as parameter
}
static $this; // Fatal error: Cannot use $this as static variable
global $this; // Fatal error: Cannot use $this as global variable
try {
...
} catch (Exception $this) { // Fatal error: Cannot re-assign $this
}
foreach ($a as $this) { // Fatal error: Cannot re-assign $this
}
unset($this); // Fatal error: Cannot unset $this
$a = "this";
$$a = 42; // throw new Error("Cannot re-assign $this")
// и другие кейсы
На этом мы пожалуй и остановимся, хотя там еще полно мелкий изменений в основном в расширениях. А нам для холивара вполне хватит и этого списка. )
Лично моё мнение про данный минорный релиз: все очень органично вписалось, именно этого и не хватало в большинстве своем в новом PHP 7.0 и данные изменения лишь подчеркивают и усиливают особенности 7.х ветки.
Рекомендую дождаться 7.1.1 и можно обновляться без страха, что-то сломать (если вы конечно уже перешли на 7.0).
Данная статья не претендует на полное описание ВСЕХ изменений и я мог пропустить что-то важное, рекомендую все равно ознакомиться с первоисточниками:
» https://wiki.php.net/rfc#php_71 [13]
» https://github.com/php/php-src/blob/php-7.1.0RC1/UPGRADING [14]
P.S. Примеры можно испытать самому в онлайн песочнице — 3v4l.org/#version=7.1.0RC1 [15]
Автор: shandy
Источник [16]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/187020
Ссылки в тексте:
[1] RFC: https://wiki.php.net/rfc/void_return_type
[2] RFC: https://wiki.php.net/rfc/iterable
[3] Nullable RFC: https://wiki.php.net/rfc/nullable_types
[4] RFC: https://wiki.php.net/rfc/negative-string-offsets
[5] RFC: https://wiki.php.net/rfc/list_keys
[6] RFC: https://wiki.php.net/rfc/short_list_syntax
[7] RFC: https://wiki.php.net/rfc/closurefromcallable
[8] RFC: https://wiki.php.net/rfc/class_const_visibility
[9] RFC: https://wiki.php.net/rfc/multiple-catch
[10] RFC: https://wiki.php.net/rfc/invalid_strings_in_arithmetic
[11] RFC: https://wiki.php.net/rfc/throw_error_in_extensions
[12] RFC: https://wiki.php.net/rfc/too_few_args
[13] https://wiki.php.net/rfc#php_71: https://wiki.php.net/rfc#php_71
[14] https://github.com/php/php-src/blob/php-7.1.0RC1/UPGRADING: https://github.com/php/php-src/blob/php-7.1.0RC1/UPGRADING
[15] 3v4l.org/#version=7.1.0RC1: https://3v4l.org/#version=7.1.0RC1
[16] Источник: https://habrahabr.ru/post/309858/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.