現状最新のPHP 8.5はこんな感じ。

PHP 8.5では、|> パイプ演算子、clone() 時のプロパティ変更、#[\NoDiscard] 属性、定数式でのクロージャや第一級 callable の利用などが追加され、コードをより読みやすく、より安全に書けるようになりました。

なお、よく「PHP 8で導入された機能」として挙げられがちな trait はPHP 5.4で導入済み で、PHP 8系の新機能ではありません。一方で enum はPHP 8.1パイプ演算子はPHP 8.5 の機能です。

PHP 7系以下と比べると、PHP 8系は「型安全」「表現力」「可読性」がかなり強化された世代だと言えます。

PHP 8系で何が変わったのか

PHP 8系では、単なる高速化だけでなく、コードの書きやすさや保守性に直結する機能が多く追加されました。特に、enummatch、属性(Attributes)、コンストラクタプロパティ昇格、Union Types、そして PHP 8.5 の |> パイプ演算子は、実務コードの見た目と設計を大きく変えています。

その一方で、注意したいのは trait はPHP 8で追加されたものではない という点です。trait は PHP 5.4 から使える仕組みで、クラス間でメソッドを再利用するための機能です。なので、「PHP 8系の新機能」として紹介するなら enum|> を中心にしつつ、trait は「以前からあるが、今でも重要な機能」として位置付けるのが正確です。

1. trait

これはPHP 8の新機能ではなく、昔からある

trait は、複数のクラスで共通のメソッドを使い回したいときに便利です。継承だと「親クラスは1つしか持てない」という制約がありますが、trait ならメソッド単位で再利用できます。

traitなしだとこうなりがち

<?php

class UserService
{
    public function log(string $message): void
    {
        echo "[LOG] " . $message . PHP_EOL;
    }
}

class OrderService
{
    public function log(string $message): void
    {
        echo "[LOG] " . $message . PHP_EOL;
    }
}

同じ log() が重複しています。

traitを使うとこうなる

<?php

trait LoggerTrait
{
    public function log(string $message): void
    {
        echo "[LOG] " . $message . PHP_EOL;
    }
}

class UserService
{
    use LoggerTrait;
}

class OrderService
{
    use LoggerTrait;
}

何がうれしいか

  • 共通処理をまとめられる
  • 継承より柔軟
  • Laravel などでもよく使われる

ただし、trait は PHP 5.4から存在 しているため、「PHP 8系で導入された機能」と説明してしまうと誤りです。

2. enum

PHP 8.1で追加された、かなり大きな進化

PHP 7系以下では、状態や種別を文字列や定数で管理することが多く、タイプミスに弱いという問題がありました。PHP 8.1 で enum が入ったことで、その問題をかなり自然に防げるようになりました。

PHP 7系以下の書き方

<?php

class UserStatus
{
    public const ACTIVE = 'active';
    public const INACTIVE = 'inactive';
    public const SUSPENDED = 'suspended';
}

function isActive(string $status): bool
{
    return $status === UserStatus::ACTIVE;
}

$status = 'actve'; // タイポしても実行時まで気づきにくい
var_dump(isActive($status)); // false

PHP 8.1以降の enum

<?php

enum UserStatus: string
{
    case ACTIVE = 'active';
    case INACTIVE = 'inactive';
    case SUSPENDED = 'suspended';
}

function isActive(UserStatus $status): bool
{
    return $status === UserStatus::ACTIVE;
}

$status = UserStatus::ACTIVE;
var_dump(isActive($status)); // true

違い

PHP 7系以下では「ただの文字列」だったものが、PHP 8.1以降では「意味を持った型」になります。
たとえば「active / inactive / suspended しか入らない」という制約を、コード上ではっきり表せます。

3. パイプ演算子 |>

PHP 8.5で追加

PHP 8.5では |> パイプ演算子が追加されました。これにより、処理を左から右へ流れるように書けるようになります。ネストした関数呼び出しが減るので、読みやすさがかなり上がります。

PHP 7系以下や8.4以前の書き方

<?php

$title = ' PHP 8.5 Released ';

$slug = strtolower(
    str_replace(
        '.',
        '',
        str_replace(' ', '-', trim($title))
    )
);

echo $slug; // php-85-released

ネストが深く、内側から読まないと流れが追いづらいです。

PHP 8.5の書き方

<?php

$title = ' PHP 8.5 Released ';

$slug = $title
    |> trim(...)
    |> (fn($str) => str_replace(' ', '-', $str))
    |> (fn($str) => str_replace('.', '', $str))
    |> strtolower(...);

echo $slug; // php-85-released

何がよいか

  • 上から下、左から右へ読める
  • 中間変数を増やさず処理をつなげられる
  • データ変換の連鎖が見やすい

たとえば配列加工でも相性がよいです。

<?php

$numbers = [1, 2, 3, 4, 5];

$result = $numbers
    |> array_filter($..., fn($n) => $n % 2 === 1)
    |> array_map(fn($n) => $n * 10, $...)
    |> array_values(...);

print_r($result); // [10, 30, 50]

4. match式

switchより安全で書きやすい

match は PHP 8.0 で追加されました。switch よりも厳密比較で、値を返せるのが便利です。

