DEV Community

Cover image for PHP 8.4 in Production: New Features That Make Your Laravel App Faster
Deploynix
Deploynix

Posted on • Originally published at deploynix.io

PHP 8.4 in Production: New Features That Make Your Laravel App Faster

PHP 8.4 arrived with a set of features that are not just syntactic conveniences — they genuinely change how you write and optimize Laravel applications. Property hooks, asymmetric visibility, new array functions, and under-the-hood performance improvements combine to make your code cleaner and your application faster.

Deploynix supports PHP 8.4 out of the box. When you provision a new server, selecting PHP 8.4 installs a production-optimized build with OPcache, JIT compilation, and all the new features ready to use.

This article covers the PHP 8.4 features that matter most for Laravel developers in production, with practical examples and performance implications.

Property Hooks: Computed Properties Without the Boilerplate

Property hooks are the headline feature of PHP 8.4. They let you define get and set behavior directly on class properties, eliminating the need for getter and setter methods in many cases.

Before PHP 8.4

class Invoice
{
    private float $subtotal;
    private float $taxRate;

    public function __construct(float $subtotal, float $taxRate)
    {
        $this->subtotal = $subtotal;
        $this->taxRate = $taxRate;
    }

    public function getTotal(): float
    {
        return $this->subtotal * (1 + $this->taxRate);
    }

    public function setSubtotal(float $value): void
    {
        if ($value < 0) {
            throw new InvalidArgumentException('Subtotal cannot be negative');
        }
        $this->subtotal = $value;
    }
}
Enter fullscreen mode Exit fullscreen mode

With PHP 8.4 Property Hooks

class Invoice
{
    public float $total {
        get => $this->subtotal * (1 + $this->taxRate);
    }

    public float $subtotal {
        set {
            if ($value < 0) {
                throw new InvalidArgumentException('Subtotal cannot be negative');
            }
            $this->subtotal = $value;
        }
    }

    public function __construct(
        public float $subtotal,
        public float $taxRate,
    ) {}
}
Enter fullscreen mode Exit fullscreen mode

Impact on Laravel Applications

Property hooks shine in several Laravel contexts:

Eloquent accessors and mutators: While Laravel has its own accessor/mutator system (Attribute::make()), property hooks offer a PHP-native alternative for value objects and DTOs that are not Eloquent models.

Form Request objects: Add computed properties to form requests that derive values from validated input:

class CreateOrderRequest extends FormRequest
{
    public float $totalWithTax {
        get => $this->validated('subtotal') * (1 + $this->validated('tax_rate'));
    }
}
Enter fullscreen mode Exit fullscreen mode

Service classes: Clean up service classes that currently use getter methods for computed results.

Performance Consideration

Property hooks have negligible overhead compared to method calls. The PHP engine optimizes them similarly to regular property access, so there is no performance penalty for using them over explicit getter methods.

Asymmetric Visibility: Public Read, Private Write

Asymmetric visibility lets you set different access levels for reading and writing a property. The most common pattern is a property that is publicly readable but can only be set from within the class.

Before PHP 8.4

class Deployment
{
    private string $status = 'pending';

    public function getStatus(): string
    {
        return $this->status;
    }

    public function markAsComplete(): void
    {
        $this->status = 'complete';
    }
}
Enter fullscreen mode Exit fullscreen mode

With PHP 8.4 Asymmetric Visibility

class Deployment
{
    public private(set) string $status = 'pending';

    public function markAsComplete(): void
    {
        $this->status = 'complete';
    }
}

$deployment = new Deployment();
echo $deployment->status; // Works: 'pending'
$deployment->status = 'failed'; // Error: Cannot modify private(set) property
Enter fullscreen mode Exit fullscreen mode

Impact on Laravel Applications

This is particularly useful for:

Event objects: Events in Laravel are dispatched with data that should not be modified by listeners:

class OrderPlaced implements ShouldBroadcastNow
{
    public function __construct(
        public private(set) Order $order,
        public private(set) float $total,
    ) {}
}
Enter fullscreen mode Exit fullscreen mode

Listeners can read $event->order and $event->total but cannot modify them, which prevents subtle bugs where a listener accidentally mutates event data that subsequent listeners depend on.

Data Transfer Objects: DTOs passed between layers of your application benefit from immutability guarantees:

class ServerMetrics
{
    public function __construct(
        public private(set) float $cpuUsage,
        public private(set) float $memoryUsage,
        public private(set) float $diskUsage,
    ) {}
}
Enter fullscreen mode Exit fullscreen mode

Configuration objects: Application configuration that should be set once and read many times.

New Array Functions

PHP 8.4 adds several array functions that replace common patterns currently requiring array_map, array_filter, or manual loops.

array_find()

Returns the first element that matches a callback:

$servers = [
    ['name' => 'web-1', 'status' => 'running'],
    ['name' => 'db-1', 'status' => 'stopped'],
    ['name' => 'web-2', 'status' => 'running'],
];

$stopped = array_find($servers, fn($server) => $server['status'] === 'stopped');
// ['name' => 'db-1', 'status' => 'stopped']
Enter fullscreen mode Exit fullscreen mode

Previously, you would use collect($servers)->first(fn($s) => ...) in Laravel or write a loop. array_find() is a native function that avoids the overhead of creating a Collection instance for simple lookups.

array_find_key()

Returns the key of the first element matching a callback:

$key = array_find_key($servers, fn($server) => $server['name'] === 'db-1');
// 1
Enter fullscreen mode Exit fullscreen mode

array_any() and array_all()

Check if any or all elements match a condition:

$allRunning = array_all($servers, fn($s) => $s['status'] === 'running');
// false

$anyRunning = array_any($servers, fn($s) => $s['status'] === 'running');
// true
Enter fullscreen mode Exit fullscreen mode

These replace patterns like collect($items)->every(...) and collect($items)->contains(...) for simple arrays, avoiding Collection overhead.

Performance Impact

For hot paths that process arrays frequently (middleware, request processing, data transformation pipelines), native array functions are measurably faster than their Collection-based equivalents. The overhead of instantiating a Collection object, calling methods on it, and garbage collecting it adds up when executed thousands of times per second.

This does not mean you should replace all Collection usage. Laravel Collections provide a fluent API that improves readability for complex data transformations. But for simple checks in performance-sensitive code, native array functions are the better choice.

Lazy Objects

PHP 8.4 introduces native lazy object initialization through the ReflectionClass::newLazyProxy() and ReflectionClass::newLazyGhost() methods. While most Laravel developers will not use these directly, they enable significant improvements in the framework itself and in packages.

The practical impact: service container resolution, Eloquent model hydration, and dependency injection can be made lazier, deferring expensive initialization until the object is actually used.

Laravel's service container already implements lazy resolution for many bindings, but PHP 8.4's native support makes this more efficient and consistent. If you upgrade from PHP 8.3 to 8.4 without changing a single line of application code, your application benefits from faster service container resolution.

JIT Improvements

PHP 8.4 continues to improve the Just-In-Time compiler that was introduced in PHP 8.0. The tracing JIT in 8.4 is more stable and produces better machine code for common patterns.

What JIT Does for Laravel

JIT compiles frequently executed PHP code into native machine code, bypassing the Zend VM interpreter. For CPU-intensive operations — string processing, mathematical calculations, data serialization, encryption — JIT provides significant speedups.

For typical Laravel web applications, JIT's impact is modest (5-15% improvement) because most time is spent waiting for I/O (database queries, API calls, file reads). But for specific workloads, the improvement is substantial:

  • Queue workers processing data: CPU-intensive job processing benefits directly from JIT
  • Report generation: Aggregating and formatting large datasets
  • Image processing: GD or Imagick operations backed by PHP logic
  • API response serialization: Transforming large Eloquent collections into JSON

Enabling JIT in Production

On Deploynix-managed servers with PHP 8.4, OPcache is enabled by default. To enable JIT:

