Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Polyfill Php71 Laravel Package

symfony/polyfill-php71

Symfony polyfill backporting PHP 7.1 features—like the iterable pseudo-type—to older runtimes (PHP 5.3+). It lets libraries and frameworks use newer syntax while remaining compatible with legacy PHP installations.

View on GitHub
Deep Wiki
Context7

Getting Started

First: decide whether you need it at all. This polyfill only exists to make a handful of PHP 7.1 runtime features available on PHP 7.0. Every Laravel version you can realistically install (5.5 → 12) either runs on PHP 8.x or has an official minimum well above 7.1, so on a modern app this package is dead weight that arrived transitively through some Symfony component. Audit it before touching it:

php -v                                                    # expect 8.1+
composer why symfony/polyfill-php71                       # who actually pulled it in
composer show symfony/polyfill-php71                      # confirm it's installed & version

If php -v is ≥ 7.1 and nothing in composer why output is a hard requirement you can't drop, remove it and re-run your test suite:

composer remove symfony/polyfill-php71

Where to look first if you do need it (i.e. you maintain a package or legacy app targeting PHP 7.0):

  • vendor/symfony/polyfill-php71/bootstrap.php — this is the whole point of the package. Composer's files autoload includes it on every request; it short-circuits with if (\PHP_VERSION_ID >= 70100) return;, so on native PHP 7.1+ it costs essentially nothing.
  • vendor/symfony/polyfill-php71/Php71.php — the Symfony\Polyfill\Php71\Php71 helper class containing the actual implementations (isIterable(), plus floating-point constant values). It is marked @internal.

Scope reality check — the package gives you exactly two things:

  1. A global is_iterable() function (backed by Php71::isIterable()).
  2. The PHP_FLOAT_DIG, PHP_FLOAT_EPSILON, PHP_FLOAT_MIN, PHP_FLOAT_MAX constants.

Everything else people associate with 7.1 — void return types, iterable type declarations, nullable ?Type hints, class-constant visibility, symmetric array destructuring, Closure::fromCallable() — is parser/engine level and cannot be backported. If your first use case is "I want to write iterable $items and still support 7.0," this package does not solve that.

First realistic use case: you maintain a Laravel package with "php": "^7.0|^8.0" in composer.json and you want a single runtime check for "array or Traversable" without hand-rolling it in every guard clause.

Implementation Patterns

Call the global function, not the class. The Php71 class is internal and bypasses the native implementation; the global function is native on 7.1+ and polyfilled below:

// Good — resolves to natively on 7.1+, polyfilled on 7.0
if (is_iterable($payload)) {
    foreach ($payload as $item) { /* ... */ }
}

// Works everywhere but always goes through userland on 7.0-7.1... and 8.x
if (\Symfony\Polyfill\Php71\Php71::isIterable($payload)) { /* ... */ }

Unqualified calls inside a namespace fall back to the global function, so is_iterable($x) inside App\Support\... is fine — you do not need a use function statement.

Require it in require, never require-dev. A polyfill is runtime code. For a package:

"require": {
    "php": "^7.0|^8.0",
    "symfony/polyfill-php71": "^1.0"
}

Composer's files autoload mechanism is what defines the function, so after adding or removing it always run composer dump-autoload -o; a stale autoload_files.php is the usual cause of "Call to undefined function is_iterable()" in CI.

Declare types you can't enforce in docblocks. Since iterable hints won't parse on 7.0, the pattern is docblock + runtime guard:

/**
 * @param iterable $rows
 * @return array
 */
public function normalize($rows)
{
    if (!is_iterable($rows)) {
        throw new \InvalidArgumentException('Expected iterable.');
    }
    return is_array($rows) ? $rows : iterator_to_array($rows);
}

Floating-point constants are defined globally by bootstrap.php behind defined() guards, so you reference them as plain constants — no import, no wrapper:

$epsilon = PHP_FLOAT_EPSILON;   // 2.22044604925031E-16
$digits  = PHP_FLOAT_DIG;       // 15
if (abs($a - $b) < PHP_FLOAT_EPSILON) { /* equal */ }

This is the common case in Laravel: money/geo/statistics code in a domain service that must run on an old host.

Feature-detection over version sniffing. If you're bridging a codebase across many PHP versions, guard on capability, not PHP_VERSION_ID:

if (function_exists('is_iterable')) { /* ... */ }
// or, for constants:
defined('PHP_FLOAT_EPSILON') || define('PHP_FLOAT_EPSILON', 2.220446049250313E-16);

Testing pattern. Add PHP 7.0 to your CI matrix (e.g. shivammathur/setup-php with php-version: 7.0) alongside 8.3. That's the only place the polyfill path actually executes — on 8.x your tests exercise the native path and will silently never touch the backport.

Gotchas and Tips

  • The polyfill cannot backport syntax. iterable $x, : void, ?string $x, [$a, $b] = $pair, Closure::fromCallable(), public const — all of these produce parse errors on PHP 7.0, not runtime failures, so no polyfill of any kind can help. Plan your minimum PHP accordingly; this package only helps with the runtime surface listed above.
  • is_iterable() is subtly broader than people assume. It returns true for arrays, Iterator, IteratorAggregate, Generator, and any Traversable. It returns false for plain stdClass and for JsonSerializable that isn't also Traversable — a common Laravel-era bug when people expect JSON-castable models to "just work."
  • Function polyfills are defined at Composer autoload time, not class-load time. Any code that runs before vendor/autoload.php is included (e.g. a phpunit.xml bootstrap that does raw file includes, or an artisan command bootstrapped oddly) will not have is_iterable(). If PHPUnit's bootstrap attribute points at something other than vendor/autoload.php, chain the autoload in.
  • Function mocking in tests. Functions\expect('is_iterable') (php-mock, Mockery aliases, or Brain Monkey) will shadow the polyfilled global. On PHP 7.0 the polyfill defines it as a real function first, which can cause "cannot redeclare" if your mocking layer defines it unconditionally — guard with function_exists.
  • PHP_FLOAT_MIN/MAX are absolute-value bounds. PHP_FLOAT_MAX is the largest finite double, PHP_FLOAT_MIN is the smallest positive normalized double (not the most negative). Don't use PHP_FLOAT_MIN as a clamp floor for negative numbers.
  • Opcache preloading: preloaded scripts execute before the autoload files bootstrap in some server configurations. If you preload a class whose top-level code calls is_iterable(), you'll get a fatal error on PHP 7.0. Keep preloading limited to classes without top-level function calls.
  • It is a leaf dependency — there are no extension points. No container binding, no config, no service provider, no strategy interface. If you need behaviour beyond is_iterable + float constants, fork the two files into your own support package rather than expecting configurability.
  • Don't add it to a Laravel 9+/Symfony 6+ app "just in case." If composer why shows nothing requires it, keeping it means an extra autoload file on every request and a dead entry in your SBOM. Conversely, if you're pruning: use composer remove (not manual composer.json edits) so the lock file and autoload_files.php stay consistent, and run the full test suite afterwards — occasionally a package declares the polyfill only in require-dev of a dependency and silently relies on it in production code.
  • Debugging undefined-function errors: composer dump-autoload, then php -r "var_dump(function_exists('is_iterable'), defined('PHP_FLOAT_EPSILON'));". If false, the bootstrap file isn't in vendor/composer/autoload_files.php — usually a corrupted lock file or an --no-scripts install.
  • Version pinning: stay on ^1.0. The polyfill API surface is frozen; there is no 2.x, and Symfony has effectively stopped adding features to the php7x polyfills, so upgrades are only ever security/consistency patches. Verify with composer outdated --direct rather than expecting changelog excitement.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource