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

# PHP 8.4 is here!

export const PostMeta = ({data = {}}) => {
  const {author, date, image} = data;
  const authors = Array.isArray(author) ? author : author ? [author] : [];
  const resolveAuthor = slug => {
    const entry = AUTHOR_MAP[slug] || ({});
    const name = entry.name || slug;
    const github = entry.github || null;
    const linkedin = entry.linkedin || null;
    const url = github ? `https://github.com/${github}` : linkedin || null;
    const avatarUrl = github ? `https://github.com/${github}.png?size=64` : null;
    return {
      name,
      url,
      avatarUrl
    };
  };
  const formattedDate = date ? new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }) : null;
  if (!image && authors.length === 0 && !formattedDate) return null;
  const AUTHOR_MAP = {
    "aaron-collier": {
      "name": "Aaron Collier"
    },
    "aaron-dudenhofer": {
      "name": "Aaron Dudenhofer"
    },
    "aaron-porter": {
      "name": "Aaron Porter"
    },
    "adriaan-odendaal": {
      "name": "Adriaan Odendaal"
    },
    "ajmal": {
      "name": "Ajmal Siddiqui"
    },
    "akalipetis": {
      "name": "Antonis Kalipetis"
    },
    "alexander-varwijk": {
      "name": "Alexander Varwijk"
    },
    "alicia-bevilacqua": {
      "name": "Alicia Bevilacqua"
    },
    "amelie-deguerry": {
      "name": "Amelie Deguerry"
    },
    "anacidre": {
      "name": "Ana Cidre",
      "linkedin": "https://www.linkedin.com/in/ana-cidre"
    },
    "andoni": {
      "name": "Andoni Auzmendi"
    },
    "andrei-taranu": {
      "name": "Andrei (Alex) Taranu",
      "linkedin": "https://www.linkedin.com/in/andrei-alex-taranu/"
    },
    "andrew-baxter": {
      "name": "Andrew Baxter"
    },
    "andrew-melck": {
      "name": "Andrew Melck"
    },
    "antoine-crochet-damais": {
      "name": "Antoine Crochet Damais"
    },
    "augustin-delaporte": {
      "name": "Augustin Delaporte",
      "linkedin": "https://www.linkedin.com/in/augustindelaporte/"
    },
    "branislav-bujisic": {
      "name": "Branislav Bujisic"
    },
    "carl-smith": {
      "name": "Carl Smith"
    },
    "caroline-leroy": {
      "name": "Caroline Leroy"
    },
    "cati-mayer": {
      "name": "Cati Mayer"
    },
    "catplat": {
      "name": "C Trinkwon"
    },
    "ceelolulu": {
      "name": "Celeste van der Watt"
    },
    "chadwcarlson": {
      "name": "Chad Carlson",
      "github": "chadwcarlson",
      "linkedin": "https://www.linkedin.com/in/chadwcarlson"
    },
    "chris-ward": {
      "name": "Chris Ward"
    },
    "chris-yates": {
      "name": "Chris Yates"
    },
    "christian-sieber": {
      "name": "Christian Sieber"
    },
    "christopher-lockheardt": {
      "name": "Christopher Lockheardt"
    },
    "christopher-skene": {
      "name": "Christopher Skene"
    },
    "chuck-morgan": {
      "name": "Chuck Morgan"
    },
    "corey-dockendorf": {
      "name": "Corey Dockendorf"
    },
    "crell": {
      "name": "Crell"
    },
    "damz": {
      "name": "Damz"
    },
    "dan-morrison": {
      "name": "Dan Morrison"
    },
    "davidbonachera": {
      "name": "David Bonachera",
      "github": "davidbonachera",
      "linkedin": "https://www.linkedin.com/in/davidbonachera"
    },
    "dereliahmet1": {
      "name": "Ahmet Faruk Dereli"
    },
    "devicezero": {
      "name": "Jonas Kröger",
      "github": "devicezero",
      "linkedin": "https://www.linkedin.com/in/jonaskroeger/"
    },
    "doug-goldberg": {
      "name": "Doug Goldberg"
    },
    "duncan-naves": {
      "name": "Duncan Naves",
      "github": "duncannaves",
      "linkedin": "https://www.linkedin.com/in/duncan-naves-a94423aa"
    },
    "erika-bustamante": {
      "name": "Erika Bustamante"
    },
    "fabpot": {
      "name": "Fabien Potencier"
    },
    "flovntp": {
      "name": "Florent Huck",
      "github": "flovntp",
      "linkedin": "https://www.linkedin.com/in/florenthuck"
    },
    "fred-plais": {
      "name": "Fred Plais"
    },
    "gauthier-garnier": {
      "name": "Gauthier Garnier"
    },
    "gilzow": {
      "name": "Paul Gilzow"
    },
    "gmoigneu": {
      "name": "Guillaume Moigneu",
      "github": "gmoigneu",
      "linkedin": "https://www.linkedin.com/in/guillaumemoigneu/"
    },
    "gregqualls": {
      "name": "Greg Qualls"
    },
    "guguss": {
      "name": "Augustin Delaporte"
    },
    "haylee-millar": {
      "name": "Haylee Millar"
    },
    "ivana-kotur": {
      "name": "Ivana Kotur"
    },
    "jackrabbithanna": {
      "name": "Mark Hanna"
    },
    "jared-wright": {
      "name": "Jared Wright",
      "github": "jww-sh",
      "linkedin": "https://www.linkedin.com/in/jaredwaynewright"
    },
    "jessica-orozco": {
      "name": "Jessica Orozco"
    },
    "joey-stanford": {
      "name": "Joey Stanford"
    },
    "john-grubb": {
      "name": "John Grubb"
    },
    "jonas-kruger": {
      "name": "Jonas Kruger"
    },
    "kathryn-frazer": {
      "name": "Kathryn Frazer"
    },
    "kemiojo": {
      "name": "Kemi Elizabeth Ojogbede"
    },
    "kieronsambrook-smith": {
      "name": "Kieronsambrook Smith"
    },
    "laurent-arnoud": {
      "name": "Laurent Arnoud"
    },
    "letoya-boyne": {
      "name": "Letoya Boyne"
    },
    "lolautruche": {
      "name": "Jérôme Vieilledent"
    },
    "lyly-lepinay": {
      "name": "Lyly Lepinay"
    },
    "manauwar-alam": {
      "name": "Manauwar Alam"
    },
    "marc-antoine-porri": {
      "name": "Marc Antoine Porri"
    },
    "maria-antinkaapo": {
      "name": "Maria Antinkaapo"
    },
    "maria-de-anton": {
      "name": "Maria De Anton"
    },
    "mark-dorison": {
      "name": "Mark Dorison"
    },
    "markus-hausammann": {
      "name": "Markus Hausammann"
    },
    "mary-thomas": {
      "name": "Mary Thomas"
    },
    "mathias-bolt-lesniak": {
      "name": "Mathias Bolt Lesniak"
    },
    "mathieu-strauch": {
      "name": "Mathieu Strauch"
    },
    "matthias-van-woensel": {
      "name": "Matthias Van Woensel",
      "linkedin": "https://www.linkedin.com/in/matthias-van-woensel-267a069"
    },
    "michael-sharp": {
      "name": "Michael Sharp"
    },
    "mupsi": {
      "name": "Marine Gandy"
    },
    "natalie-harper": {
      "name": "Natalie Harper"
    },
    "ngommenginger": {
      "name": "Nicolas Gommenginger",
      "linkedin": "https://www.linkedin.com/in/nicolas-gommenginger"
    },
    "nicholas-bennison": {
      "name": "Nicholas Bennison"
    },
    "nicholas-vahalik": {
      "name": "Nicholas Vahalik"
    },
    "nick-hardiman": {
      "name": "Nick Hardiman"
    },
    "nickanderegg": {
      "name": "Nickanderegg"
    },
    "nicolas-grekas": {
      "name": "Nicolas Grekas",
      "github": "nicolas-grekas",
      "linkedin": "https://www.linkedin.com/in/nicolasgrekas/"
    },
    "niti-malwade": {
      "name": "Niti Malwade"
    },
    "opensocialteam": {
      "name": "Opensocialteam"
    },
    "ori-pekelman": {
      "name": "Ori Pekelman"
    },
    "otavio-santana": {
      "name": "Otavio Santana"
    },
    "palwandi": {
      "name": "Pawan Alwandi",
      "github": "pawpy",
      "linkedin": "https://www.linkedin.com/in/pawanalwandi"
    },
    "patrick-boest": {
      "name": "Patrick Boest"
    },
    "patrick-dawkins": {
      "name": "Patrick Dawkins",
      "github": "pjcdawkins",
      "linkedin": "https://www.linkedin.com/in/patrickdawkins"
    },
    "patrick-klima": {
      "name": "Patrick Klima"
    },
    "pjcdawkins": {
      "name": "Pjcdawkins"
    },
    "prineet-kaurbhurji": {
      "name": "Prineet Kaurbhurji"
    },
    "quentin-sinig": {
      "name": "Quentin Sinig"
    },
    "ralt": {
      "name": "Florian Margaine",
      "github": "ralt",
      "linkedin": "https://www.linkedin.com/in/florian-margaine-43971136"
    },
    "ramanathanramakrishnamurthy": {
      "name": "Ramanathanramakrishnamurthy"
    },
    "remi-lejeune": {
      "name": "Rémi Lejeune"
    },
    "ribel": {
      "name": "Taras Kruts"
    },
    "robert-douglass": {
      "name": "Robert Douglass"
    },
    "rudy-weber": {
      "name": "Rudy Weber"
    },
    "ryan-hicks": {
      "name": "Ryan Hicks"
    },
    "sabri-helal": {
      "name": "Sabri Helal"
    },
    "savannah-bergeron": {
      "name": "Savannah Bergeron"
    },
    "shannon-vettes": {
      "name": "Shannon Vettes"
    },
    "shawn-ogasawara": {
      "name": "Shawn Ogasawara",
      "linkedin": "https://www.linkedin.com/in/shawn-ogasawara-83a9a0/"
    },
    "shawna-spoor": {
      "name": "Shawna Spoor"
    },
    "shedrack-akintayo": {
      "name": "Shedrack Akintayo"
    },
    "simon-ruggier": {
      "name": "Simon Ruggier"
    },
    "sophie-van-der-kindere": {
      "name": "Sophie Van Der Kindere"
    },
    "stefanos-thampis": {
      "name": "Stefanos Thampis"
    },
    "stephen-weinberg": {
      "name": "Stephen Weinberg"
    },
    "sukhman-virk": {
      "name": "Sukhman Virk"
    },
    "sumaira-nazir": {
      "name": "Sumaira Nazir"
    },
    "sumer": {
      "name": "Sümer Cip"
    },
    "syed-raza": {
      "name": "Syed Raza"
    },
    "tamara-bacchia": {
      "name": "Tamara Bacchia"
    },
    "tara-arnold": {
      "name": "Tara Arnold"
    },
    "theosakamg": {
      "name": "Mickael Gaillard",
      "github": "theosakamg"
    },
    "thomasdiluccio": {
      "name": "Thomas di Luccio"
    },
    "tim-anderson": {
      "name": "Tim Anderson"
    },
    "tom-helmer-hansen": {
      "name": "Tom Helmer Hansen"
    },
    "tylermills": {
      "name": "Tyler Mills"
    },
    "upsun": {
      "name": "Upsun"
    },
    "veronika-tolkachova": {
      "name": "Veronika Tolkachova",
      "linkedin": "https://www.linkedin.com/in/veronika-tolkachova-169167a2"
    },
    "vince-parker": {
      "name": "Vince Parker"
    },
    "vinnie-russo": {
      "name": "Vincenzo Russo"
    },
    "vrobert78": {
      "name": "Vincent Robert",
      "github": "vrobert78",
      "linkedin": "https://www.linkedin.com/in/vincent-robert-498a883"
    },
    "yuriy-babenko": {
      "name": "Yuriy Babenko"
    },
    "yuriy-gerasimov": {
      "name": "Yuriy Gerasimov"
    }
  };
  return <div className="post-meta">
      {(authors.length > 0 || formattedDate) && <div className="post-meta-info">
          {authors.length > 0 && <div className="post-meta-authors">
              {authors.map(slug => {
    const {name, url, avatarUrl} = resolveAuthor(slug);
    const inner = <>
                    {avatarUrl && <img src={avatarUrl} alt={name} className="post-meta-avatar" />}
                    <span className="post-meta-author-name">{name}</span>
                  </>;
    return url ? <a key={slug} href={url} target="_blank" rel="noopener noreferrer" className="post-meta-author">
                    {inner}
                  </a> : <span key={slug} className="post-meta-author">{inner}</span>;
  })}
            </div>}
          {authors.length > 0 && formattedDate && <span className="post-meta-separator" aria-hidden="true">·</span>}
          {formattedDate && <span className="post-meta-date">{formattedDate}</span>}
        </div>}
      {image && <img src={image} alt="" className="post-meta-image" aria-hidden="true" />}
    </div>;
};

<PostMeta data={{ author: ["chadwcarlson"], date: "2024-11-26T15:34:22-05:00", image: "/images/posts/releases/php-84-release/elephant-84.webp" }} />

PHP 8.4 was [officially released](https://www.php.net/archive/2024.php#2024-11-21-4) on November 21st, and with it comes a number of improvements and new features that you can - as of today - begin working with on your Upsun and Platform.sh projects.

## How to upgrade

You can explore all that PHP 8.4 has to offer on your projects today.

### Install the new version

First, follow the official instructions for installing PHP 8.4 on your computer:

* [Unix systems instructions](https://www.php.net/manual/install.unix.php)
* [macOS instructions](https://www.php.net/manual/install.macosx.php)
* [Windows binaries](https://windows.php.net/download/)

Then you can check that it's installed and accessible with:

```bash {filename="Terminal"} theme={null}
php -r 'echo PHP_VERSION;'
```

### Create a new environment

Create a branch dedicated to the latest version:

```bash {filename="Terminal"} theme={null}
upsun branch php-84-testing
```

### Upgrade your dependencies

Run the command:

```bash {filename="Terminal"} theme={null}
composer upgrade
```

### Upgrade your configuration

<Tabs>
  <Tab title="Single runtime image">
    On Upsun:

    ```yaml {filename=".upsun/config.yaml"} theme={null}
    applications:
      your_application:
        type: "php:8.4"
    ```

    and on Platform.sh:

    ```yaml {filename=".platform.app.yaml"} theme={null}
    name: "your_application"
    type: "php:8.4"
    ```
  </Tab>

  <Tab title="Composable image">
    At the time of this post, PHP 8.4 is still a part of the 24.11 Nix packages **Beta** channel.
    Beta channels are not yet supported for the Upsun and Platform.sh Composable image.
    As soon as it becomes available on the stable channel, you will be able to upgrade to PHP 8.4 as shown below.

    On Upsun:

    ```yaml {filename=".upsun/config.yaml"} theme={null}
    applications:
      your_application:
        stack:
          - "php@8.4"
    ```

    and on Platform.sh:

    ```yaml {filename=".platform.app.yaml"} theme={null}
    name: "your_application"
    stack:
      - "php@8.4"
    ```
  </Tab>
</Tabs>

And test the changes on the new environment with an `upsun push`.
Once the environment is live, you can merge the upgrades now (`upsun merge`), then come back to visit many of the performance improvements and new features packaged in the release below.
You can test the changes on the new environment with an `upsun push`.
You can as always find more information about available extensions and PHP configuration in the [Upsun](https://docs.upsun.com) and [Platform.sh](https://docs.platform.sh) documentation.

<Note>
  **A note on production upgrades:**

  There are some noted [incompatibilities](https://www.php.net/manual/en/migration84.incompatible.php) that come with this new minor version release that you should keep in mind when upgrading production environments.
  Consult those warnings and the links below for more details.
</Note>

## What's changed in PHP 8.4?

With this release comes a number of resources to better understand what's changed, and how those changes impact your applications:

* A comprehensive list of all changes can be found in [the ChangeLog](https://www.php.net/ChangeLog-8.php#8.4.1)
* A side-by-side comparison on the [release homepage](https://www.php.net/releases/8.4/en.php)
* [Migrating from PHP 8.3.x to PHP 8.4.x instructions](https://www.php.net/manual/en/migration84.php), which further breaks down the changes into:
  * [New features](https://www.php.net/manual/en/migration84.new-features.php)
  * [New classes, Enums, and interfaces](https://www.php.net/manual/en/migration84.new-classes.php)
  * [New functions](https://www.php.net/manual/en/migration84.new-functions.php)
  * [New global constants](https://www.php.net/manual/en/migration84.constants.php)
  * [Backward incompatible changes](https://www.php.net/manual/en/migration84.incompatible.php)
  * [Deprecated features](https://www.php.net/manual/en/migration84.deprecated.php)
  * [Removed extensions](https://www.php.net/manual/en/migration84.removed-extensions.php)

### New features

While there are a great number of improvements, updates, and added functions and subclasses in this release, much of the discussion up to this point has seemed to focus primarily on three enhancements in particular.

1. **Property hooks**

   With much inspiration from Kotlin, Property hooks in PHP 8.4 allow for defining additional logic (such as validation) associated with an objects `get`/`set` operations.

   [From php.net](https://www.php.net/manual/en/migration84.new-features.php#migration84.new-features.core.property-hooks):

   > Object properties may now have additional logic associated with their get and set operations. Depending on the usage, that may or may not make the property virtual, that is, it has no backing value at all.
   >
   > ```php theme={null}
   > <?php
   > class Person
   > {
   >     // A "virtual" property.  It may not be set explicitly.
   >     public string $fullName {
   >         get => $this->firstName . ' ' . $this->lastName;
   >     }
   >
   >     // All write operations go through this hook, and the result is what is written.
   >     // Read access happens normally.
   >     public string $firstName {
   >         set => ucfirst(strtolower($value));
   >     }
   >
   >     // All write operations go through this hook, which has to write to the backing value itself.
   >     // Read access happens normally.
   >     public string $lastName {
   >         set {
   >             if (strlen($value) < 2) {
   >                 throw new \InvalidArgumentException('Too short');
   >             }
   >             $this->lastName = $value;
   >         }
   >     }
   > }
   >
   > $p = new Person();
   >
   > $p->firstName = 'peter';
   > print $p->firstName; // Prints "Peter"
   > $p->lastName = 'Peterson';
   > print $p->fullName; // Prints "Peter Peterson"
   > ```

   **Resources:**

   * [Original RFC](https://wiki.php.net/rfc/property-hooks)
   * [Release notes](https://www.php.net/manual/en/migration84.new-features.php#migration84.new-features.core.property-hooks)

   <Note>
     **Consider the following:**

     If you're looking for even more background into not just the impact of property hooks, but also the history behind the RFC process in conjunction with [Asymmetrics Visibility](https://wiki.php.net/rfc/asymmetric-visibility) to replace the older [Property Accessors](https://wiki.php.net/rfc/property_accessors) RFC, be sure to check out the great article by Larry Garfield on the topic on the PHP foundation website - [***How Property Hooks Happened***](https://thephp.foundation/blog/2024/11/01/how-hooks-happened/).
   </Note>

2. **Asymmetric visibility**

   While the visibility of `get` and `set` object operations have historically been "symmetric" - that is, both must be `public`, `private`, or `protected` - PHP 8.4 allows for asymmetrics definitions in your objects.

   [From php.net](https://www.php.net/manual/en/migration84.new-features.php#migration84.new-features.core.asymmetric-property-visibility):

   > Object properties may now have their `set` visibility controlled separately from the `get` visibility.
   >
   > ```php theme={null}
   > <?php
   > class Example
   > {
   >     // The first visibility modifier controls the get-visibility, and the second modifier
   >     // controls the set-visibility. The get-visibility must not be narrower than set-visibility.
   >     public protected(set) string $name;
   >
   >     public function __construct(string $name)
   >     {
   >         $this->name = $name;
   >     }
   > }
   > ```

   **Resources:**

   * [Original RFC](https://wiki.php.net/rfc/asymmetric-visibility-v2)
   * [Release notes](https://www.php.net/manual/en/migration84.new-features.php#migration84.new-features.core.asymmetric-property-visibility)

3. **Lazy objects**

   PHP 8.4 takes the responsibility of the lazy-initialization of object out of userland, bringing it into the PHP engine itself.

   From [php.net](https://www.php.net/manual/en/migration84.new-features.php#migration84.new-features.core.lazy-objects):

   > It is now possible to create objects whose initialization is deferred until they are accessed. Libraries and frameworks can leverage these lazy objects to defer fetching data or dependencies required for initialization.
   > Object properties may now have their `set` visibility controlled separately from the `get` visibility.
   >
   > ```php theme={null}
   > <?php
   > class Example
   > {
   >     public function __construct(private int $data)
   >     {
   >     }
   >
   >     // ...
   > }
   >
   > $initializer = static function (Example $ghost): void {
   >     // Fetch data or dependencies
   >     $data = ...;
   >     // Initialize
   >     $ghost->__construct($data);
   > };
   >
   > $reflector = new ReflectionClass(Example::class);
   > $object = $reflector->newLazyGhost($initializer);
   > ```

   **Resources:**

   * [Original RFC](https://wiki.php.net/rfc/lazy-objects)
   * [Release notes](https://www.php.net/manual/en/migration84.new-features.php#migration84.new-features.core.lazy-objects)
   * [Feature documentation](https://www.php.net/manual/en/language.oop5.lazy-objects.php)

### Deprecations

You can find a list of all deprecations for PHP 8.4 on the [php.net wiki](https://windows.php.net/download/).

## What's next?

With 8.4 now released, the road to 8.5 begins with a new round of discussion and voting on [RFCs](https://wiki.php.net/rfc), so be sure to follow the debate there.

Otherwise, you're all set!
Join us in the [Discord](https://discord.gg/upsun) and let us know how it goes.

Be seeing you!
