Forum PHP 2017

Новая функциональность

Декларация скалярных типов

Декларация скалярных типов введена в двух вариантах: принуждающая (по умолчанию) и строгая. Следующие типы могут использоваться для декларации параметров (в обоих вариантах): строки (string), целые (int), рациональные числа (float) и логические значения (bool). Они дополняют аргументы других типов, введенных в PHP 5: имена классов, интерфейсов, array и callable.

<?php
// Принуждающий режим
function sumOfInts(int ...$ints)
{
    return 
array_sum($ints);
}

var_dump(sumOfInts(2'3'4.1));

Результат выполнения данного примера:

int(9)

Для установки строгого режима, в самом начале файла необходимо поместить одну директиву declare. Это означает, что строгость декларации работает на уровне файла и не затрагивает весь остальной код. Эта директива затрагивает не только декларацию параметров, но и возвращаемые значения функций (см. декларация возвращаемого типа), встроенные функции PHP и функции загруженных расширений.

Подробную документацию и примеры использования читайте в разделе декларация типов.

Декларация возвращаемых значений

В PHP 7 добавлена поддержка декларация возвращаемого типа. Аналогично как и декларация типов аргументов, декларация типа возвращаемого значения указывает, значение какого типа должна вернуть функция. Для декларации типа возвращаемого значения доступны все те же типы, что и для декларации типов аргументов.

<?php

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
)

Подробную документацию и примеры использования читайте в разделе декларация возвращаемого типа.

Оператор объединения с null

Был добавлен оператор объединения с null (??), являющийся синтаксическим сахаром для достаточно распространенного действия, когда совместно используются тернарный оператор и функция isset(). Он возвращает первый операнд, если он задан и не равен NULL, а в обратном случае возвращает второй операнд.

<?php
// Извлекаем значение $_GET['user'], а если оно не задано,
// то возвращаем 'nobody'
$username $_GET['user'] ?? 'nobody';
// Это идентично следующему коду:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// Данный оператор можно использовать в цепочке.
// В этом примере мы сперва проверяем, задан ли $_GET['user'], если нет,
// то проверяем $_POST['user'], и если он тоже не задан, то присваеваем 'nobody'.
$username $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

Оператор spaceship (космический корабль)

Этот оператор предназначен для сравнения двух выражений. Он возвращает -1, 0 или 1 если $a, соответственно, меньше, равно или больше чем $b. Сравнение производится в соответствии со правилами сравнения типов PHP.

<?php
// Целые
echo <=> 1// 0
echo <=> 2// -1
echo <=> 1// 1

// Рациональные
echo 1.5 <=> 1.5// 0
echo 1.5 <=> 2.5// -1
echo 2.5 <=> 1.5// 1
 
// Строки
echo "a" <=> "a"// 0
echo "a" <=> "b"// -1
echo "b" <=> "a"// 1
?>

Задание констант массивов с помощью define()

Можно задать константу типа array с помощью функции define(). В PHP 5.6, такие константы можно было задавать только с помощью const.

<?php
define
('ANIMALS', [
    
'dog',
    
'cat',
    
'bird'
]);

echo 
ANIMALS[1]; // выводит "cat"
?>

Анонимные классы

Была добавлена поддержка анонимных классов с помощью new class. Их можно использовать тогда, когда нужен одноразовый класс и создавать полноценный класс, а потом его объект не имеет смысла:

<?php
interface Logger {
    public function 
log(string $msg);
}

class 
Application {
    private 
$logger;

    public function 
getLogger(): Logger {
         return 
$this->logger;
    }

    public function 
setLogger(Logger $logger) {
         
$this->logger $logger;
    }
}

$app = new Application;
$app->setLogger(new class implements Logger {
    public function 
log(string $msg) {
        echo 
$msg;
    }
});

var_dump($app->getLogger());
?>

Результат выполнения данного примера:

object(class@anonymous)#2 (0) {
}

Подробную документацию и примеры использования читайте в разделе анонимные классы.

Синтаксис кодирования Unicode

Берем шестнадцатеричный код Unicode и записываем его в формате UTF-8 в двойных кавычках или формате heredoc. Любой корректный код будет принят. Лидирующие нули по желанию.

echo "\u{aa}";
echo "\u{0000aa}";
echo "\u{9999}";

Результат выполнения данного примера:

ª
ª (То же самое, что и первый вариант, но с лидирующими нулями)
香

Closure::call()

Closure::call() является более производительным и коротким способом временного связывания области действия объекта с замыканием и его вызовом.

<?php
class {private $x 1;}

// До PHP 7
$getX = function() {return $this->x;};
$getXCB $getX->bindTo(new A'A'); // промежуточное замыкание
echo $getXCB();

// PHP 7+
$getX = function() {return $this->x;};
echo 
$getX->call(new A);

Результат выполнения данного примера:

1
1

unserialize() с фильтрацией

Этот функционал обеспечивает более высокий уровень безопасности при десериализации объектов с непроверенными данными. Это позволяет предотвратить возможную инъекцию кода, позволяя разработчику использовать белый список классов для десериализации.

<?php

// Преобразование всех объектов в into __PHP_Incomplete_Class
$data unserialize($foo, ["allowed_classes" => false]);

// Преобразование всех объектов кроме MyClass и MyClass2 в __PHP_Incomplete_Class
$data unserialize($foo, ["allowed_classes" => ["MyClass""MyClass2"]]);

// Поведение по умолчанию принимает все классы (можно просто не задавать второй аргумент)
$data unserialize($foo, ["allowed_classes" => true]);

IntlChar

Новый класс IntlChar добавляет новую функциональность в ICU. Класс определяет несколько статических методов и констант для манипулирования символами Unicode.

<?php

printf
('%x'IntlChar::CODEPOINT_MAX);
echo 
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

Результат выполнения данного примера:

10ffff
COMMERCIAL AT
bool(true)

Для использования это класса необходимо установить расширение Intl.

Ожидания

Ожидания являются улучшенной, обратно совместимой версией старой функции assert(). Они позволяют делать предположения с нулевой стоимостью в промышленном коде и предоставляют возможность выбрасывать пользовательские исключения в случае провала ожидания.

Вместе тем, что старое API поддерживается, assert() теперь является языковой конструкцией, принимающей первым аргументом выражения, а не только строки для оценки или логические значения для проверки.

<?php
ini_set
('assert.exception'1);

class 
CustomError extends AssertionError {}

assert(false, new CustomError('Some error message'));
?>

Результат выполнения данного примера:

Fatal error: Uncaught CustomError: Some error message

Подробное описание этого функционала, а также инструкции для его конфигурирования для тестовых и промышленных сред, читайте в секции Ожидания раздела посвященному assert().

Групповые декларации use

Классы, функции и константы импортируемые из одного и того же namespace, теперь можно группировать в одном операторе use.

<?php
// До 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\{ClassAClassBClassC as C};
use function 
some\namespace\{fn_afn_bfn_c};
use const 
some\namespace\{ConstAConstBConstC};
?>

Выражение return в генераторах

Эта функциональность добавлена к генераторам, введенным в PHP 5.5. Она позволяет использовать оператор return в генераторах в качестве финального возвращаемого значение (возврат по ссылке недопустим). Это значение можно извлечь с помощью нового метода Generator::getReturn(), которые можно использовать только после того, как генератор вернул все сгенерированные значение.

<?php

$gen 
= (function() {
    
yield 1;
    
yield 2;

    return 
3;
})();

foreach (
$gen as $val) {
    echo 
$valPHP_EOL;
}

echo 
$gen->getReturn(), PHP_EOL;

Результат выполнения данного примера:

1
2
3

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

Делегация генератора