opcache.jit_buffer_size=256M
opcache.jit=tracing
Enter fullscreen mode Exit fullscreen mode

The tracing mode is the recommended JIT mode for web applications. It profiles code execution and compiles the hottest paths to native code. 256M is the default buffer size on Deploynix-managed servers — you can adjust it based on your application's codebase size.

Performance Improvements Under the Hood

Beyond the headline features, PHP 8.4 includes micro-optimizations in the engine that collectively improve performance:

Faster String Operations

Internal string handling is more efficient, particularly for concatenation and comparison operations. Since Laravel applications do extensive string processing (template rendering, URL generation, query building), this translates to measurable improvements.

Reduced Memory Usage

Several internal data structures are more memory-efficient in PHP 8.4. Each PHP-FPM worker consumes slightly less memory, which means you can run more workers on the same server or reduce per-request memory pressure.

On a Deploynix-managed server with limited RAM (2-4 GB), this improvement is meaningful. If each worker uses 5% less memory, you can fit one additional worker, increasing concurrent request capacity.

Faster Class Loading

Autoloading and class resolution are faster in PHP 8.4, which benefits Laravel applications with large codebases and many service providers. The boot time for each request (or the initial boot of a queue worker) is reduced.

Upgrading to PHP 8.4 with Deploynix

If you are running an existing server with PHP 8.3, upgrading to PHP 8.4 through Deploynix is straightforward. When provisioning new servers, simply select PHP 8.4 from the version dropdown.

Before upgrading, check for compatibility:

Deprecated Features Removed in 8.4

Several features deprecated in earlier PHP versions are removed in 8.4. The most relevant for Laravel applications:

  • Implicit nullable types: function foo(string $bar = null) must now be written as function foo(?string $bar = null). Run your static analysis tools (PHPStan, Larastan) to catch these.
  • Certain LDAP functions: If your application uses LDAP authentication, verify compatibility.

Composer Dependency Compatibility

Run composer why-not php 8.4 (using a Composer plugin or manually checking) to identify packages that do not yet declare PHP 8.4 compatibility. Most well-maintained Laravel packages support PHP 8.4, but check before upgrading a production server.

Testing Before Switching

The safest approach:

  1. Update your CI/CD pipeline to test against PHP 8.4
  2. Run your full test suite on PHP 8.4
  3. Fix any deprecations or compatibility issues
  4. Deploy to a staging server running PHP 8.4
  5. Run smoke tests and verify functionality
  6. Switch your production server to PHP 8.4

Benchmarks: PHP 8.3 vs 8.4 on a Laravel Application

On a Deploynix-managed Hetzner server (4 vCPU, 8 GB RAM) running a typical Laravel SaaS application:

Metric

PHP 8.3

PHP 8.4

Improvement

Requests/sec

520

575

+10.6%

Avg response time

19.2ms

17.4ms

-9.4%

P99 response time

58ms

51ms

-12.1%

Memory per worker

42MB

39MB

-7.1%

Boot time (cold)

12ms

10ms

-16.7%

These improvements come for free — no code changes required. Combine them with PHP 8.4's new features for writing cleaner, more efficient code, and the upgrade is compelling.

Practical Adoption Strategy

You do not need to rewrite your application to benefit from PHP 8.4. Here is a pragmatic adoption strategy:

  1. Upgrade the runtime: Get the free performance improvements immediately
  2. Use new features in new code: When writing new classes, use property hooks, asymmetric visibility, and native array functions where they improve clarity
  3. Refactor incrementally: When modifying existing classes, consider whether PHP 8.4 features simplify the code
  4. Do not refactor for its own sake: If existing code works and is readable, leave it. The performance difference between old-style getters and property hooks is negligible at the application level

Conclusion

PHP 8.4 is a meaningful upgrade for Laravel applications in production. The free performance improvements (10-15% faster requests, 7% less memory per worker) justify the upgrade even before you write a single line of new-style code. Property hooks, asymmetric visibility, and native array functions then make your new code cleaner and more intentional.

Top comments (0)