symfony/polyfill-php80
Backport of PHP 8.0 core features for older runtimes. Adds Stringable, fdiv, ValueError/UnhandledMatchError, FILTER_VALIDATE_BOOL, get_debug_type, PhpToken, preg_last_error_msg, str_contains/starts_with/ends_with, and get_resource_id.
Installation:
composer require symfony/polyfill-php80
Add to composer.json under require or require-dev based on your needs.
First Use Case: Replace legacy string checks with modern PHP 8.0+ methods:
// Before (PHP 7.4)
if (strpos($string, 'admin') !== false) {
// Handle match
}
// After (works on PHP 7.2+ with polyfill)
if (str_contains($string, 'admin')) {
// Handle match
}
Verify Compatibility: Check if your environment supports the polyfill by running:
php -r "echo PHP_VERSION; var_dump(class_exists('Stringable'));"
Should output 7.2–8.0 and true for Stringable.
str_contains, ValueError).php artisan test to ensure polyfilled methods work as expected across your PHP version range.String Manipulation:
Replace strpos()/substr() checks with polyfilled methods:
// Validation in Laravel Form Requests
public function rules()
{
return [
'input' => ['string', function ($attribute, $value, $fail) {
if (str_contains($value, 'admin')) {
$fail('Admin keywords not allowed.');
}
}],
];
}
Type Safety with Stringable:
Use in DTOs or API responses to enforce type consistency:
class ApiResponse implements Stringable
{
public function __toString(): string
{
return json_encode($this->data);
}
}
Error Handling:
Replace custom InvalidArgumentException with ValueError:
public function parseInput($input)
{
if (!is_string($input)) {
throw new ValueError('Input must be a string.');
}
// ...
}
Floating-Point Math:
Use fdiv() for precise division (avoids PHP 7.x’s div precision issues):
$result = fdiv(1, 3); // Returns 0.3333333333333333 instead of 0.33333333333333331
Regex Error Handling:
Catch regex errors with preg_last_error_msg():
if (!preg_match('/pattern/', $input)) {
$error = preg_last_error_msg();
Log::error("Regex failed: {$error}");
}
Incremental Adoption:
str_contains in validation).strpos → str_starts_with).if (PHP_VERSION >= 8.0) checks temporarily to isolate polyfill-dependent code.Laravel Package Development:
// In a validation rule package
if (str_contains($value, 'invalid')) {
return false;
}
composer.json.Testing Across PHP Versions:
phpunit.xml to test on multiple PHP versions:
<php>
<env name="PHP_VERSION" value="7.4"/>
<env name="PHP_VERSION" value="8.0"/>
</php>
str_contains, ValueError).Avoid Conflicts:
grep -r "str_contains\|ValueError\|Stringable" app/
MyValueError → CustomValueError).Performance Considerations:
fdiv in financial calculations).IDE Support:
@phpstan-ignore-next-line for static analysis tools if they flag polyfilled types.Dependency Management:
composer.json for stability:
"symfony/polyfill-php80": "^1.35"
Custom Implementations:
str_contains() or ValueError before the polyfill loads.composer.json:
"autoload": {
"psr-4": {
"App\\": "app/",
"Symfony\\Polyfill\\": "vendor/symfony/polyfill-php80/"
}
}
Type System Quirks:
Stringable polyfill may not work with PHP 7.4’s type system (e.g., return type hints).if (interface_exists('Stringable') && $obj instanceof Stringable) {
// Safe to use __toString()
}
Precision Warnings:
fdiv() may still have precision limitations in PHP 7.x (not identical to PHP 8.0’s native fdiv).fdiv(1, 10)) and document limitations.Regex Edge Cases:
preg_last_error_msg() may not cover all regex errors (e.g., stack overflows).preg_last_error() for unsupported cases.Laravel Service Providers:
use Symfony\Polyfill\Php80\Stringable;
Verify Polyfill Loading:
var_dump(function_exists('str_contains')); // Should return true
composer show symfony/polyfill-php80 to confirm installation.Common Errors:
composer dump-autoload).str_contains requires PHP 7.2+).@phpstan-ignore-line for static analysis tools.Performance Profiling:
$start = microtime(true);
str_contains($haystack, $needle);
$time = microtime(true) - $start;
Leverage match Expressions:
UnhandledMatchError for exhaustive match expressions (PHP 8.0+):
$result = match ($status) {
'active' => 'Active',
'inactive' => 'Inactive',
default => throw new UnhandledMatchError($status),
};
Validation Shortcuts:
FILTER_VALIDATE_BOOL for boolean input parsing:
$isActive = filter_var($input, FILTER_VALIDATE_BOOL);
Debugging with get_debug_type:
gettype() with get_debug_type() for clearer output:
dd(get_debug_type($variable)); // e.g., "array(3)" instead of "array"
Resource Handling:
get_resource_id() for resource comparison:
if (get_resource_id($resource1)
How can I help you explore Laravel packages today?