Теперь генератор может автоматически делегировать другому генератору, объекту класса Traversable или массиву без необходимости писать в нем дополнительную обработку полученных значений. Достигается это с помощью конструкции yield from.

<?php
function gen()
{
    
yield 1;
    
yield 2;
    
yield from gen2();
}

function 
gen2()
{
    
yield 3;
    
yield 4;
}

foreach (
gen() as $val)
{
    echo 
$valPHP_EOL;
}
?>

Результат выполнения данного примера:

1
2
3
4

Функция целочисленного деления intdiv()

Новая функция intdiv() производит целочисленное деление операндов и возвращает его результат.

<?php
var_dump
(intdiv(103));
?>

Результат выполнения данного примера:

int(3)

Опции сессий

Теперь session_start() принимает массив опций, которые переопределят конфигурационные директивы сессии установленные в php.ini.

Также опции были расширены включенной по умолчанию опцией session.lazy_write, которая говорит PHP о том, что файл сессии надо перезаписывать, только если изменились даные сессии, и опцией read_and_close, которую можно задать только через session_start() для того, чтобы PHP закрывал сессию сразу же как прочитает ее данные и не вносил в нее каких либо изменений.

К примеру, для задания session.cache_limiter равным private и немедленному закрытию сессии после чтения ее данных:

<?php
session_start
([
    
'cache_limiter' => 'private',
    
'read_and_close' => true,
]);
?>

preg_replace_callback_array()

Новая функция preg_replace_callback_array() позволяет писать более чистый код, когда требуется использовать функцию preg_replace_callback(). До PHP 7 при необходимости обработать разные регулярные выражения разными функциями, приходилось для каждой такой обработки писать отдельный вызов функции.

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

Функции CSPRNG

Были добавлены две новые кроссплатформенные функции для генерации криптографически безопасных строк и целых чисел: random_bytes() и random_int().

Теперь функция list() всегда может раскрывать объекты реализующие ArrayAccess

Ранее функция list() не гарантировала корректную обработку объектов реализующих ArrayAccess. Теперь это исправлено.

Прочие изменения

  • Добавлена возможность обращения к методам и свойствам класса при клонировании, т.е. (clone $foo)->bar().
add a note add a note

User Contributed Notes 5 notes

up
66
PawelD
11 months ago
<?php
class foo { static $bar = 'baz'; }
var_dump('foo'::$bar);
?>

if < php7.0

then we will receive a syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)

but php7 returns string(3) "baz"

I think it's not documented anywhere
up
0
robert.j.pounder
3 days ago
<?php
class foo { static $bar = 'baz'; }
var_dump('foo'::$bar);

and
variations dont work

but

<?php
class foo { static $bar = 'baz'; }
$t = 'foo';
var_dump($t::$bar);

works < 7.0
up
0
TerryE
5 days ago
$a = ''; // or 0 or false

$b = $a ?? 'a'; 
// $b is '' or 0 or false

$c = $a ?: 'a';
// $c is 'a'
up
-5
omarv_r at yahoo dot com
10 months ago
lexx918, It is not working unexpectedly... lets see:

Calling to isset() method for a non existing property ($foo->bar in this case), automatically the magic method __isset() is invoked. So

$a = isset($foo->bar) ?: null; // __isset

is correct.

But when we try to evaluate $foo->bar, we are calling a getter. Because the bar property does not exist, the implicit calling is to magic method __get(). So

$a = $foo->bar ?? null; // __get

is correct too.
up
-45
lexx918 at mail dot ru
10 months ago
Sugar of ternary operator:
<?php
$a
?? 'b'
// allegedly equivalent to
isset($a) ? $a : 'b'
?>
.. in classes working unexpectedly:
<?php
class Foo {
    public function
__get($p) { echo "__get" . PHP_EOL; }
    public function
__isset($p) { echo "__isset" . PHP_EOL; }
}
$foo = new Foo;
$a = isset($foo->bar) ?: null; // __isset
$a = $foo->bar ?? null; // __get
?>
To Top