1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VB.NET 4.8.1を今の時代に触る!!PHP 8.x, TypeScript 5.xとの言語仕様比較(第17章 エラーハンドリング)

1
Last updated at Posted at 2025-12-27

目次
第16章 Null安全性

第17章 エラーハンドリング

17.1 例外の基本

PHP

<?php
try {
    throw new Exception("Something went wrong");
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
    echo "File: " . $e->getFile();
    echo "Line: " . $e->getLine();
    echo "Trace: " . $e->getTraceAsString();
} finally {
    echo "Cleanup";
}

// 複数の例外タイプ
try {
    // ...
} catch (InvalidArgumentException $e) {
    // 引数エラー
} catch (RuntimeException $e) {
    // 実行時エラー
} catch (Exception $e) {
    // その他
}

// PHP 8.0+ 複数の例外を1つの catch で
try {
    // ...
} catch (InvalidArgumentException | RuntimeException $e) {
    // どちらかの例外
}

// PHP 8.0+ 変数なしの catch
try {
    // ...
} catch (NotFoundException) {
    // 例外オブジェクトを使わない場合
}

TypeScript

try {
    throw new Error("Something went wrong");
} catch (e) {
    if (e instanceof Error) {
        console.log("Error:", e.message);
        console.log("Stack:", e.stack);
    }
} finally {
    console.log("Cleanup");
}

// 型アサーション
try {
    throw new Error("error");
} catch (e: unknown) {
    if (e instanceof Error) {
        console.log(e.message);
    } else if (typeof e === "string") {
        console.log(e);
    }
}

// never型を返す関数
function fail(message: string): never {
    throw new Error(message);
}

VB.NET

Try
    Throw New Exception("Something went wrong")
Catch ex As Exception
    Console.WriteLine("Error: " & ex.Message)
    Console.WriteLine("Source: " & ex.Source)
    Console.WriteLine("Stack: " & ex.StackTrace)
Finally
    Console.WriteLine("Cleanup")
End Try

' 複数の例外タイプ
Try
    ' ...
Catch ex As ArgumentException
    ' 引数エラー
Catch ex As InvalidOperationException
    ' 無効な操作
Catch ex As Exception
    ' その他
End Try

' When 句による条件付きキャッチ
Try
    ' ...
Catch ex As Exception When ex.Message.Contains("timeout")
    ' タイムアウトエラーのみ
Catch ex As Exception
    ' その他
End Try

17.2 例外クラス階層

PHP

Throwable
├── Error(内部エラー)
│   ├── ArithmeticError
│   ├── AssertionError
│   ├── CompileError
│   ├── ParseError
│   ├── TypeError
│   └── ValueError
└── Exception(ユーザー例外)
    ├── ErrorException
    ├── LogicException
    │   ├── BadFunctionCallException
    │   ├── BadMethodCallException
    │   ├── DomainException
    │   ├── InvalidArgumentException
    │   ├── LengthException
    │   └── OutOfRangeException
    └── RuntimeException
        ├── OutOfBoundsException
        ├── OverflowException
        ├── RangeException
        ├── UnderflowException
        └── UnexpectedValueException

TypeScript

Error
├── RangeError
├── ReferenceError
├── SyntaxError
├── TypeError
└── URIError

// 組み込みエラーは少ないため、カスタムエラーを定義することが多い

VB.NET

Exception
├── SystemException
│   ├── ArgumentException
│   │   ├── ArgumentNullException
│   │   └── ArgumentOutOfRangeException
│   ├── ArithmeticException
│   │   ├── DivideByZeroException
│   │   └── OverflowException
│   ├── FormatException
│   ├── IndexOutOfRangeException
│   ├── InvalidCastException
│   ├── InvalidOperationException
│   ├── NotImplementedException
│   ├── NotSupportedException
│   ├── NullReferenceException
│   └── OutOfMemoryException
└── ApplicationException(カスタム例外の基底クラス、非推奨)

17.3 カスタム例外

PHP

<?php
class UserNotFoundException extends Exception {
    public function __construct(
        public readonly int $userId,
        string $message = "User not found",
        int $code = 0,
        ?Throwable $previous = null
    ) {
        parent::__construct($message, $code, $previous);
    }

    public function getUserId(): int {
        return $this->userId;
    }
}

class ValidationException extends Exception {
    public function __construct(
        public readonly array $errors,
        string $message = "Validation failed"
    ) {
        parent::__construct($message);
    }
}

