PHP 7.4: Изменения

Опубликовано 0 комментариев 111 просмотров
PHP 7.4: Изменения

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

По аналогии с чейнжлогом PHP 7.3 данный пост будет дополняться до тех пор, пока не состоится официальный релиз стабильной версии PHP 7.4. С учетом цикла разработки это произойдет в ноябре-декабре 2019 года. Стоит также напомнить, что уже 30 ноября 2019 года будет окончательно прекращен выпуск обновлений (кроме обновлений безопасности) для PHP 7.1 поэтому для всех, кто использует эту или, что еще хуже, более ранние версии языка в своих проектах настало время апгрейда.

Список изменений

Предварительная загрузка

Данное нововведение базируется на технологии "Class Data Sharing" от Java HotSpot VM. Оно предоставляет пользователю возможность использовать гибкость кэширования, предоставляемого PHP (APC, Turck MMCache, Zend OpCache) для увеличения производительности собственных приложений. При запуске сервера, перед запуском любого приложения появится возможность скомпилировать и сохранить в памяти определенный набор файлов PHP, сделав их доступными сразу при последующих запросах. Все функции и классы из этих файлов будут доступны для использования прямо из коробки абсолютно так же, как и внутренние объекты (\Exception или strlen(), например).

Таким образом появится возможность предзагрузки целых фреймворков, библиотек. Это также позволит добавлять “встроеннные” функции, написанные на PHP (по аналогии с HHVM sytemlib).

Предварительная загрузка будет контролироваться новой директивой php.ini - opcache.preload. В ней будет указан путь к файлу PHP, который будет загружен в память. Этот файл может загружать другие файлы, используя их или функцию opcache_compile_file().

Например, этот файл добавляет новую функцию и использует ее для загрузки всего Zend Framework.

<?php

function _preload($preload, string $pattern = '/\.php$/', array $ignore = [])
{
  if(is_array($preload)) {
    foreach($preload as $path) {
      _preload($path, $pattern, $ignore);
    }
  } elseif(is_string($preload)) {
    $path = $preload;
    if(!in_array($path, $ignore)) {
      if(is_dir($path)) {
        if($dh = opendir($path)) {
          while(($file = readdir($dh)) !== false) {
            if($file !== '.' && $file !== '..') {
              _preload($path.'/'.$file, $pattern, $ignore);
            }
          }

          closedir($dh);
        }
      } elseif(is_file($path) && preg_match($pattern, $path)) {
        if(!opcache_compile_file($path)) {
          trigger_error('Preloading Failed', E_USER_ERROR);
        }
      }
    }
  }
}

set_include_path(get_include_path().PATH_SEPARATOR.realpath('/var/www/ZendFramework/library'));

_preload(['/var/www/ZendFramework/library']);

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

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

В Windows невозможно будет предварительно загрузить классы, унаследованные от внутренних.

Хэш-расширение всегда доступно

Расширение хэша ext/hash будет всегда доступно подобно date, spl и pcre.

Аргумент –enable-hash, используемый в конфигурации сборки удален.

Реестр хэш-расширений

Будет добавлен механизм реестра хэш-расширений password_algos().

print_r(password_algos());

Array(
    [0] => "2y" // Ident for "bcrypt"
    [1] => "argon2i"
    [2] => "argon2id"
)

Типизированные свойства

7 версия языка добавила возможность указывать скалярный или структурированный тип для аргументов функций и методов, а также скалярный тип для возвращаемых ими значений. PHP 7.4 дополнит это изменение возможностью указывать типы свойств классов.

class Test {
    // Legal default values
    public bool $a = true;
    public int $b = 42;
    public float $c = 42.42;
    public float $d = 42; // Special exemption
    public string $e = "str";
    public array $f = [1, 2, 3];
    public iterable $g = [1, 2, 3];
    public ?int $h = null;
    public ?object $i = null;
    public ?Test $j = null;

    // These have *no* legal default values
    public object $k;
    public Test $l;

    // ILLEGAL default values
    public bool $m = 1;
    public int $n = null;
    public Test $o = null;
}

Изменения openssl_random_pseudo_bytes()

В случае ошибки генерации строки в openssl_random_pseudo_bytes() будет вызван \Exception с описанием проблемы. Присваемое второму аргументу $crypto_strong значение гарантированно будет true в случае, если не сработал механизм вызова ошибки.

FFI - Интерфейс для внешних функций на C

FFI - полезная фича из Python и LuaJIT, позволяющая работать с функциями и данными C из скриптового языка. Для PHP FFI открывает способ написания расширений и привязок PHP к библиотекам C на чистом PHP.

<?php

// create FFI object, loading libc and exporting function printf()
$ffi = FFI::cdef(
    "int printf(const char *format, ...);", // this is regular C declaration
    "libc.so.6"
);

// call C printf()
$ffi->printf("Hello %s!\n", "world");

Для минимизации рисков использование данного интерфейса будет определяться директивой php.ini ffi.enable - false отключить, true включить везде и preload (по-умолчанию) разрешить использование только в файле предварительной загрузки.

У класса FFI доступны следующие методы:

  • FFI::cdef([string $cdef = "" [, string $lib = null]]): FFI
  • FFI::new(mixed $type [, bool $own = true [, bool $persistent = false]]): FFI\CData
  • FFI::free(FFI\CData $cdata): void
  • FFI::cast(mixed $type, FFI\CData $cdata): FFI\CData
  • FFI::addr(FFI\CData $cdata): FFI\CData
  • FFI::type(string $type): FFI\CType
  • FFI::arrayType(FFI\CType $type, array $dims): FFI\CType
  • FFI::typeof(FFI\CData $data): FFI\CType
  • FFI::sizeof(mixed $cdata_or_ctype): int
  • FFI::alignof(mixed $cdata_or_ctype): int
  • FFI::memcpy(FFI\CData $dst, mixed $src, int $size): void
  • FFI::memcmp(mixed $src1, mixed $src2, int $size): int
  • FFI::memset(FFI\CData $dst, int $c, int $size): void
  • FFI::string(FFI\CData $src [, int $size]): string
  • FFI::load(string $file_name): FFI
  • FFI::scope(string $scope_name): FFI

Более подробно о доступных методах можно прочитать в RFC.

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

Native FFI
Python 0.212 0.343
PyPy 0.010 0.081
LuaJit -joff 0.037 0.412
LuaJit -jon 0.003 0.002
PHP 0.040 0.093
PHP + jit 0.016 0.087

В ответ на сообщение

Доступна разметка Markdown. А еще вы можете использовать крутой пак эмоций.

Нажимая на кнопку «Отправить» вы даете свое согласие на обработку персональных данных в соответствии с законом №152-ФЗ «О персональных данных» от 27.07.2006 и принимаете условия Политики конфеденциальности.