Zum Hauptinhalt springen

Was sind Casts?

Eloquent-Casts wandeln aus der Datenbank gelesene Rohwerte in PHP-Typen um und beim Speichern in die umgekehrte Richtung. Sie werden über die Methode casts definiert.
protected function casts(): array
{
    return [
        'is_admin'   => 'boolean',
        'settings'   => 'array',
        'created_at' => 'datetime',
    ];
}

Arten der integrierten Casts

Liste der von Laravel mitgelieferten Casts.
CastBeschreibung
integer / intIn Integer umwandeln
float / doubleIn Fließkommazahl umwandeln
stringIn String umwandeln
boolean / boolIn Boolean umwandeln (inklusive 0/1)
arrayJSON-String ↔ PHP-Array
collectionJSON-String ↔ Collection-Instanz
objectJSON-String ↔ stdObject-Instanz
datetimeString ↔ Carbon-Instanz
immutable_datetimeString ↔ CarbonImmutable-Instanz
dateString ↔ Carbon (ohne Zeit)
timestampString ↔ UNIX-Zeitstempel
encryptedVerschlüsselung beim Speichern, Entschlüsselung beim Lesen
hashedBeim Speichern hashen (kombiniert mit Read-only-Casts)
AsStringable::classString ↔ Stringable-Objekt
AsArrayObject::classJSON ↔ ArrayObject-Instanz
AsCollection::classJSON ↔ Collection-Instanz
AsArrayObject und AsCollection sind Laravel-intern als eigene Casts implementiert, damit einzelne Offsets eines Arrays direkt geändert werden können.

Eine eigene Cast-Klasse erstellen

Wenn die eingebauten Casts nicht ausreichen, erstellen Sie eine eigene Cast-Klasse, die das Interface CastsAttributes implementiert.

Definition des Interfaces

Der Framework-Contract sieht folgendermaßen aus:
// src/Illuminate/Contracts/Database/Eloquent/CastsAttributes.php

interface CastsAttributes
{
    /**
     * Wandelt den DB-Rohwert in einen PHP-Wert (beim Lesen).
     *
     * @param  array<string, mixed>  $attributes  Alle Attributwerte des Modells
     */
    public function get(Model $model, string $key, mixed $value, array $attributes);

    /**
     * Wandelt einen PHP-Wert in ein DB-taugliches Format (beim Schreiben).
     *
     * @param  array<string, mixed>  $attributes  Alle Attributwerte des Modells
     */
    public function set(Model $model, string $key, mixed $value, array $attributes);
}
Weil das Argument $attributes alle Modellattribute enthält, sind auch spaltenübergreifende Umwandlungen möglich (siehe Value-Object-Muster unten).

Grundlegende Implementierung eines eigenen Casts

Erzeugen Sie ein Gerüst mit make:cast.
php artisan make:cast AsMoney
Die Datei app/Casts/AsMoney.php wird angelegt. Als Beispiel implementieren wir einen Cast, der einen als Integer gespeicherten Geldbetrag in ein Money-Value-Object umwandelt.
<?php

namespace App\Casts;

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

class AsMoney implements CastsAttributes
{
    /**
     * Wandelt den DB-Integerwert (in Yen) in ein Money-Objekt um.
     */
    public function get(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): Money {
        return new Money((int) $value);
    }

    /**
     * Wandelt ein Money-Objekt in einen DB-tauglichen Integer um.
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): int {
        if ($value instanceof Money) {
            return $value->amount;
        }

        return (int) $value;
    }
}
Aktivieren Sie den Cast am Modell:
<?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->price liefert nun eine Money-Instanz.

Value-Object-Casts

Ein Muster, um mehrere DB-Spalten als ein einziges Value Object zu behandeln.

Beispiel: Adress-Cast

Die zwei Spalten address_line_one und address_line_two werden in ein Address-Value-Object zusammengefasst.
<?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
{
    /**
     * Aus mehreren Spalten ein Address-Objekt zusammenbauen.
     */
    public function get(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): Address {
        return new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        );
    }

    /**
     * Ein Address-Objekt in ein Array pro Spalte zerlegen.
     *
     * @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,
        ];
    }
}
Gibt set ein Array zurück, verwendet Eloquent die Schlüssel als Spaltennamen und speichert die Werte in die jeweiligen Spalten. Bei Ein-Spalten-Casts geben Sie einen String oder Integer zurück.
Die Anwendung am Modell und die Nutzung:
<?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);

// Als Address-Objekt lesen
echo $user->address->lineOne;

// Änderungen am Value Object werden beim Speichern automatisch in die DB übertragen
$user->address = new Address('123 Main St', 'Apt 4B');
$user->save();

Value-Object-Cache

In Value Objects umgewandelte Attributwerte werden von Eloquent gecacht. Beim zweifachen Zugriff auf dasselbe Attribut erhalten Sie dieselbe Instanz. Wenn Sie den Cache deaktivieren möchten, fügen Sie in der Cast-Klasse die Property $withoutObjectCaching hinzu.
class AsAddress implements CastsAttributes
{
    public bool $withoutObjectCaching = true;

    // ...
}

Inbound-Casts (nur Schreiben)

Ein Cast, der nur beim Schreiben in die DB umwandelt, beim Lesen aber nicht. Implementiert das Interface CastsInboundAttributes. Typischer Anwendungsfall ist Hashing: Beim Speichern von Passwörtern oder geheimen Werten wird gehasht, beim Lesen wird der Hash unverändert zurückgegeben.
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,
    ) {}

    /**
     * Beim Speichern hashen.
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): string {
        return is_null($this->algorithm)
            ? bcrypt($value)
            : hash($this->algorithm, $value);
    }
}

Cast-Parameter

Parameter an einen Cast übergeben Sie nach dem Klassennamen mit Doppelpunkt getrennt. Mehrere Parameter trennen Sie durch Komma.
protected function casts(): array
{
    return [
        'secret' => AsHash::class.':sha256',
        'data'   => AsHash::class.':sha512',
    ];
}
Die Parameter werden dem Konstruktor der Cast-Klasse übergeben.
class AsHash implements CastsInboundAttributes
{
    public function __construct(
        protected string|null $algorithm = null, // ':sha256' wird übergeben
    ) {}
}

Castables: Cast-Logik im Value Object

Ein Value Object, das das Interface Castable implementiert, besitzt eine Methode castUsing, die die zu verwendende Cast-Klasse zurückgibt. So muss das Modell die Cast-Klasse nicht kennen und die Domänenlogik bleibt aufgeräumt.
<?php

namespace App\ValueObjects;

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

class Address implements Castable
{
    /**
     * Gibt die zu verwendende Cast-Klasse zurück.
     *
     * @param  array<string, mixed>  $arguments
     */
    public static function castUsing(array $arguments): string
    {
        return AsAddress::class;
    }
}
Am Modell geben Sie statt der Cast-Klasse die Value-Object-Klasse an.
protected function casts(): array
{
    return [
        'address' => Address::class,
    ];
}
In Kombination mit Castable und einer anonymen Klasse können Sie Value Object und Cast-Logik in einer Datei bündeln.
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,
                ];
            }
        };
    }
}

Zusammenspiel mit $appends und $hidden

Casts, $appends und $hidden sind eigenständige Mechanismen. Bei der Kombination ist Sorgfalt geboten.
class User extends Model
{
    protected function casts(): array
    {
        return [
            'address' => AsAddress::class,
        ];
    }

    // address bei toArray()/toJson() ausschließen
    protected $hidden = ['address_line_one', 'address_line_two'];

    // Gecastetes address im Serialisierungsergebnis mitliefern
    protected $appends = ['address'];
}
In $hidden geben Sie DB-Spaltennamen an. Nicht den durch den Cast entstandenen Attributnamen (address), sondern die Ursprungsnamen (address_line_one, address_line_two).

Casts zur Laufzeit ergänzen

Wenn Sie nur für eine bestimmte Query oder Anfrage Casts ergänzen wollen, nutzen Sie mergeCasts.
$user = User::find(1);

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

Nächste Schritte

Eloquent-Observer und Modell-Events

Lernen Sie, wie Sie sich in Lebenszyklus-Events wie Speichern oder Löschen einklinken und eigene Verarbeitung ergänzen.
Zuletzt geändert am 13. Juli 2026