// 使用
try {
    throw new UserNotFoundException(123);
} catch (UserNotFoundException $e) {
    echo "User ID: " . $e->userId;
}

TypeScript

class UserNotFoundError extends Error {
    constructor(public readonly userId: number) {
        super(`User not found: ${userId}`);
        this.name = "UserNotFoundError";
        // ES5 ターゲットの場合に必要
        Object.setPrototypeOf(this, UserNotFoundError.prototype);
    }
}

class ValidationError extends Error {
    constructor(
        public readonly errors: Record<string, string[]>,
        message = "Validation failed"
    ) {
        super(message);
        this.name = "ValidationError";
        Object.setPrototypeOf(this, ValidationError.prototype);
    }
}

// 使用
try {
    throw new UserNotFoundError(123);
} catch (e) {
    if (e instanceof UserNotFoundError) {
        console.log("User ID:", e.userId);
    }
}

VB.NET

Public Class UserNotFoundException
    Inherits Exception

    Public ReadOnly Property UserId As Integer

    Public Sub New(userId As Integer)
        MyBase.New($"User not found: {userId}")
        Me.UserId = userId
    End Sub

    Public Sub New(userId As Integer, message As String)
        MyBase.New(message)
        Me.UserId = userId
    End Sub

    Public Sub New(userId As Integer, message As String, inner As Exception)
        MyBase.New(message, inner)
        Me.UserId = userId
    End Sub
End Class

Public Class ValidationException
    Inherits Exception

    Public ReadOnly Property Errors As Dictionary(Of String, String())

    Public Sub New(errors As Dictionary(Of String, String()))
        MyBase.New("Validation failed")
        Me.Errors = errors
    End Sub
End Class

' 使用
Try
    Throw New UserNotFoundException(123)
Catch ex As UserNotFoundException
    Console.WriteLine($"User ID: {ex.UserId}")
End Try

17.4 エラー伝播

PHP

<?php
// 例外の再スロー
function process(): void {
    try {
        doSomething();
    } catch (Exception $e) {
        // ログを取って再スロー
        log($e->getMessage());
        throw $e;
    }
}

// 例外のラップ
function processWithWrap(): void {
    try {
        doSomething();
    } catch (DatabaseException $e) {
        throw new ServiceException("Service failed", 0, $e);
    }
}

// グローバルエラーハンドラ
set_exception_handler(function (Throwable $e) {
    error_log($e->getMessage());
    http_response_code(500);
    echo "Internal Server Error";
});

TypeScript

// 例外の再スロー
async function process(): Promise<void> {
    try {
        await doSomething();
    } catch (e) {
        console.error(e);
        throw e;
    }
}

// 例外のラップ
async function processWithWrap(): Promise<void> {
    try {
        await doSomething();
    } catch (e) {
        throw new ServiceError("Service failed", { cause: e });
    }
}

// cause プロパティ(ES2022+)
class ServiceError extends Error {
    constructor(message: string, options?: ErrorOptions) {
        super(message, options);
    }
}

