This project backports features found in the latest PHP versions and provides compatibility layers for some extensions and functions. It is intended to be used when portability across PHP versions and extensions is desired.
Polyfills are provided for:
- the
apcuextension when the legacyapcextension is installed; - the
ctypeextension when PHP is compiled without ctype; - the
deepcloneextension (deepclone_to_arrayanddeepclone_from_arrayfunctions); - the
mbstringandiconvextensions; - the
uuidextension; - the
MessageFormatterclass and themsgfmt_format_messagefunctions; - the
Normalizerclass and thegrapheme_*functions; - the
utf8_encodeandutf8_decodefunctions from thexmlextension or PHP-7.2 core; - the
Collator,NumberFormatter,Locale,IntlDateFormatterandIntlListFormatterclasses, limited to the "en" locale; - the
intl_error_name,intl_get_error_code,intl_get_error_messageandintl_is_failurefunctions; - the
idn_to_asciiandidn_to_utf8functions; - a
Binaryutility class to be used when compatibility withmbstring.func_overloadis required; - the
spl_object_idandstream_isattyfunctions introduced in PHP 7.2; - the
mb_ord,mb_chrandmb_scrubfunctions introduced in PHP 7.2 from thembstringextension - the
sapi_windows_vt100_supportfunction (Windows only) introduced in PHP 7.2; - the
PHP_FLOAT_*constant introduced in PHP 7.2; - the
PHP_OS_FAMILYconstant introduced in PHP 7.2; - the
is_countablefunction introduced in PHP 7.3; - the
array_key_firstandarray_key_lastfunctions introduced in PHP 7.3; - the
hrtimefunction introduced in PHP 7.3; - the
JsonExceptionclass introduced in PHP 7.3; - the
normalizer_get_raw_decompositionfunction introduced in PHP 7.3; - the
get_mangled_object_vars,mb_str_splitandpassword_algosfunctions introduced in PHP 7.4; - the
fdivfunction introduced in PHP 8.0; - the
get_debug_typefunction introduced in PHP 8.0; - the
preg_last_error_msgfunction introduced in PHP 8.0; - the
str_containsfunction introduced in PHP 8.0; - the
str_starts_withandstr_ends_withfunctions introduced in PHP 8.0; - the
ValueErrorclass introduced in PHP 8.0; - the
UnhandledMatchErrorclass introduced in PHP 8.0; - the
FILTER_VALIDATE_BOOLconstant introduced in PHP 8.0; - the
get_resource_idfunction introduced in PHP 8.0; - the
Attributeclass introduced in PHP 8.0; - the
Stringableinterface introduced in PHP 8.0; - the
PhpTokenclass introduced in PHP 8.0 when the tokenizer extension is enabled; - the
array_is_listfunction introduced in PHP 8.1; - the
enum_existsfunction introduced in PHP 8.1; - the
MYSQLI_REFRESH_REPLICAconstant introduced in PHP 8.1; - the
ReturnTypeWillChangeattribute introduced in PHP 8.1; - the
CURLStringFileclass introduced in PHP 8.1 (but only if PHP >= 7.4 is used); - the
CURLOPT_ISSUERCERT_BLOBconstant introduced in PHP 8.1 when curl 7.47+ is used; - the
AllowDynamicPropertiesattribute introduced in PHP 8.2; - the
SensitiveParameterattribute introduced in PHP 8.2; - the
SensitiveParameterValueclass introduced in PHP 8.2; - the
Random\Engineinterface introduced in PHP 8.2; - the
Random\CryptoSafeEngineinterface introduced in PHP 8.2; - the
Random\Engine\Secureclass introduced in PHP 8.2 (check arokettu/random-polyfill for more engines); - the
odbc_connection_string_is_quotedfunction introduced in PHP 8.2; - the
odbc_connection_string_should_quotefunction introduced in PHP 8.2; - the
odbc_connection_string_quotefunction introduced in PHP 8.2; - the
ini_parse_quantityfunction introduced in PHP 8.2; - the
CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256constant introduced in PHP 8.1 when curl 7.50+ is used; - the
json_validatefunction introduced in PHP 8.3; - the
Overrideattribute introduced in PHP 8.3; - the
mb_str_padfunction introduced in PHP 8.3; - the
ldap_exop_syncfunction introduced in PHP 8.3; - the
ldap_connect_walletfunction introduced in PHP 8.3; - the
stream_context_set_optionsfunction introduced in PHP 8.3; - the
str_incrementandstr_decrementfunctions introduced in PHP 8.3; - the
Date*Exception/Errorclasses introduced in PHP 8.3; - the
SQLite3Exceptionclass introduced in PHP 8.3; - the
mb_ucfirstandmb_lcfirstfunctions introduced in PHP 8.4; - the
array_find,array_find_key,array_anyandarray_allfunctions introduced in PHP 8.4; - the
Deprecatedattribute introduced in PHP 8.4; - the
mb_trim,mb_ltrimandmb_rtrimfunctions introduced in PHP 8.4; - the
ReflectionConstantclass introduced in PHP 8.4 - the
CURL_HTTP_VERSION_3andCURL_HTTP_VERSION_3ONLYconstants introduced in PHP 8.4; - the
grapheme_str_splitfunction introduced in PHP 8.4; - the
bcceil,bcdivmod,bcfloorandbcroundfunctions introduced in PHP 8.4; - the
PDOdriver specific sub-classes introduced in PHP 8.4; - the
get_error_handlerandget_exception_handlerfunctions introduced in PHP 8.5; - the
NoDiscardattribute introduced in PHP 8.5; - the
array_firstandarray_lastfunctions introduced in PHP 8.5; - the
DelayedTargetValidationattribute introduced in PHP 8.5; - the
Filter\FilterExceptionclass introduced in PHP 8.5; - the
Filter\FilterFailedExceptionclass introduced in PHP 8.5; - the
grapheme_levenshteinfunction introduced in PHP 8.5; - the
locale_is_right_to_leftfunction introduced in PHP 8.5; - the
clampfunction introduced in PHP 8.6; - the
ARRAY_FILTER_USE_VALUEconstant introduced in PHP 8.6; - the
SortDirectionenum introduced in PHP 8.6; - the
grapheme_strrevfunction introduced in PHP 8.6;
It is strongly recommended to upgrade your PHP version and/or install the missing extensions whenever possible. This polyfill should be used only when there is no better choice or when portability is a requirement.
Polyfills target the API of the latest PHP version and backport it to older ones. The goal is that code written for a recent PHP runs unchanged on the oldest supported version; it is not to reproduce the historical behavior of every intermediate version. In practice:
- New functions, classes, constants and arguments are backported; removed or
legacy behavior is not. For example, the
is_hexargument thatmb_decode_numericentity()lost in PHP 8.0 is not accepted by the polyfill. - A symbol is backported only when defining it carries the native effect.
A constant whose sole purpose is to switch on behavior in a function that
cannot be polyfilled is left undefined, so its absence stays usable for feature
detection, e.g.
FILTER_THROW_ON_FAILURE, which only configuresfilter_var(). Declarative symbols such as attributes are polyfilled even when their runtime effect needs engine support, since reflection still conveys their semantics. - A polyfill runs only when the native symbol is missing, so it reproduces the
contract of the function it shims rather than a blanket "PHP 7" or "PHP 8"
behavior. Functions that always raised a
ValueErroron invalid input throw on every supported version (aValueErrorstub is declared on PHP < 8 where needed); functions whose native contract returnedfalsekeep returningfalse. - The signatures declared by the bootstrap files match the native signature of
the PHP version being run, so the polyfill stays a drop-in that the engine can
supersede. New arguments that cannot be implemented are accepted and ignored,
e.g. the
$localeargument added to thegrapheme_*()functions in PHP 8.5. - Extensions that were never bundled with PHP, such as
uuidanddeepclone, follow the extension's own release history rather than PHP's. Since a polyfill cannot influenceextension_loaded()nor conditionally define constants, it mirrors the newest native state, including deprecations:UUID_TYPE_DCEandUUID_TYPE_NAMEare defined with aDeprecatedattribute on PHP 8.5+. - When a function is provided by both an extension polyfill (
Mbstring) and a version polyfill (Php74,Php83,Php84), both implementations must behave identically, because either one may end up registered depending on the PHP version and whether the extension is loaded.
To write portable code between PHP5 and PHP7, some care must be taken:
\*Errorexceptions must be caught before\Exception;- after calling
error_clear_last(), the result of$e = error_get_last()must be verified usingisset($e['message'][0])instead ofnull !== $e.
When using Composer to manage your dependencies, you
should not require the symfony/polyfill package, but the standalone ones:
symfony/polyfill-apcufor using theapcu_*functions,symfony/polyfill-ctypefor using the ctype functions,symfony/polyfill-deepclonefor using thedeepclone_*functions,symfony/polyfill-php54for using the PHP 5.4 functions,symfony/polyfill-php55for using the PHP 5.5 functions,symfony/polyfill-php56for using the PHP 5.6 functions,symfony/polyfill-php70for using the PHP 7.0 functions,symfony/polyfill-php71for using the PHP 7.1 functions,symfony/polyfill-php72for using the PHP 7.2 functions,symfony/polyfill-php73for using the PHP 7.3 functions,symfony/polyfill-php74for using the PHP 7.4 functions,symfony/polyfill-php80for using the PHP 8.0 functions,symfony/polyfill-php81for using the PHP 8.1 functions,symfony/polyfill-php82for using the PHP 8.2 functions,symfony/polyfill-php83for using the PHP 8.3 functions,symfony/polyfill-php84for using the PHP 8.4 functions,symfony/polyfill-php85for using the PHP 8.5 functions,symfony/polyfill-iconvfor using the iconv functions,symfony/polyfill-intl-graphemefor using thegrapheme_*functions,symfony/polyfill-intl-idnfor using theidn_to_asciiandidn_to_utf8functions,symfony/polyfill-intl-icufor using the intl functions and classes,symfony/polyfill-intl-messageformatterfor using the intl messageformatter,symfony/polyfill-intl-normalizerfor using the intl normalizer,symfony/polyfill-mbstringfor using the mbstring functions,symfony/polyfill-utilfor using the polyfill utility helpers.symfony/polyfill-uuidfor using theuuid_*functions,
Requiring symfony/polyfill directly would prevent Composer from sharing
correctly polyfills in dependency graphs. As such, it would likely install
more code than required.
This package is designed for low overhead and high quality polyfilling.
It adds only a few lightweight require statements to the bootstrap process
to support all polyfills. Implementations are then loaded on-demand when
needed during code execution.
If your project requires a minimum PHP version it is advisable to add polyfills
for lower PHP versions to the replace section of your composer.json.
This removes any overhead from these polyfills as they are no longer part of your project.
The same can be done for polyfills for extensions that you require.
If your project requires php 7.0, and needs the mb extension, the replace section would look something like this:
{
"replace": {
"symfony/polyfill-php54": "*",
"symfony/polyfill-php55": "*",
"symfony/polyfill-php56": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-mbstring": "*"
}
}Polyfills are unit-tested alongside their native implementation so that feature and behavior parity can be proven and enforced in the long run.
This library is released under the MIT license.