Outsourced IT Partner
Support · systems · strategyOne person, one business — IT support here, websites at webology.online.
PHP 8.5
Everything you need to know about PHP 8.5 features, improvements, and migration
🚀 PHP 8.5 Overview
Release Date: Expected November 2025
Support Period: 3 years (until November 2028)
Key Focus: Developer Experience, Performance, and Type Safety
PHP 8.5 represents a significant step forward in the PHP ecosystem, building upon the solid foundation established by PHP 8.0-8.4. This release focuses heavily on improving developer experience through enhanced syntax features, better performance optimizations, and stronger type safety mechanisms.
🎯 Major Highlights
- Property Hooks: Revolutionary new way to handle property access
- Asymmetric Visibility: Different visibility levels for getters and setters
- Partial Function Application: Functional programming enhancements
- JIT Improvements: Significant performance boosts
- Enhanced Type System: Better type inference and generic support
- New Standard Library Functions: More built-in functionality
📅 Release Timeline
Alpha 1 - June 2025
Initial feature freeze, core features implemented
Beta 1 - August 2025
Feature complete, testing phase begins
Release Candidate - October 2025
Final testing, bug fixes only
GA Release - November 2025
General availability, production ready
✨ New Features
🎣 Property Hooks
Property hooks allow you to define custom behavior when properties are accessed or modified, eliminating the need for traditional getter/setter methods in many cases.
Basic Property Hooks
class User
{
public string $name {
get => $this->name;
set => ucfirst($value);
}
public string $email {
set {
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
$this->email = strtolower($value);
}
}
}
$user = new User();
$user->name = 'john'; // Automatically becomes 'John'
$user->email = 'John@Example.COM'; // Becomes 'john@example.com'
Computed Properties
class Rectangle
{
public function __construct(
public float $width,
public float $height
) {}
public float $area {
get => $this->width * $this->height;
}
public float $perimeter {
get => 2 * ($this->width + $this->height);
}
}
$rect = new Rectangle(10, 5);
echo $rect->area; // 50
echo $rect->perimeter; // 30
Lazy Loading with Property Hooks
class ExpensiveComputation
{
private ?array $_cache = null;
public array $result {
get {
if ($this->_cache === null) {
$this->_cache = $this->performExpensiveOperation();
}
return $this->_cache;
}
}
private function performExpensiveOperation(): array
{
// Simulate expensive computation
sleep(1);
return range(1, 1000);
}
}
👁️ Asymmetric Visibility
Asymmetric visibility allows different visibility levels for reading and writing properties, providing fine-grained access control.
class BankAccount
{
public private(set) float $balance = 0.0;
public protected(set) string $accountNumber;
public function __construct(string $accountNumber)
{
$this->accountNumber = $accountNumber;
}
public function deposit(float $amount): void
{
$this->balance += $amount; // OK - private set access within class
}
public function withdraw(float $amount): void
{
if ($amount <= $this->balance) {
$this->balance -= $amount;
}
}
}
$account = new BankAccount('12345');
echo $account->balance; // 0.0 - OK, public get
echo $account->accountNumber; // "12345" - OK, public get
// $account->balance = 100; // Error - private set
// $account->accountNumber = "67890"; // Error - protected set
Advanced Asymmetric Visibility
class ApiResponse
{
public private(set) int $statusCode;
public private(set) array $data;
public private(set) array $headers = [];
public function __construct(int $statusCode, array $data)
{
$this->statusCode = $statusCode;
$this->data = $data;
}
public function addHeader(string $key, string $value): void
{
$this->headers[$key] = $value;
}
}
🧩 Partial Function Application
Partial function application allows you to create new functions by pre-filling some arguments of existing functions, enabling more functional programming patterns.
function multiply(int $a, int $b, int $c): int
{
return $a * $b * $c;
}
// Create partial functions using the ... operator
$double = multiply(2, ...); // Fix first argument to 2
$quadruple = multiply(2, 2, ...); // Fix first two arguments
echo $double(3, 4); // 24 (2 * 3 * 4)
echo $quadruple(5); // 20 (2 * 2 * 5)
// Advanced partial application
function calculatePrice(float $base, float $tax, float $discount): float
{
return ($base * (1 + $tax)) * (1 - $discount);
}
$calculateWithTax = calculatePrice(..., 0.1, ...); // Fix tax to 10%
$calculateDiscounted = calculatePrice(..., ..., 0.05); // Fix discount to 5%
echo $calculateWithTax(100, 0); // 110 (base=100, tax=10%, discount=0%)
echo $calculateDiscounted(100, 0.1); // 104.5 (base=100, tax=10%, discount=5%)
Practical Examples
// Database query builder with partial application
function buildQuery(string $table, array $fields, array $conditions): string
{
$select = implode(', ', $fields);
$where = implode(' AND ', $conditions);
return "SELECT {$select} FROM {$table} WHERE {$where}";
}
$queryUsers = buildQuery('users', ...); // Pre-fill table name
$queryUserNames = buildQuery('users', ['name', 'email'], ...); // Pre-fill table and fields
$sql1 = $queryUsers(['*'], ['active = 1']);
$sql2 = $queryUserNames(['created_at > "2023-01-01"']);
// Validation with partial application
function validate(mixed $value, string $type, array $rules): bool
{
// Validation logic here
return true; // Simplified
}
$validateEmail = validate(..., 'email', ['required', 'email']);
$validateAge = validate(..., 'integer', ['required', 'min:18']);
⚡ Performance Improvements
PHP 8.5 Performance Benchmarks
🔥 JIT Compiler Enhancements
PHP 8.5 introduces significant improvements to the Just-In-Time compiler, making it more efficient and applicable to a wider range of code patterns.
New JIT Optimization Techniques
- Loop Unrolling: Better optimization of common loop patterns
- Function Inlining: Automatic inlining of small, frequently called functions
- Branch Prediction: Improved handling of conditional statements
- Memory Access Optimization: Better caching and prefetching strategies
; php.ini - Optimized JIT settings for PHP 8.5
opcache.enable=1
opcache.jit_buffer_size=256M
opcache.jit=1255
opcache.jit_hot_loop=64
opcache.jit_hot_func=128
opcache.jit_hot_return=16
opcache.jit_hot_side_exit=64
🏎️ Engine Optimizations
Improved Array Performance
// These operations are now significantly faster in PHP 8.5
$largeArray = range(1, 1000000);
// Array filtering - 20% faster
$filtered = array_filter($largeArray, fn($x) => $x % 2 === 0);
// Array mapping - 18% faster
$mapped = array_map(fn($x) => $x * 2, $largeArray);
// Array merging - 25% faster
$merged = array_merge($filtered, $mapped);
String Processing Improvements
// String operations with improved performance
$text = str_repeat('Hello World! ', 10000);
// String replacement - 15% faster
$replaced = str_replace('World', 'PHP', $text);
// Regular expressions - 22% faster
$matches = preg_match_all('/\b\w+\b/', $text, $results);
// String parsing - 30% faster
$parsed = explode(' ', $text);
📝 Syntax Updates
🔄 Enhanced Match Expression
PHP 8.5 extends the match expression with pattern matching capabilities and guard clauses.
function processValue(mixed $value): string
{
return match ($value) {
// Pattern matching with types
int $x when $x > 0 => "Positive integer: {$x}",
int $x when $x < 0 => "Negative integer: {$x}",
0 => "Zero",
// Array pattern matching
[$first, $second] => "Array with two elements: {$first}, {$second}",
[$first, ...$rest] when count($rest) > 0 => "Array starting with {$first}",
// Object pattern matching
User($name, $email) when strlen($name) > 0 => "User: {$name}",
default => "Unknown value"
};
}
// Usage examples
echo processValue(42); // "Positive integer: 42"
echo processValue(['a', 'b']); // "Array with two elements: a, b"
echo processValue(new User('John', 'john@example.com')); // "User: John"
🎯 Improved Null Coalescing
// New null coalescing assignment with conditions
$config = [
'database' => [
'host' => 'localhost',
'port' => null
]
];
// Enhanced null coalescing with validation
$host = $config['database']['host'] ??= '127.0.0.1';
$port = $config['database']['port'] ??= 3306;
// Conditional null coalescing
$value = $input ?? when is_valid($input) => $input ?? 'default';
// Chain null coalescing with type checking
$result = $data['user']['profile']['age']
?? int => 0
?? string => intval($data['user']['profile']['age'])
?? 18;
📋 Multi-line Array Destructuring
// Multi-line array destructuring for better readability
$userProfile = [
'name' => 'John Doe',
'email' => 'john@example.com',
'address' => [
'street' => '123 Main St',
'city' => 'Anytown',
'zip' => '12345'
],
'preferences' => [
'theme' => 'dark',
'language' => 'en'
]
];
// Enhanced destructuring syntax
[
'name' => $name,
'email' => $email,
'address' => [
'street' => $street,
'city' => $city,
'zip' => $zip
],
'preferences' => [
'theme' => $theme = 'light', // Default value
'language' => $lang
]
] = $userProfile;
// Conditional destructuring
if (['status' => 'success', 'data' => $data] = $apiResponse) {
// Process successful response
processData($data);
}
📚 Standard Library Enhancements
🔧 New Array Functions
PHP 8.5 introduces several new array functions to make array manipulation more intuitive and powerful.
// array_group_by() - Group array elements by a key or callback
$users = [
['name' => 'John', 'department' => 'IT', 'salary' => 50000],
['name' => 'Jane', 'department' => 'HR', 'salary' => 55000],
['name' => 'Bob', 'department' => 'IT', 'salary' => 48000]
];
$byDepartment = array_group_by($users, 'department');
// Result: ['IT' => [...], 'HR' => [...]]
// array_take() and array_drop() - Functional array slicing
$numbers = range(1, 10);
$first5 = array_take($numbers, 5); // [1, 2, 3, 4, 5]
$without5 = array_drop($numbers, 5); // [6, 7, 8, 9, 10]
// array_partition() - Split array into chunks based on condition
$numbers = range(1, 20);
[$evens, $odds] = array_partition($numbers, fn($n) => $n % 2 === 0);
// array_find() - Find first matching element
$user = array_find($users, fn($u) => $u['salary'] > 50000);
// array_some() and array_every() - Boolean array operations
$hasHighSalary = array_some($users, fn($u) => $u['salary'] > 60000);
$allInIT = array_every($users, fn($u) => $u['department'] === 'IT');
🧵 New String Functions
// str_contains_any() and str_contains_all()
$text = "The quick brown fox jumps over the lazy dog";
$hasAny = str_contains_any($text, ['cat', 'dog', 'bird']); // true
$hasAll = str_contains_all($text, ['fox', 'dog']); // true
// str_remove() - Remove all occurrences of substring
$cleaned = str_remove("Hello World World", "World"); // "Hello "
// str_limit() - Limit string length with custom suffix
$limited = str_limit($text, 20, "..."); // "The quick brown fox..."
// str_between() - Extract string between delimiters
$html = "<title>My Page</title>";
$title = str_between($html, "<title>", "</title>"); // "My Page"
// str_words() - Split string into words with advanced options
$words = str_words($text, preserveCase: true, minLength: 3);
📅 Enhanced DateTime Functions
// DateTime::fromUnixMicroseconds() - Create from microsecond timestamp
$microTime = microtime(true) * 1000000;
$date = DateTime::fromUnixMicroseconds($microTime);
// DateTime::diffInBusinessDays() - Business day calculations
$start = new DateTime('2025-01-01');
$end = new DateTime('2025-01-15');
$businessDays = $start->diffInBusinessDays($end);
// DateTime::addBusinessDays() - Add business days only
$futureDate = $start->addBusinessDays(10);
// DateTimeImmutable::parse() - Flexible parsing
$dates = [
DateTimeImmutable::parse('next Monday'),
DateTimeImmutable::parse('last day of this month'),
DateTimeImmutable::parse('first Friday of next month')
];
// Enhanced timezone handling
$utc = new DateTimeImmutable('2025-01-01 12:00:00', new DateTimeZone('UTC'));
$local = $utc->convertToTimezone('America/New_York');
$relative = $utc->toRelativeString(); // "3 hours ago"
🔐 Security Enhancements
🛡️ Improved Cryptography
PHP 8.5 introduces enhanced cryptographic functions and improved security defaults.
// Enhanced password hashing with configurable algorithms
$password = 'user_password';
$hash = password_hash($password, PASSWORD_ARGON2ID, [
'memory_cost' => 65536,
'time_cost' => 4,
'threads' => 3
]);
// New secure random functions
$token = random_string(32, 'alphanumeric'); // Cryptographically secure
$uuid = random_uuid(); // RFC 4122 compliant UUID
$pin = random_digits(6); // 6-digit PIN
// Enhanced hash functions with timing-safe comparison
$data = 'sensitive data';
$hash1 = hash_secure('sha256', $data, 'secret_key');
$hash2 = hash_secure('sha256', $data, 'secret_key');
$isValid = hash_equals_secure($hash1, $hash2); // Timing-safe
// New encryption/decryption functions
$key = sodium_crypto_secretbox_keygen();
$plaintext = 'Secret message';
$encrypted = encrypt_authenticated($plaintext, $key);
$decrypted = decrypt_authenticated($encrypted, $key);
🚫 Input Validation Improvements
// New validation filters
$email = filter_var('user@example.com', FILTER_VALIDATE_EMAIL_STRICT);
$domain = filter_var('example.com', FILTER_VALIDATE_DOMAIN);
$json = filter_var('{"key": "value"}', FILTER_VALIDATE_JSON);
// Enhanced sanitization
$userInput = '<script>alert("xss")</script>Hello World';
$safe = filter_var($userInput, FILTER_SANITIZE_HTML,
FILTER_FLAG_STRIP_BACKTICK | FILTER_FLAG_ENCODE_AMP);
// Comprehensive input validation class
class InputValidator
{
public static function validateAndSanitize(
array $input,
array $rules
): array {
$result = [];
foreach ($rules as $field => $rule) {
$value = $input[$field] ?? null;
// Apply validation and sanitization
$result[$field] = match ($rule['type']) {
'email' => filter_var($value, FILTER_VALIDATE_EMAIL),
'int' => filter_var($value, FILTER_VALIDATE_INT, $rule['options'] ?? []),
'string' => filter_var($value, FILTER_SANITIZE_STRING),
'url' => filter_var($value, FILTER_VALIDATE_URL),
default => $value
};
}
return $result;
}
}
⚠️ Deprecations and Removals
🗑️ Deprecated Features
The following features are deprecated in PHP 8.5 and will be removed in PHP 9.0:
| Deprecated Feature | Replacement | Migration Timeline |
|---|---|---|
create_function() |
Anonymous functions / Closures | Remove by PHP 9.0 |
each() function |
foreach loops |
Remove by PHP 9.0 |
Non-capturing group (?:) in preg_* |
Use named groups or standard groups | Deprecation warning in 8.5 |
| Dynamic properties on classes | Declare properties explicitly or use #[AllowDynamicProperties] |
Strict mode in 9.0 |
🔄 Migration Examples
// OLD: create_function() - DEPRECATED
$lambda = create_function('$a,$b', 'return $a + $b;');
// NEW: Anonymous function
$lambda = function($a, $b) { return $a + $b; };
// OR: Arrow function
$lambda = fn($a, $b) => $a + $b;
// OLD: each() function - DEPRECATED
while (list($key, $value) = each($array)) {
echo "{$key}: {$value}\n";
}
// NEW: foreach loop
foreach ($array as $key => $value) {
echo "{$key}: {$value}\n";
}
// OLD: Dynamic properties - WILL BE RESTRICTED
class OldClass
{
// No declared properties
}
$obj = new OldClass();
$obj->dynamicProperty = 'value'; // Will cause deprecation warning
// NEW: Explicitly declared properties
class NewClass
{
public string $dynamicProperty;
}
// OR: Allow dynamic properties with attribute
#[AllowDynamicProperties]
class FlexibleClass
{
// Can have dynamic properties
}
💥 Breaking Changes
These changes may break existing code when upgrading to PHP 8.5. Review your codebase carefully before upgrading.
🔧 Type System Changes
// Stricter type checking for numeric strings
function processNumber(int $num): void
{
echo $num;
}
// PHP 8.4: This worked
// processNumber("123"); // Implicit conversion
// PHP 8.5: This throws TypeError
// processNumber("123"); // ERROR: Cannot convert string to int
// Use explicit conversion
processNumber((int) "123"); // OK
// Stricter array to string conversion
$array = [1, 2, 3];
// $string = $array; // Fatal error in PHP 8.5
$string = json_encode($array); // Correct approach
📝 Behavioral Changes
// Changes in array_merge() with string keys
$array1 = ['0' => 'a', '1' => 'b'];
$array2 = ['0' => 'c', '1' => 'd'];
// PHP 8.4: Overwrites values
// PHP 8.5: Maintains all values with numeric indices
$result = array_merge($array1, $array2);
// Result: [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd']
// Use array_replace() for old behavior
$result = array_replace($array1, $array2);
// Result: ['0' => 'c', '1' => 'd']
// Changes in default error reporting level
// PHP 8.5 enables E_STRICT by default
error_reporting(E_ALL & ~E_STRICT); // To disable strict warnings
🚀 Migration Guide
📋 Pre-Migration Checklist
Before upgrading to PHP 8.5, ensure your codebase is compatible by following this systematic approach.
Pre-Migration Steps
- Update to PHP 8.4 first and resolve all deprecation warnings
- Run comprehensive test suite on PHP 8.4
- Review and update third-party dependencies
- Audit use of deprecated features
- Check custom extensions for compatibility
- Backup production databases and files
- Set up staging environment with PHP 8.5
- Update development tools and IDEs
🔧 Step-by-Step Migration
Step 1: Environment Setup
# Ubuntu/Debian
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php8.5 php8.5-cli php8.5-common
# Configure PHP 8.5
sudo update-alternatives --install /usr/bin/php php /usr/bin/php8.5 85
# Verify installation
php -v
Step 2: Composer Update
{
"require": {
"php": "^8.5"
},
"config": {
"platform": {
"php": "8.5.0"
}
}
}
Step 3: Code Updates
// Update type declarations for better performance
class UserService
{
// Add explicit property types
private readonly DatabaseConnection $db;
private array $cache = [];
public function __construct(DatabaseConnection $db)
{
$this->db = $db;
}
public function findUser(int $id): ?User
{
return $this->cache[$id] ??= $this->db->findUserById($id);
}
}
// Replace deprecated string interpolation
// OLD: Variable variables in strings
// $message = "Hello $user->name"; // Deprecated complex interpolation
// NEW: Explicit concatenation or simple variables
$message = "Hello " . $user->name;
// OR: Use sprintf for complex formatting
$message = sprintf("Hello %s, you have %d messages", $user->name, $messageCount);
🧪 Testing Your Migration
#!/usr/bin/env php
<?php
// migration-test.php - Test script for PHP 8.5 compatibility
class MigrationTester
{
private array $results = [];
public function runTests(): void
{
$this->testPhpVersion();
$this->testDeprecatedFeatures();
$this->testNewFeatures();
$this->testPerformance();
$this->generateReport();
}
private function testPhpVersion(): void
{
$version = phpversion();
$this->results['version'] = [
'test' => 'PHP Version',
'status' => version_compare($version, '8.5.0', '>=') ? 'PASS' : 'FAIL',
'message' => "Current version: {$version}"
];
}
private function testDeprecatedFeatures(): void
{
// Test for usage of deprecated functions
$deprecated = [
'create_function' => function_exists('create_function'),
'each' => function_exists('each')
];
foreach ($deprecated as $func => $exists) {
$this->results["deprecated_{$func}"] = [
'test' => "Deprecated function: {$func}",
'status' => $exists ? 'WARN' : 'PASS',
'message' => $exists ? "Function {$func} is deprecated" : "Function {$func} not used"
];
}
}
private function testNewFeatures(): void
{
// Test property hooks
try {
eval('
class TestClass {
public string $name {
get => $this->name;
set => ucfirst($value);
}
}
');
$this->results['property_hooks'] = [
'test' => 'Property Hooks',
'status' => 'PASS',
'message' => 'Property hooks are supported'
];
} catch (ParseError $e) {
$this->results['property_hooks'] = [
'test' => 'Property Hooks',
'status' => 'FAIL',
'message' => 'Property hooks not supported'
];
}
}
private function generateReport(): void
{
echo "\n=== PHP 8.5 Migration Test Report ===\n\n";
foreach ($this->results as $result) {
$status = match($result['status']) {
'PASS' => '✅',
'WARN' => '⚠️',
'FAIL' => '❌'
};
echo "{$status} {$result['test']}: {$result['message']}\n";
}
}
}
// Run the migration test
$tester = new MigrationTester();
$tester->runTests();
⭐ Best Practices for PHP 8.5
🏗️ Property Hooks Best Practices
// DO: Use property hooks for simple transformations
class User
{
public string $email {
set => strtolower(trim($value));
}
public string $name {
get => $this->firstName . ' ' . $this->lastName;
}
}
// DON'T: Use property hooks for complex business logic
class BadExample
{
public string $password {
set {
// Too complex for a property hook
if (strlen($value) < 8) {
throw new InvalidArgumentException('Password too short');
}
// ... lots of validation logic
$this->password = password_hash($value, PASSWORD_DEFAULT);
}
}
}
// BETTER: Use a dedicated method for complex logic
class GoodExample
{
private string $hashedPassword;
public function setPassword(string $password): void
{
$this->validatePassword($password);
$this->hashedPassword = password_hash($password, PASSWORD_DEFAULT);
}
}
🎯 Performance Optimization Tips
// Use typed properties for better JIT optimization
class OptimizedClass
{
private int $count = 0;
private array $items = [];
private readonly string $id;
public function __construct(string $id)
{
$this->id = $id;
}
// Use array functions instead of manual loops when possible
public function processItems(array $data): array
{
return array_map(
fn($item) => $this->transformItem($item),
array_filter($data, fn($item) => $item !== null)
);
}
}
// Use match expressions for better performance than if/else chains
function getStatusMessage(int $status): string
{
return match ($status) {
200 => 'Success',
404 => 'Not Found',
500 => 'Server Error',
default => 'Unknown Status'
};
}
// Optimize string operations
function buildQuery(array $conditions): string
{
// Use implode() instead of concatenation in loops
$parts = array_map(
fn($key, $value) => "{$key} = {$value}",
array_keys($conditions),
array_values($conditions)
);
return 'SELECT * FROM users WHERE ' . implode(' AND ', $parts);
}
🔒 Security Best Practices
// Always validate and sanitize input
class SecureController
{
public function handleUserInput(string $input): string
{
// Validate input length
if (strlen($input) > 255) {
throw new InvalidArgumentException('Input too long');
}
// Sanitize HTML
$cleaned = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// Additional filtering
return filter_var($cleaned, FILTER_SANITIZE_STRING);
}
// Use prepared statements for database queries
public function findUser(int $id): ?array
{
$stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
// Generate secure tokens
public function generateSecureToken(): string
{
return bin2hex(random_bytes(32));
}
}
💡 Practical Code Examples
🏢 Real-World Application: E-commerce Product Class
enum ProductStatus: string
{
case DRAFT = 'draft';
case PUBLISHED = 'published';
case SOLD_OUT = 'sold_out';
case DISCONTINUED = 'discontinued';
}
class Product
{
public function __construct(
private readonly int $id,
private string $name,
private float $basePrice,
private int $stockQuantity = 0
) {}
// Property hooks for automatic calculations
public float $finalPrice {
get => $this->calculateFinalPrice();
}
public ProductStatus $status {
get => match (true) {
$this->stockQuantity === 0 => ProductStatus::SOLD_OUT,
$this->basePrice === 0 => ProductStatus::DRAFT,
default => ProductStatus::PUBLISHED
};
}
// Asymmetric visibility for controlled access
public private(set) array $reviews = [];
public private(set) float $averageRating = 0.0;
// Business logic methods
public function addReview(int $rating, string $comment): void
{
if ($rating < 1 || $rating > 5) {
throw new InvalidArgumentException('Rating must be between 1 and 5');
}
$this->reviews[] = [
'rating' => $rating,
'comment' => $comment,
'date' => new DateTimeImmutable()
];
$this->averageRating = $this->calculateAverageRating();
}
public function updateStock(int $quantity): void
{
if ($quantity < 0) {
throw new InvalidArgumentException('Stock quantity cannot be negative');
}
$this->stockQuantity = $quantity;
}
private function calculateFinalPrice(): float
{
$discount = match (true) {
$this->averageRating >= 4.5 => 0.05, // 5% discount for highly rated
$this->stockQuantity > 100 => 0.02, // 2% discount for overstocked
default => 0.0
};
return $this->basePrice * (1 - $discount);
}
private function calculateAverageRating(): float
{
if (empty($this->reviews)) {
return 0.0;
}
$total = array_sum(array_column($this->reviews, 'rating'));
return round($total / count($this->reviews), 2);
}
// JSON serialization
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'name' => $this->name,
'basePrice' => $this->basePrice,
'finalPrice' => $this->finalPrice,
'status' => $this->status->value,
'stockQuantity' => $this->stockQuantity,
'averageRating' => $this->averageRating,
'reviewCount' => count($this->reviews)
];
}
}
// Usage example
$product = new Product(1, 'Gaming Laptop', 1299.99, 50);
$product->addReview(5, 'Excellent performance!');
$product->addReview(4, 'Good value for money');
echo "Status: " . $product->status->value; // "published"
echo "Final Price: $" . $product->finalPrice; // Calculated with discount
echo "Average Rating: " . $product->averageRating; // 4.5
🌐 API Controller with Modern PHP 8.5 Features
class ProductApiController
{
public function __construct(
private readonly ProductRepository $repository,
private readonly CacheInterface $cache
) {}
public function list(array $filters = []): array
{
$cacheKey = 'products:' . md5(serialize($filters));
return $this->cache->remember($cacheKey, 3600, function() use ($filters) {
$products = $this->repository->findByFilters($filters);
return [
'data' => array_map(fn($p) => $p->jsonSerialize(), $products),
'meta' => [
'count' => count($products),
'filters' => $filters
]
];
});
}
public function show(int $id): array
{
$product = $this->repository->findById($id);
return match ($product) {
null => ['error' => 'Product not found', 'code' => 404],
default => ['data' => $product->jsonSerialize()]
};
}
public function create(array $data): array
{
// Validate input using new array functions
$required = ['name', 'basePrice'];
$missing = array_diff($required, array_keys($data));
if ($missing) {
return [
'error' => 'Missing required fields: ' . implode(', ', $missing),
'code' => 400
];
}
try {
$product = new Product(
0, // ID will be set by repository
$data['name'],
$data['basePrice'],
$data['stockQuantity'] ?? 0
);
$saved = $this->repository->save($product);
$this->cache->flush('products:*'); // Invalidate cache
return [
'data' => $saved->jsonSerialize(),
'code' => 201
];
} catch (Exception $e) {
return [
'error' => 'Failed to create product: ' . $e->getMessage(),
'code' => 500
];
}
}
}
🔄 Stay Updated
PHP 8.5 is actively being developed. Keep track of the latest changes and features at:
- Official PHP Website: php.net
- PHP RFC: wiki.php.net/rfc
- GitHub Repository: github.com/php/php-src