메인 콘텐츠로 건너뛰기

캐스트란

Eloquent의 캐스트는, 데이터베이스에서 취득한 생의 값을 PHP의 데이터 타입으로 변환하고, 저장 시에는 그 역변환을 하는 구조입니다. casts 메서드로 정의합니다.
protected function casts(): array
{
    return [
        'is_admin'   => 'boolean',
        'settings'   => 'array',
        'created_at' => 'datetime',
    ];
}

내장 캐스트의 종류

Laravel이 표준으로 제공하는 캐스트 목록입니다.
캐스트설명
integer / int정수로 변환
float / double부동소수점수로 변환
string문자열로 변환
boolean / bool진위값으로 변환(0/1 포함)
arrayJSON 문자열 ↔ PHP 배열
collectionJSON 문자열 ↔ Collection 인스턴스
objectJSON 문자열 ↔ stdObject 인스턴스
datetime문자열 ↔ Carbon 인스턴스
immutable_datetime문자열 ↔ CarbonImmutable 인스턴스
date문자열 ↔ Carbon(시각 없음)
timestamp문자열 ↔ UNIX 타임스탬프
encrypted저장 시에 암호화, 취득 시에 복호화
hashed저장 시에 해시화(읽기 전용 캐스트와 조합)
AsStringable::class문자열 ↔ Stringable 오브젝트
AsArrayObject::classJSON ↔ ArrayObject 인스턴스
AsCollection::classJSON ↔ Collection 인스턴스
AsArrayObjectAsCollection은, 배열의 특정 오프셋을 직접 변경할 수 있도록, Laravel 내부에서 커스텀 캐스트로서 구현되어 있습니다.

커스텀 캐스트 클래스의 작성

내장 캐스트로는 대응할 수 없는 변환이 필요한 경우, CastsAttributes 인터페이스를 구현한 커스텀 캐스트를 작성합니다.

인터페이스의 정의

프레임워크 본체의 컨트랙트는 다음과 같이 정의되어 있습니다.
// src/Illuminate/Contracts/Database/Eloquent/CastsAttributes.php

interface CastsAttributes
{
    /**
     * DBの生の値をPHPの値に変換する(読み取り時)
     *
     * @param  array<string, mixed>  $attributes  モデルのすべての属性値
     */
    public function get(Model $model, string $key, mixed $value, array $attributes);

    /**
     * PHPの値をDBに保存できる形に変換する(書き込み時)
     *
     * @param  array<string, mixed>  $attributes  モデルのすべての属性値
     */
    public function set(Model $model, string $key, mixed $value, array $attributes);
}
$attributes 인수에는 모델의 전 속성이 들어 있으므로, 여러 컬럼을 걸친 변환도 가능합니다(후술의 Value Object 패턴 참조).

기본적인 커스텀 캐스트의 구현

make:cast 커맨드로 뼈대를 생성합니다.
php artisan make:cast AsMoney
app/Casts/AsMoney.php가 생성됩니다. 예로 금액(정수로 저장)을 Money Value Object로 변환하는 캐스트를 구현합니다.
<?php

namespace App\Casts;

use App\ValueObjects\Money;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;

class AsMoney implements CastsAttributes
{
    /**
     * DBの整数値(円単位)を Money オブジェクトに変換する
     */
    public function get(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): Money {
        return new Money((int) $value);
    }

    /**
     * Money オブジェクトをDBに保存できる整数値に変換する
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): int {
        if ($value instanceof Money) {
            return $value->amount;
        }

        return (int) $value;
    }
}
모델에 캐스트를 적용합니다.
<?php

namespace App\Models;

use App\Casts\AsMoney;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    protected function casts(): array
    {
        return [
            'price' => AsMoney::class,
        ];
    }
}
이것으로 $order->priceMoney 인스턴스를 반환합니다.

Value Object 캐스트

여러 DB 컬럼을 정리하여 하나의 Value Object로서 다루는 패턴입니다.

구현 예: 주소 캐스트

address_line_oneaddress_line_two의 2컬럼을 Address Value Object로 정리합니다.
<?php

namespace App\ValueObjects;

use Illuminate\Contracts\Support\Arrayable;

class Address implements Arrayable, \JsonSerializable
{
    public function __construct(
        public readonly string $lineOne,
        public readonly string $lineTwo,
    ) {}

    public function toArray(): array
    {
        return [
            'line_one' => $this->lineOne,
            'line_two' => $this->lineTwo,
        ];
    }

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}
<?php

namespace App\Casts;

use App\ValueObjects\Address;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use InvalidArgumentException;

class AsAddress implements CastsAttributes
{
    /**
     * 複数カラムから Address オブジェクトを組み立てる
     */
    public function get(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): Address {
        return new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        );
    }

    /**
     * Address オブジェクトをカラムごとの配列に分解して返す
     *
     * @return array<string, string>
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): array {
        if (! $value instanceof Address) {
            throw new InvalidArgumentException('The given value is not an Address instance.');
        }

        return [
            'address_line_one' => $value->lineOne,
            'address_line_two' => $value->lineTwo,
        ];
    }
}
set 메서드에서 배열을 반환하면, Eloquent는 키를 컬럼명으로 하고, 값을 각각의 컬럼에 저장합니다. 단일 컬럼의 캐스트에서는 문자열이나 정수를 반환합니다.
모델에의 적용과 사용법은 다음과 같습니다.
<?php

namespace App\Models;

use App\Casts\AsAddress;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected function casts(): array
    {
        return [
            'address' => AsAddress::class,
        ];
    }
}
$user = User::find(1);

// Address オブジェクトとして取得できる
echo $user->address->lineOne;

// Value Object を変更すると保存時に自動的にDBに反映される
$user->address = new Address('123 Main St', 'Apt 4B');
$user->save();

Value Object의 캐시

Value Object로 변환된 속성값은 Eloquent에 의해 캐시됩니다. 같은 속성에 2번 접근해도, 같은 오브젝트 인스턴스가 반환됩니다. 캐시를 무효화하고 싶은 경우에는 $withoutObjectCaching 프로퍼티를 캐스트 클래스에 추가합니다.
class AsAddress implements CastsAttributes
{
    public bool $withoutObjectCaching = true;

    // ...
}

인바운드 캐스트(쓰기 전용)

DB에의 쓰기 시에만 변환을 하고, 읽기 시에는 변환하지 않는 캐스트입니다. CastsInboundAttributes 인터페이스를 구현합니다. 전형적인 용도는 해시화입니다. 비밀번호나 비밀값을 저장할 때만 변환하고, 읽기 시에는 해시값을 그대로 반환합니다.
php artisan make:cast AsHash --inbound
<?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
use Illuminate\Database\Eloquent\Model;

class AsHash implements CastsInboundAttributes
{
    public function __construct(
        protected string|null $algorithm = null,
    ) {}

    /**
     * 保存時にハッシュ化する
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): string {
        return is_null($this->algorithm)
            ? bcrypt($value)
            : hash($this->algorithm, $value);
    }
}

캐스트 파라미터

커스텀 캐스트에 파라미터를 전달하는 경우에는, 클래스명 뒤에 콜론 구분으로 지정합니다. 여러 파라미터는 콤마 구분입니다.
protected function casts(): array
{
    return [
        'secret' => AsHash::class.':sha256',
        'data'   => AsHash::class.':sha512',
    ];
}
파라미터는 캐스트 클래스의 컨스트럭터에 전달됩니다.
class AsHash implements CastsInboundAttributes
{
    public function __construct(
        protected string|null $algorithm = null, // ':sha256' が渡される
    ) {}
}

Castables: Value Object 측에 캐스트 로직을 갖게 하기

Castable 인터페이스를 구현한 Value Object는, 자신의 캐스트 클래스를 반환하는 castUsing 메서드를 갖습니다. 모델 측에서 캐스트 클래스를 몰라도 되므로, 도메인 로직이 정리됩니다.
<?php

namespace App\ValueObjects;

use App\Casts\AsAddress;
use Illuminate\Contracts\Database\Eloquent\Castable;

class Address implements Castable
{
    /**
     * このオブジェクトのキャストに使うクラスを返す
     *
     * @param  array<string, mixed>  $arguments
     */
    public static function castUsing(array $arguments): string
    {
        return AsAddress::class;
    }
}
모델 측은 캐스트 클래스 대신 Value Object 클래스를 지정합니다.
protected function casts(): array
{
    return [
        'address' => Address::class,
    ];
}
Castable과 무명 클래스를 조합하면, Value Object와 캐스트 로직을 하나의 파일에 정리할 수 있습니다.
class Address implements Castable
{
    public static function castUsing(array $arguments): CastsAttributes
    {
        return new class implements CastsAttributes
        {
            public function get(Model $model, string $key, mixed $value, array $attributes): Address
            {
                return new Address(
                    $attributes['address_line_one'],
                    $attributes['address_line_two'],
                );
            }

            public function set(Model $model, string $key, mixed $value, array $attributes): array
            {
                return [
                    'address_line_one' => $value->lineOne,
                    'address_line_two' => $value->lineTwo,
                ];
            }
        };
    }
}

$appends$hidden과의 상호작용

캐스트와 $appends, $hidden은 독립된 구조이지만, 조합할 때 주의가 필요합니다.
class User extends Model
{
    protected function casts(): array
    {
        return [
            'address' => AsAddress::class,
        ];
    }

    // toArray() / toJson() 時に address を除外する
    protected $hidden = ['address_line_one', 'address_line_two'];

    // キャスト済みの address をシリアライズ結果に含める
    protected $appends = ['address'];
}
$hidden에 지정하는 것은 DB의 컬럼명입니다. 캐스트를 통해 만들어지는 속성명(address)이 아니라, 원래의 컬럼명(address_line_one, address_line_two)을 지정합니다.

실행 시 캐스트의 추가

특정 쿼리나 요청만 캐스트를 추가하고 싶을 때는 mergeCasts 메서드를 사용합니다.
$user = User::find(1);

$user->mergeCasts([
    'extra_data' => 'array',
]);

다음 단계

Eloquent Observer와 모델 이벤트

모델의 저장·삭제 등의 라이프사이클 이벤트에 훅을 걸어 처리를 추가하는 방법을 배웁니다.
마지막 수정일 2026년 7월 13일