Home / Symfony / Symfony Polyfill 1.34.0 released

Symfony Polyfill 1.34.0 released

Symfony Polyfill 1.34.0 ships ten new polyfills that cover features from
PHP 8.4, 8.5, and 8.6, along with a new polyfill for the deepclone
Symfony PHP extension. This release lets you write forward-compatible
code against upcoming PHP APIs while still running on the PHP versions
your projects support today.

PDO driver-specific subclasses

PHP 8.4 introduced dedicated PdoMysql, PdoPgsql, PdoSqlite,
PdoOdbc, PdoFirebird, and PdoDblib subclasses with their
own driver-specific constants and methods, and PHP 8.5 deprecates the
equivalents on the base PDO class. This polyfill makes the new
classes and constants available on earlier PHP versions, so you can move
away from the deprecated API without waiting for every target runtime to
reach PHP 8.4:

use PdoMysql;

$connection = new Mysql('mysql:host=localhost;dbname=shop', $user, $pass);
$connection->setAttribute(Mysql::ATTR_MULTI_STATEMENTS, false);

Note that the PDO::connect() static factory introduced alongside the
subclasses is not polyfilled.

Thanks to @nicolas-grekas and @jnoordsij for
#549.

bcmath rounding functions

PHP 8.4 added bcround(), bcceil(), and bcfloor() to round
arbitrary-precision decimal numbers without ever converting them to
floats. The polyfill makes the three functions available on earlier PHP
versions, together with the RoundingMode constants that bcround()
expects:

$total = bcround('19.995', 2, RoundingMode::HalfAwayFromZero); // '20.00'
$floor = bcfloor('19.999');                                    // '19'
$ceil  = bcceil('19.001');                                     // '20'

Thanks to @Dean151 for
#546.

IntlListFormatter

PHP 8.5 ships a new IntlListFormatter class that joins items into a
locale-aware list, picking the correct conjunction and punctuation for
each language. The ICU polyfill provides it back to PHP 7.2 using the
CLDR list patterns:

$formatter = new IntlListFormatter('en');
echo $formatter->format(['apples', 'oranges', 'pears']);
// apples, oranges, and pears

$formatter = new IntlListFormatter('fr');
echo $formatter->format(['pommes', 'oranges', 'poires']);
// pommes, oranges et poires

Thanks to @Ayesh for
#532.

locale_is_right_to_left()

PHP 8.5 also exposes locale_is_right_to_left() (along with the
Locale::isRightToLeft() method), which returns true for locales
written from right to left such as Arabic or Hebrew. You can use it to
flip the layout direction of a response without shipping your own list
of RTL language codes:

$direction = locale_is_right_to_left($request->getLocale()) ? 'rtl' : 'ltr';

Thanks to @alexander-schranz for
#527.

grapheme_levenshtein()

PHP’s built-in levenshtein() counts bytes, which produces incorrect
results as soon as a string contains multi-byte characters or combining
marks. PHP 8.5 adds grapheme_levenshtein(), which operates on
grapheme clusters so that user-visible characters are counted as one
unit:

grapheme_levenshtein('café', 'cafe');  // 1
grapheme_levenshtein('Å', 'A');        // 1

Thanks to @sudam802 for
#558.

Filter exception classes

PHP 8.5 introduces a FILTER_THROW_ON_FAILURE flag that makes
filter_var() throw instead of returning false on invalid input.
The throwing behavior itself cannot be emulated, but the new exception
classes can, which lets library authors write catch blocks that
compile on both PHP 8.5 and earlier releases:

use FilterFilterException;
use FilterFilterFailedException;

$flags = FILTER_THROW_ON_FAILURE;

try {
    $email = filter_var($input, FILTER_VALIDATE_EMAIL, $flags);
} catch (FilterFailedException $e) {
    // ... report the invalid input
}

Thanks to @Ayesh for
#557.

DelayedTargetValidation attribute

PHP 8.5 adds the #[DelayedTargetValidation] attribute, which tells
the engine to defer target validation of a user attribute until
reflection actually instantiates it. This unblocks attribute authors who
need to apply an attribute to a target that the engine would otherwise
reject. The polyfill provides an empty stub so the attribute compiles
and is visible through reflection on earlier PHP versions:

#[DelayedTargetValidation]
#[Route('/invoices')]
class InvoiceController
{
}

Thanks to @DanielEScherzer for
#541.

clamp()

Looking further ahead, the release ships a polyfill for the upcoming
PHP 8.6 clamp() function, which constrains a numeric value between
a minimum and a maximum:

clamp($volume, 0, 100);  // caps volume to the 0..100 range
clamp(-5, 1, 10);        // 1
clamp(42, 1, 10);        // 10

Thanks to @kylekatarnls for
#554.

Polyfill for the deepclone extension

Symfony now ships an optional symfony/php-ext-deepclone native
extension that round-trips arbitrary PHP value graphs through an array
representation, preserving object identity, references, cycles, and
private property state. It is several times faster than
unserialize(serialize(...)) and produces output that OPcache can map
into shared memory when dumped via var_export().

The new symfony/polyfill-deepclone package provides the same
deepclone_to_array() and deepclone_from_array() functions in
pure PHP, reusing the wire format already used by
SymfonyComponentVarExporterDeepCloner:

$snapshot = deepclone_from_array(deepclone_to_array($order));

When the native extension is loaded, the polyfill steps aside.

Thanks to @nicolas-grekas and @GromNaN for
#561.

Collator::compare() fallback

Before this release, calling Collator::compare() on the ICU polyfill
raised a MethodNotImplementedException. It now falls back to a
deterministic string comparison based on the spaceship operator, so code
that needs a stable ordering (rather than full ICU collation) works out
of the box:

$collator = new Collator('en');
usort($products, fn ($a, $b) => $collator->compare($a->name, $b->name));

Thanks to @aymericcucherousset for
#560.

Full Changelog


Sponsor the Symfony project.
Tagged:

Leave a Reply

Your email address will not be published. Required fields are marked *