PHP 7.4: Основни нововъведения

PHP 7.4 е последният минорен 7.x преди линията 8.0: добавя типизирани свойства, arrow functions, ограничена ковариантност/контравариантност и ежедневен синтактичен захар (??=, spread в масиви, разделители в числа). На паралелна писта идват FFI, OPcache preloading и модерният чифт __serialize / __unserialize. При миграция фокусирайте се върху: инициализация на typed properties, константи за password алгоритми (вече низове), build/разширения (SQLite/Zip вече не са банднати, преход към pkg-config).

Съдържание


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

Свойствата на клас могат да имат типове. Неинициализирано typed property не трябва да се чете преди присвояване — идва Typed property ... must not be accessed before initialization.

final class User
{
    public int $id;
    public string $name;
    public ?string $nickname = null;
}

От практиката:

  • Ако „няма стойност“ е валидно — ползвайте ?Type или default.
  • Тип callable за property не се поддържа.
  • Обектните typed properties имат ограничения при декларация — вижте мануала.

Arrow functions

fn улавя променливи от обкръжението по стойност и връща един израз — удобно за кратки callback-и.

$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3]);

fn е запазена дума — не може име на функция/клас (методи/константи — ок).

Ковариантност и контравариантност

Типовете на връщане могат да се стесняват, типовете на параметрите — да се разширяват при наследяване, с ограничения. Пълна вариантност работи най-добре с autoload; в един файл са позволени само нециклични препратки към класове.

Присвояване с null coalescing (??=)

Присвоява се, ако отляво е unset или null:

$config['debug'] ??= false;

Spread оператор в масиви

Разпаковане на итерируеми стойности в литерал:

$base = [1, 2];
$all = [0, ...$base, 3]; // [0, 1, 2, 3]

Комбинира се с array_merge(...$arrays); array_merge() без аргументи връща [].

Разделител в числови литерали

Подчертаванията подобряват четимостта, не променят стойността:

$million = 1_000_000;
$hex = 0xFF_FF_FF;

Слаби референции (WeakReference)

WeakReference държи референция, която не предотвратява унищожаването на обекта — полезно за кешове без течове.

Изключения от __toString()

Хвърлянето от __toString() е позволено (преди — fatal). Част от старите recoverable fatals са станали Error — одитирайте string casting.

Сериализация: __serialize / __unserialize

Нов механизъм, който постепенно измества Serializable:

final class Point
{
    public function __serialize(): array
    {
        return ['x' => $this->x, 'y' => $this->y];
    }

    public function __unserialize(array $data): void
    {
        $this->x = $data['x'];
        $this->y = $data['y'];
    }
}

SPL типове като ArrayObject могат да създават нови сериализирани натоварвания, четими на 7.4+, но не на по-стари PHP.

Разширения и стандартна библиотека

  • FFI: извикване на C библиотеки (мощно; изисква сигурност).
  • OPcache preloading: opcache.preload, често opcache.preload_user.
  • mb_str_split(): като str_split(), но по кодпойнти.
  • proc_open(): команда като масив (без shell), дескриптори redirect / null.
  • strip_tags(): позволени тагове като масив от имена.
  • PDO: user/pass в DSN за повече драйвери; ?? в SQL екранира литерален ? (напр. при PostgreSQL JSON оператори).
  • PCRE: preg_replace_callback* приема flagsPREG_OFFSET_CAPTURE, PREG_UNMATCHED_AS_NULL и др.
  • Password: Argon2 през sodium без libargon.

Практични рецепти

Подразбирания с ??=

$options['timeout'] ??= 30;

Arrow function в сортиране

usort($rows, fn($a, $b) => $a['score'] <=> $b['score']);

Spread-merge на динамични списъци

$merged = array_merge(...$chunks);

Обратно несъвместими промени (миграционни бележки)

