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 Pdo\Mysql, Pdo\Pgsql, Pdo\Sqlite,
Pdo\Odbc, Pdo\Firebird, and Pdo\Dblib 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:
1 2 3 4
use Pdo\Mysql;
$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:
1 2 3
$total = bcround('19.995', 2, RoundingMode::HalfAwayFromZero); // '20.00'
$floor = bcfloor('19.999'); // '19'
$ceil = bcceil('19.001'); // '20'
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:
1 2 3 4 5 6 7
$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
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:
1
$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:
1 2
grapheme_levenshtein('café', 'cafe'); // 1
grapheme_levenshtein('Å', 'A'); // 1
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:
1 2 3 4 5 6 7 8 9 10
use Filter\FilterException;
use Filter\FilterFailedException;
$flags = FILTER_THROW_ON_FAILURE;
try {
$email = filter_var($input, FILTER_VALIDATE_EMAIL, $flags);
} catch (FilterFailedException $e) {
// ... report the invalid input
}
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:
1 2 3 4 5
#[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:
1 2 3
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
Symfony\Component\VarExporter\DeepCloner:
1
$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:
1 2
$collator = new Collator('en');
usort($products, fn ($a, $b) => $collator->compare($a->name, $b->name));
Thanks to @aymericcucherousset for #560.
Full Changelog
- #565 Fix bcdiv handling of DivisionByZeroError (@nicolas-grekas)
- #501 mbstring polyfills must not raise value errors in PHP 7 (@derrabus)
- #527 [8.5] Add
locale_is_right_to_left(@alexander-schranz) - #532 [Intl] Add PHP 8.5
IntlListFormatterto ICU polyfill (@Ayesh) - #549 Add polyfill for PDO driver specific subclasses (@nicolas-grekas, @jnoordsij)
- #558 Add the grapheme_levenshtein polyfill (@sudam802)
- #557 [PHP 8.5] Add new
\Filter\FilterExceptionandFilter\FilterFailedException(@Ayesh) - #560 Add fallback implementation for Collator::compare() (@aymericcucherousset)
- #556 Fix PHP 7.2 compatibility for PHP 8.4 polyfill (@Seldaek)
- #561 Add polyfill for symfony/php-ext-deepclone (@nicolas-grekas, @GromNaN)
- #554 [8.6] Add
clampfunction (@kylekatarnls) - #546 [8.4] implement bcround, bcceil and bcfloor (@Dean151)
- #504 Ctype: Give the correct deprecations for PHP 8.1+ (@BackEndTea)
- #541 [8.5] Add polyfill for DelayedTargetValidation (@DanielEScherzer)