PHP 7系以下の switch

<?php

$status = 2;

switch ($status) {
    case 1:
        $label = '未対応';
        break;
    case 2:
        $label = '対応中';
        break;
    case 3:
        $label = '完了';
        break;
    default:
        $label = '不明';
}

PHP 8の match

<?php

$status = 2;

$label = match ($status) {
    1 => '未対応',
    2 => '対応中',
    3 => '完了',
    default => '不明',
};

違い

  • break 不要
  • 式として使える
  • == ではなく厳密比較

5. 属性(Attributes)

コメント風アノテーションから正式構文へ

PHP 7系以下では、メタ情報をDocBlockコメントに書いてフレームワーク側で解釈することが多くありました。PHP 8.0 以降は Attributes によって、言語仕様として安全にメタデータを付与できます。

PHP 7系以下

<?php

/**
 * @Route("/users")
 * @Auth("admin")
 */
class UserController
{
}

PHP 8以降

<?php

#[Route('/users')]
#[Auth('admin')]
class UserController
{
}

何がよいか

  • コメントではなく正式な構文
  • リファクタしやすい
  • IDEや静的解析と相性がよい

6. コンストラクタプロパティ昇格

PHP 8.0で定番になった書き方

PHP 7系以下だと、プロパティ定義と代入を別々に書いていました。PHP 8.0からは、コンストラクタ引数に publicprivate を書くだけでプロパティ宣言と代入をまとめられます。

PHP 7系以下

<?php

class User
{
    private string $name;
    private int $age;

    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

PHP 8以降

<?php

class User
{
    public function __construct(
        private string $name,
        private int $age
    ) {}
}

違い

かなり短くなります。
DTOや値オブジェクトでは特に恩恵が大きいです。

7. Union Types

型を複数許容できる

PHP 7系でも型宣言はありましたが、「string または null」のような複数型はDocBlock頼りなことが多くありました。PHP 8では型として表現できます。

PHP 7系以下

<?php

/**
 * @param int|string $id
 */
function findUser($id)
{
    // ...
}

PHP 8以降

<?php

function findUser(int|string $id): array|null
{
    // ...
    return null;
}

何がよいか

  • 型情報が実コードに乗る
  • IDE補完が強くなる
  • バグを早めに発見しやすい

8. named arguments

引数の意味が読みやすくなる

PHP 8.0から、関数呼び出し時に引数名を指定できます。

PHP 7系以下

<?php

htmlspecialchars($text, ENT_QUOTES, 'UTF-8', false);

何の値かわかりづらいです。

PHP 8以降

<?php

htmlspecialchars(
    string: $text,
    flags: ENT_QUOTES,
    encoding: 'UTF-8',
    double_encode: false
);

9. PHP 8.5の追加ポイント

パイプ演算子だけではない

PHP 8.5では |> のほかにも、clone() 時にプロパティを変更できる機能や #[\NoDiscard] 属性などが入っています。

Clone With

8.4以前

<?php

readonly class Color
{
    public function __construct(
        public int $red,
        public int $green,
        public int $blue,
        public int $alpha = 255,
    ) {}

    public function withAlpha(int $alpha): self
    {
        return new self($this->red, $this->green, $this->blue, $alpha);
    }
}

8.5

<?php

readonly class Color
{
    public function __construct(
        public int $red,
        public int $green,
        public int $blue,
        public int $alpha = 255,
    ) {}

    public function withAlpha(int $alpha): self
    {
        return clone($this, ['alpha' => $alpha]);
    }
}

#[\NoDiscard]

<?php

#[\NoDiscard]
function buildToken(): string
{
    return bin2hex(random_bytes(16));
}

buildToken(); // 戻り値を使わないと警告対象

APIの戻り値をうっかり無視するミスを減らせます。

まとめ

PHP 7系以下とPHP 8系の違いを一言でいうと、「動けばよいコード」から「安全で読みやすいコード」へ進化した という点にあります。

特に次の3つは押さえておくと理解しやすいです。

  • trait: 便利だが新機能ではない。PHP 5.4からある
  • enum: PHP 8.1で追加。文字列定数管理よりずっと安全
  • パイプ演算子 |>: PHP 8.5で追加。処理の流れがかなり読みやすくなる

つまり、PHP 8系は「新しい文法が増えた」だけではなく、型・設計・可読性を言語レベルで支える方向に進化した と捉えるとわかりやすいです。

前後の記事

関連記事

技術(バックエンド) 2026/4/2

Laravel12から13へ上げるときの注意点と確認項目

2026年3月17日にリリースされたLaravel13へ、Laravel12から上げる際に先に見ておきたいポイントを実務寄りに整理する。

技術(バックエンド) 2026/4/1

PHP8.4から8.5に上げるときの注意点と変更チェック項目

PHP8.4から8.5へ上げる際に、実務で確認しておきたい非互換やdeprecationの見どころを整理する。

技術(バックエンド) 2026/4/14

フレームワークや言語のアップデートを行うことで設計やロジックの勉強になる

簡単とみなされがちかつ業務として避けられがちなフレームワークや言語のアップデートを行うことで結構設計やロジックの勉強になるということ。