Ядро

  • Достъп като масив към не-масиви: $null["key"] и подобни за null, bool, int, float, resourcenotice.
  • get_declared_classes(): вече не връща анонимни класове, докато не са инстанцирани.
  • fn: запазена ключова дума за имена на функции/класове.
  • <?php в края на файл без нов ред: вече се тълкува като отварящ PHP таг (преди зависеше от short_open_tag).
  • Stream wrappers: при include/require на stream може да се извика streamWrapper::stream_set_option(STREAM_OPTION_READ_BUFFER) — имплементирайте метода или върнете false, за да няма warning.
  • Сериализация: формат o е премахнат (актуално само за ръчно съставени низове).
  • Константи за password алгоритми: PASSWORD_* са низове ('2y', 'argon2id', …), не цели — код, сравняващ с 1/2/3, се чупи.
  • htmlentities(): notice, когато кодирането се свежда до поведение като htmlspecialchars.
  • fread/fwrite: при неуспех връщат false (не ''/0); възможен е notice.
  • BCMath: предупреждение при лошо формирани числови низове (като преди се интерпретира като нула).
  • CURL: сериализация на CURLFile хвърля по-рано; нестандартен аргумент на curl_version() — предупреждение/игнориране.
  • Date: var_dump на DateTime* не оставя „излишни“ свойства; сравнение на DateInterval предупреждава и винаги е false.
  • Intl: по подразбиране idn_to_ascii / idn_to_utf8 използват INTL_IDNA_VARIANT_UTS46.
  • MySQLi: премахнат embedded server; премахнато недокументираното $mysqli->stat — ползвайте mysqli::stat().
  • OpenSSL: openssl_random_pseudo_bytes хвърля като random_bytes при грешка; $crypto_strong е true, ако няма изключение.
  • PCRE: с PREG_UNMATCHED_AS_NULL опашните несъвпаднали групи са null (стабилен размер на $matches).
  • PDO: сериализация на PDO/PDOStatement хвърля Exception (не PDOException).
  • Reflection: сериализация на reflection обекти хвърля; променени са числови стойности на някои константи за модификатори.
  • SPL / ArrayObject: променено поведение на get_object_vars без STD_PROP_LIST; SplPriorityQueue::setExtractFlags(0) хвърля веднага.
  • Tokenizer: неочаквани байтове стават T_BAD_CHARACTER вместо „празнини“ в потока.
  • Бисквитки (от 7.4.11): имената на входящи cookies не се URL-декодират.

Deprecated (поправете рано)

Акценти:

  • Вложени тернарни оператори без явни скоби (освен еднозначната форма с влагане в средния операнд).
  • Фигурни скоби за offset $str{0} / $arr{0} → използвайте [].
  • (real) и is_real()(float) / is_float().
  • array_key_exists() върху обектиisset() / property_exists().
  • implode($parts, $glue) — обърнат ред → implode($glue, $parts).
  • ReflectionType::__toString() и Reflection*::export() → API като ReflectionNamedType::getName() и string cast на reflection обекти.
  • allow_url_include, FILTER_SANITIZE_MAGIC_QUOTES, остарели LDAP paged функции, money_format(), hebrevc() и др. — пълен списък: migration74 deprecated.

Други промени и експлоатация

  • zend.exception_ignore_args: нов INI (по подразбиране може да скрие аргументи в stack traces — проверете error reporting).
  • opcache.preload_user: потребител за preload, когато не е root.
  • Миграция към pkg-config: много ./configure флагове вече не приемат =DIR; ползвайте PKG_CONFIG_PATH или FOO_CFLAGS/FOO_LIBS.
  • Премахнати бандли: SQLite3, Zip, onig (mbregex) — нужни са системни библиотеки; hash винаги е включен.
  • CSV: празен низ за $escape изключва PHP escape механизма; str_getcsv() е съгласуван.
  • GD: imagecropauto() синхронизиран със system libgd; променен default режим; imagescale() с -1 за запазване на пропорции.
  • PEAR: не се инсталира по подразбиране (--with-pear опционално и deprecated).
  • Производителност: opcode за array_key_exists() при статично разрешаване; UTF-8 preg_match валидира низа веднъж при повторни извиквания.

Обобщение

PHP 7.4 е мост към 8.x: въведете typed properties и __serialize/__unserialize рано; търсете fn, $var{idx}, целочислени password алгоритми и чуплив ArrayObject код; тествайте streams, OpenSSL random и сериализация на PDO/Reflection.