// グローバルエラーハンドラ(Node.js)
process.on('uncaughtException', (error) => {
    console.error('Uncaught Exception:', error);
    process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {
    console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});

VB.NET

' 例外の再スロー
Sub Process()
    Try
        DoSomething()
    Catch ex As Exception
        Log(ex.Message)
        Throw  ' 元の例外をそのまま再スロー
    End Try
End Sub

' 例外のラップ
Sub ProcessWithWrap()
    Try
        DoSomething()
    Catch ex As DatabaseException
        Throw New ServiceException("Service failed", ex)
    End Try
End Sub

' InnerException の活用
Sub HandleException(ex As Exception)
    Console.WriteLine($"Error: {ex.Message}")

    Dim inner = ex.InnerException
    While inner IsNot Nothing
        Console.WriteLine($"Caused by: {inner.Message}")
        inner = inner.InnerException
    End While
End Sub

' グローバルエラーハンドラ(Windows Forms)
Sub Main()
    AddHandler Application.ThreadException,
        Sub(sender, e)
            MessageBox.Show(e.Exception.Message)
        End Sub

    AddHandler AppDomain.CurrentDomain.UnhandledException,
        Sub(sender, e)
            Dim ex = DirectCast(e.ExceptionObject, Exception)
            MessageBox.Show(ex.Message)
        End Sub

    Application.Run(New MainForm())
End Sub

17.5 Result型パターン

PHP

<?php
class Result {
    private function __construct(
        private readonly bool $success,
        private readonly mixed $value,
        private readonly ?string $error
    ) {}

    public static function ok(mixed $value): self {
        return new self(true, $value, null);
    }

    public static function fail(string $error): self {
        return new self(false, null, $error);
    }

    public function isOk(): bool {
        return $this->success;
    }

    public function getValue(): mixed {
        if (!$this->success) {
            throw new RuntimeException("Cannot get value from failed result");
        }
        return $this->value;
    }

    public function getError(): ?string {
        return $this->error;
    }

    public function map(callable $fn): self {
        if (!$this->success) {
            return $this;
        }
        return self::ok($fn($this->value));
    }
}

// 使用
function divide(float $a, float $b): Result {
    if ($b === 0.0) {
        return Result::fail("Division by zero");
    }
    return Result::ok($a / $b);
}

$result = divide(10, 2);
if ($result->isOk()) {
    echo $result->getValue();
} else {
    echo $result->getError();
}

TypeScript

type Result<T, E = Error> =
    | { ok: true; value: T }
    | { ok: false; error: E };

function ok<T>(value: T): Result<T, never> {
    return { ok: true, value };
}

function err<E>(error: E): Result<never, E> {
    return { ok: false, error };
}

function divide(a: number, b: number): Result<number, string> {
    if (b === 0) {
        return err("Division by zero");
    }
    return ok(a / b);
}

// 使用
const result = divide(10, 2);
if (result.ok) {
    console.log(result.value);
} else {
    console.log(result.error);
}

// パターンマッチング風
function match<T, E, R>(
    result: Result<T, E>,
    patterns: { ok: (value: T) => R; err: (error: E) => R }
): R {
    return result.ok ? patterns.ok(result.value) : patterns.err(result.error);
}

const message = match(result, {
    ok: (value) => `Result: ${value}`,
    err: (error) => `Error: ${error}`
});

VB.NET

Public Class Result(Of T)
    Public ReadOnly Property IsSuccess As Boolean
    Public ReadOnly Property Value As T
    Public ReadOnly Property ErrorMessage As String

    Private Sub New(isSuccess As Boolean, value As T, errorMessage As String)
        Me.IsSuccess = isSuccess
        Me.Value = value
        Me.ErrorMessage = errorMessage
    End Sub

    Public Shared Function Ok(value As T) As Result(Of T)
        Return New Result(Of T)(True, value, Nothing)
    End Function

    Public Shared Function Fail(errorMessage As String) As Result(Of T)
        Return New Result(Of T)(False, Nothing, errorMessage)
    End Function

    Public Function Map(Of U)(fn As Func(Of T, U)) As Result(Of U)
        If Not IsSuccess Then
            Return Result(Of U).Fail(ErrorMessage)
        End If
        Return Result(Of U).Ok(fn(Value))
    End Function

    Public Function Match(Of U)(
        onSuccess As Func(Of T, U),
        onFailure As Func(Of String, U)) As U
        If IsSuccess Then
            Return onSuccess(Value)
        End If
        Return onFailure(ErrorMessage)
    End Function
End Class

' 使用
Function Divide(a As Double, b As Double) As Result(Of Double)
    If b = 0 Then
        Return Result(Of Double).Fail("Division by zero")
    End If
    Return Result(Of Double).Ok(a / b)
End Function

Dim result = Divide(10, 2)
If result.IsSuccess Then
    Console.WriteLine(result.Value)
Else
    Console.WriteLine(result.ErrorMessage)
End If

' パターンマッチング風
Dim message = result.Match(
    Function(v) $"Result: {v}",
    Function(e) $"Error: {e}"
)

17.6 ベストプラクティス

例外を使うべき場面

  • 予期しないエラー(ファイルが見つからない、ネットワークエラー)
  • 回復不能な状態
  • プログラミングエラー(不正な引数)

例外を避けるべき場面

  • 予期されるフロー制御(ユーザー入力の検証)
  • パフォーマンスが重要な場面
  • 正常な代替パスがある場合
// 悪い例:例外でフロー制御
function findUser(id: number): User {
    const user = database.get(id);
    if (!user) {
        throw new UserNotFoundError(id);
    }
    return user;
}

// 良い例:Result型または null
function findUser(id: number): User | null {
    return database.get(id);
}

// または
function findUser(id: number): Result<User, string> {
    const user = database.get(id);
    if (!user) {
        return err("User not found");
    }
    return ok(user);
}

第18章 リフレクションとメタプログラミング

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?