assert — 実行時前提を検証するアサート関数

PHP
  • カテゴリ: PHP
  • 掲載バージョン: PHP 8.4
  • 名前空間 / FQCN / コマンド: assert(mixed $expression, ?Throwable|string $description = null): bool
  • 関連: AssertionError / trigger_error / LogicException / InvalidArgumentException / php.ini: zend.assertions, assert.exception
  • 変更履歴: PHP 7 で“ゼロコスト”アサーション導入、Throwable指定可。PHP 7.2 で文字列式(eval)非推奨、PHP 8.0 で削除。PHP 8.x は zend.assertions / assert.exception を使用。

要点(TL;DR)

  • 用途: 開発時の不変条件や前提をチェックし、破れたら即座に失敗させる。
  • 最小: assert($x > 0, 'x must be positive');
  • :
    • 本番で zend.assertions=1 のままだと性能劣化
    • 文字列式 assert('2 > 1') は PHP 8 で不可
    • 例外が出ないときは zend.assertions / assert.exception の設定を確認

概要

assert() は「ここでは必ず〜であるべき」という開発時の前提を検証します。失敗時は例外(既定:AssertionError)を投げ、早期にバグを発見できます。入力検証や業務エラー処理とは目的が異なり、**本番では無効化(ゼロコスト)**する前提で使います。

構文 / シグネチャ

assert(bool|callable $expression, ?Throwable|string $description = null): bool
  • 引数(表) 引数 型 必須 既定値 説明 $expression bool | callable ✓ — true で合格。callable なら実行結果で判定。 $description Throwable | string | null null 失敗時のメッセージ、または投げる例外オブジェクト
  • 戻り値true(合格/無効化時)。失敗時は通常例外が投げられ制御は戻らない。
  • 例外/副作用:失敗時に AssertionError もしくは $description に渡した Throwable を送出。zend.assertions=-1 ではアサートコード自体が生成されず副作用なし(ゼロコスト)。

主要 ini 設定(PHP 8.x)

; 開発(デフォルト例)
zend.assertions=1
assert.exception=1   ; 失敗で AssertionError

; 本番
zend.assertions=-1   ; アサートを完全除去(ゼロコスト)
assert.exception=1

使用例

最小例

<?php
declare(strict_types=1);

$qty = 10;
assert($qty > 0, 'Quantity must be positive');

実務例(ドメイン不変条件 + カスタム例外)

<?php
declare(strict_types=1);

use LogicException;

final class Order
{
    public function __construct(
        public readonly int $id,
        public int $totalCents,
    ) {
        // 生成直後の整合性を保証(開発時のみ実行)
        assert($this->totalCents >= 0, new LogicException('Order total cannot be negative'));
    }

    public function applyDiscount(int $cents): void
    {
        $this->totalCents -= $cents;

        // 不変条件維持
        assert($this->totalCents >= 0, new LogicException('Discount made total negative'));
    }
}

よくある落とし穴・注意

  • 本番で有効のままzend.assertions=1 は常に評価されオーバーヘッド。必ず -1
  • 文字列式は不可assert('2 > 1') は PHP 8 で廃止。必ず ブール式または fn() => ... を渡す。
  • 例外が出ないassert.exception=0 だと例外ではなく警告扱い(運用非推奨)。
  • 用途の勘違い:ユーザー入力の検証や業務エラーは 例外/バリデーション を使う。assert() は開発時の契約・不変条件向け。

PHPカテゴリの補足

  • 必要拡張:なし(標準)
  • エラー形態:合格→継続、失敗→AssertionError$descriptionThrowable
  • エンコーディング:関与なし
  • 8.1/8.2/8.3/8.4 差分:挙動は安定。旧 ini(assert.active など)は PHP 8 で廃止済み。

代替・関連APIとの比較

  • 例外(LogicException / InvalidArgumentException:業務ルール/入力検証の失敗に使用。本番でも必ず実行
  • trigger_error():実行継続しつつ通知したいとき。契約破りの検出には不向き。
  • 静的解析・型:実行前に欠陥を減らす。assert() は実行時チェックで補完。

テスト例(Pest)

<?php

use AssertionError;

it('throws on failed assertion', function () {
    assert(1 === 2, 'should fail');
})->throws(AssertionError::class);

it('can throw custom exception', function () {
    assert(false, new LogicException('broken invariant'));
})->throws(LogicException::class);

トラブルシュート(エラー別)

症状/エラー原因対処
失敗しても何も起きないzend.assertions=-1 または =0開発時は =1 に。動作確認後は本番で =-1
例外が出ず警告だけassert.exception=0assert.exception=1 にする。
assert('A > B') が動かない文字列式廃止(PHP 8)ブール式または fn() => で書く。
本番で重いzend.assertions=1 のまま本番は zend.assertions=-1(ゼロコスト)。

参考リンク

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする