<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr" -->

---
title: How PHP generates machine code | daily.dev
description: A deep technical dive into how PHP 8.6&#x27;s JIT compiler works, comparing its two modes: function JIT (compiles everything upfront) and tracing JIT (compiles...
canonical: https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: How PHP generates machine code | daily.dev
og:description: A deep technical dive into how PHP 8.6&#x27;s JIT compiler works, comparing its two modes: function JIT (compiles everything upfront) and tracing JIT (compiles...
og:url: https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr
og:image: https://api.daily.dev/og/posts/ZWFYNbekR.png
og:image:alt: How PHP generates machine code
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How PHP generates machine code

**[PHPUnit Expert](https://daily.dev/sources/phpunit-expert)** · 23 min read · 14 upvotes · 1 comments

## Summary

A deep technical dive into how PHP 8.6's JIT compiler works, comparing its two modes: function JIT (compiles everything upfront) and tracing JIT (compiles based on observed runtime behavior). Walks through actual generated machine code, side exits, deoptimization, and the IR compiler framework underneath. Benchmarks against a 177-test raytracer suite show the function JIT makes a test run 5.8% slower than no JIT at all, while the tracing JIT cuts run time by roughly a quarter, because the function JIT pays a large fixed compilation cost that never gets amortized in short-lived CLI processes. Concludes that tracing is the right choice for CLI/test workloads, while function JIT may still make sense under FPM workers serving many requests.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://phpunit.expert/articles/how-php-generates-machine-code.html>

## Questions this post answers

### Should I enable opcache.jit=function or opcache.jit=tracing for running a PHPUnit test suite on the command line?

Tracing JIT is the better choice for command-line test runs. On a 177-test PHPUnit suite, tracing JIT cut wall-clock time by about a quarter compared to no JIT, while function JIT added 5.8% overhead because its large upfront compilation cost (3.57s fixed cost measured) is paid again on every CLI invocation and rarely gets earned back in a short-lived process.

_Developers tuning PHP test suite performance can find measured JIT tradeoffs like these through daily.dev._

### Is PHP's JIT compiler enabled by default?

No, opcache.jit is set to disable by default in PHP 8.6, even though opcache.jit_buffer_size defaults to 64M. Neither php.ini-production nor php.ini-development mention opcache.jit at all, so anyone wanting the JIT must add the setting themselves. This differs from PHP versions up to 8.3, where the default was tracing mode with a buffer size of 0, which had the same disabling effect but was more confusing.

_Anyone configuring php.ini for production PHP can track defaults like this via daily.dev._

### What replaced PHP's own JIT compiler backend and when did that change happen?

Since PHP 8.4, PHP's JIT no longer uses its own compiler code; it relies on the IR framework written by Dmitry Stogov, an intermediate representation library checked in under ext/opcache/jit/ir/ and periodically pulled from the upstream project. Roughly 47,600 lines belong to the IR framework itself and about 37,100 lines are the PHP-specific translation layer.

_Developers following PHP internals changes can track shifts like the IR framework adoption on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@agustinbarrientos** · 0 upvotes

> I wouldn't turn JIT on everywhere from a raytracer win. Give a big PHPUnit suite the same treatment. Most PHP apps aren't raytracers.

---

Tags: [#performance](https://daily.dev/tags/performance), [#php](https://daily.dev/tags/php), [#compiler-optimization](https://daily.dev/tags/compiler-optimization)

[View this post on daily.dev](https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"How PHP generates machine code","url":"https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr"},"datePublished":"2026-09-02T03:14:42.790Z","dateModified":"2026-09-14T08:51:57.313Z","description":"A deep technical dive into how PHP 8.6's JIT compiler works, comparing its two modes: function JIT (compiles everything upfront) and tracing JIT (compiles...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/d2f3015afac78be70b06ae26b624ed26?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/d2f3015afac78be70b06ae26b624ed26?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"PHPUnit Expert","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"PHPUnit Expert","logo":"https://media.daily.dev/image/upload/s--FMZoysoG--/f_auto,q_auto/v1774964057/logos/phpunit-expert?_a=BAMAMiWQ0","url":"https://daily.dev/sources/phpunit-expert"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":14},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"performance,php,compiler-optimization","timeRequired":"PT23M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"PHPUnit Expert","item":"https://daily.dev/sources/phpunit-expert"},{"@type":"ListItem","position":3,"name":"How PHP generates machine code"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr","comment":[{"@type":"Comment","text":"I wouldn’t turn JIT on everywhere from a raytracer win. Give a big PHPUnit suite the same treatment. Most PHP apps aren’t raytracers.","datePublished":"2026-09-09T13:02:18.265Z","url":"https://daily.dev/posts/ZWFYNbekR#c-lTZG8v3s6","author":{"@type":"Person","name":"Agustin Barrientos","url":"https://daily.dev/agustinbarrientos","image":"https://media.daily.dev/image/upload/s--5ayxQnqn--/f_auto/v1788281802/avatars/avatar_wQYYVe5Tbj0NJ7C7qPoa8?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/how-php-generates-machine-code-zwfynbekr#faq","mainEntity":[{"@type":"Question","name":"Should I enable opcache.jit=function or opcache.jit=tracing for running a PHPUnit test suite on the command line?","acceptedAnswer":{"@type":"Answer","text":"Tracing JIT is the better choice for command-line test runs. On a 177-test PHPUnit suite, tracing JIT cut wall-clock time by about a quarter compared to no JIT, while function JIT added 5.8% overhead because its large upfront compilation cost (3.57s fixed cost measured) is paid again on every CLI invocation and rarely gets earned back in a short-lived process. Developers tuning PHP test suite performance can find measured JIT tradeoffs like these through daily.dev."}},{"@type":"Question","name":"Is PHP's JIT compiler enabled by default?","acceptedAnswer":{"@type":"Answer","text":"No, opcache.jit is set to disable by default in PHP 8.6, even though opcache.jit_buffer_size defaults to 64M. Neither php.ini-production nor php.ini-development mention opcache.jit at all, so anyone wanting the JIT must add the setting themselves. This differs from PHP versions up to 8.3, where the default was tracing mode with a buffer size of 0, which had the same disabling effect but was more confusing. Anyone configuring php.ini for production PHP can track defaults like this via daily.dev."}},{"@type":"Question","name":"What replaced PHP's own JIT compiler backend and when did that change happen?","acceptedAnswer":{"@type":"Answer","text":"Since PHP 8.4, PHP's JIT no longer uses its own compiler code; it relies on the IR framework written by Dmitry Stogov, an intermediate representation library checked in under ext/opcache/jit/ir/ and periodically pulled from the upstream project. Roughly 47,600 lines belong to the IR framework itself and about 37,100 lines are the PHP-specific translation layer. Developers following PHP internals changes can track shifts like the IR framework adoption on daily.dev."}}]}
```

