PHP Laravel ๊ฐœ๋ฐœ์ž ๋ฉด์ ‘ ์งˆ๋ฌธ 2026: ์™„๋ฒฝ ์ค€๋น„ ๊ฐ€์ด๋“œ

2026๋…„ Laravel 13 ๋Œ€์‘ ๋ฉด์ ‘ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค. Eloquent ORM, ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ, ์ธ์ฆ ํŒจํ„ด, ํ ์ฒ˜๋ฆฌ, ํ…Œ์ŠคํŠธ ์ „๋žต ๋“ฑ Laravel ์—”์ง€๋‹ˆ์–ด ๋ฉด์ ‘์—์„œ ์ž์ฃผ ๋ฌป๋Š” ํ•ต์‹ฌ ์ฃผ์ œ๋ฅผ ์ƒ์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

PHP Laravel ๊ฐœ๋ฐœ์ž ๋ฉด์ ‘ ์งˆ๋ฌธ 2026: ์™„๋ฒฝ ์ค€๋น„ ๊ฐ€์ด๋“œ

PHP Laravel ๊ฐœ๋ฐœ์ž ๋ฉด์ ‘์—์„œ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ ์ง€์‹๊ณผ ์†Œํ”„ํŠธ์›จ์–ด ์„ค๊ณ„ ์›์น™์„ ํ•จ๊ป˜ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. 2026๋…„ 3์›”์— ์ถœ์‹œ๋œ Laravel 13์—์„œ๋Š” AI SDK, PHP Attributes, Passkey ์ธ์ฆ์ด ๋„์ž…๋˜์—ˆ์œผ๋ฉฐ, ๋ฉด์ ‘๊ด€๋“ค์€ ์ตœ์‹  ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ดํ•ด์™€ ํ•ต์‹ฌ ๊ธฐ์ดˆ ์ง€์‹์„ ๋ชจ๋‘ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

๋ฉด์ ‘ ํ•ต์‹ฌ ์˜์—ญ

Laravel ๋ฉด์ ‘์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์„ฏ ๊ฐ€์ง€ ํ•ต์‹ฌ ์˜์—ญ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค: Eloquent ORM ๊ด€๊ณ„ ๋ฐ ์„ฑ๋Šฅ, ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ์™€ ์˜์กด์„ฑ ์ฃผ์ž…, ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ ํŒจํ„ด, ํ์™€ ์ž‘์—… ์ฒ˜๋ฆฌ, ํ…Œ์ŠคํŠธ ์ „๋žต์ž…๋‹ˆ๋‹ค. ์‹œ๋‹ˆ์–ด ํฌ์ง€์…˜์˜ ๊ฒฝ์šฐ ์•„ํ‚คํ…์ฒ˜ ๊ฒฐ์ •๊ณผ ํŒจํ‚ค์ง€ ์ƒํƒœ๊ณ„ ์ง€์‹๋„ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

Eloquent ORM ๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์งˆ๋ฌธ

Eloquent๋Š” Laravel ๋ฉด์ ‘์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ๋…ผ์˜๋˜๋Š” ์ฃผ์ œ์ž…๋‹ˆ๋‹ค. ๋ฉด์ ‘๊ด€์€ ์ง€์—ฐ ๋กœ๋”ฉ๊ณผ ์ฆ‰์‹œ ๋กœ๋”ฉ, ๊ด€๊ณ„ ์œ ํ˜•, ์ฟผ๋ฆฌ ์ตœ์ ํ™”์— ๋Œ€ํ•œ ์ดํ•ด๋„๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

Q: N+1 ๋ฌธ์ œ๋ž€ ๋ฌด์—‡์ด๋ฉฐ Laravel์€ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๊นŒ?

N+1 ๋ฌธ์ œ๋Š” ์ฝ”๋“œ๊ฐ€ ์ปฌ๋ ‰์…˜์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•œ ํ›„, ๊ฐ ํ•ญ๋ชฉ์˜ ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด N๊ฐœ์˜ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. Laravel์€ with()๋ฅผ ํ†ตํ•œ ์ฆ‰์‹œ ๋กœ๋”ฉ์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

app/Http/Controllers/PostController.phpphp
// N+1 ๋ฌธ์ œ: ๊ฒŒ์‹œ๋ฌผ์šฉ 1๊ฐœ ์ฟผ๋ฆฌ + ์ž‘์„ฑ์ž์šฉ N๊ฐœ ์ฟผ๋ฆฌ
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name; // ๊ฒŒ์‹œ๋ฌผ๋‹น ์ฟผ๋ฆฌ ๋ฐœ์ƒ
}

// ํ•ด๊ฒฐ์ฑ…: with()๋กœ ์ฆ‰์‹œ ๋กœ๋”ฉ
$posts = Post::with('author')->get(); // ์ด 2๊ฐœ ์ฟผ๋ฆฌ
foreach ($posts as $post) {
    echo $post->author->name; // ์ถ”๊ฐ€ ์ฟผ๋ฆฌ ์—†์Œ
}

Laravel 13์€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ strict ๋ชจ๋“œ๋ฅผ ์œ ์ง€ํ•˜์—ฌ ์ง€์—ฐ ๋กœ๋”ฉ ๋ฐœ์ƒ ์‹œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋ฏ€๋กœ N+1 ๋ฌธ์ œ๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Q: hasOne, hasMany, belongsTo, belongsToMany์˜ ์ฐจ์ด์ ์„ ์„ค๋ช…ํ•˜์‹ญ์‹œ์˜ค.

๊ด€๊ณ„์™ธ๋ž˜ ํ‚ค ์œ„์น˜์˜ˆ์‹œ
hasOne๊ด€๋ จ ๋ชจ๋ธUser hasOne Profile (profiles.user_id)
hasMany๊ด€๋ จ ๋ชจ๋ธUser hasMany Posts (posts.user_id)
belongsToํ˜„์žฌ ๋ชจ๋ธPost belongsTo User (posts.user_id)
belongsToManyํ”ผ๋ฒ— ํ…Œ์ด๋ธ”User belongsToMany Roles (role_user ํ…Œ์ด๋ธ”)

Q: ์†Œํ”„ํŠธ ์‚ญ์ œ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•๊ณผ ๊ทธ ์˜ํ–ฅ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜์‹ญ์‹œ์˜ค.

app/Models/Post.phpphp
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use SoftDeletes;
    
    // ์†Œํ”„ํŠธ ์‚ญ์ œ๋œ ๋ ˆ์ฝ”๋“œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ์™ธ๋จ
    // ํฌํ•จํ•˜๋ ค๋ฉด:
    // Post::withTrashed()->get();
    // ์‚ญ์ œ๋œ ๊ฒƒ๋งŒ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด:
    // Post::onlyTrashed()->get();
}

์†Œํ”„ํŠธ ์‚ญ์ œ๋Š” deleted_at ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋ช…์‹œ์ ์œผ๋กœ ์š”์ฒญํ•˜์ง€ ์•Š๋Š” ํ•œ ์ฟผ๋ฆฌ๋Š” ์†Œํ”„ํŠธ ์‚ญ์ œ๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์œ ๋‹ˆํฌ ์ œ์•ฝ ์กฐ๊ฑด์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋ฉฐ ์ตœ์ ์˜ ์„ฑ๋Šฅ์„ ์œ„ํ•ด deleted_at๋ฅผ ํฌํ•จํ•˜๋Š” ๋ณตํ•ฉ ์ธ๋ฑ์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ์™€ ์˜์กด์„ฑ ์ฃผ์ž…

์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ๋Š” Laravel์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ๋ฐ”์ธ๋”ฉ, ํ•ด๊ฒฐ, ์ปจํ…์ŠคํŠธ ์ฃผ์ž…์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ์ฃผ๋‹ˆ์–ด์™€ ์‹œ๋‹ˆ์–ด ์ง€์›์ž๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

Q: ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ๋ž€ ๋ฌด์—‡์ด๋ฉฐ ์™œ ์ค‘์š”ํ•ฉ๋‹ˆ๊นŒ?

์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ๋Š” ํด๋ž˜์Šค ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์˜์กด์„ฑ ์ฃผ์ž…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ํ•ด๊ฒฐํ•˜์—ฌ ๋А์Šจํ•œ ๊ฒฐํ•ฉ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

app/Providers/AppServiceProvider.phpphp
public function register(): void
{
    // ์ธํ„ฐํŽ˜์ด์Šค ๋ฐ”์ธ๋”ฉ
    $this->app->bind(
        PaymentGatewayInterface::class,
        StripePaymentGateway::class
    );
    
    // ์‹ฑ๊ธ€ํ†ค: ๋งค๋ฒˆ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค
    $this->app->singleton(ReportGenerator::class, function ($app) {
        return new ReportGenerator($app->make(Cache::class));
    });
}

Q: bind(), singleton(), instance()์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

  • bind(): ํด๋ž˜์Šค๊ฐ€ ํ•ด๊ฒฐ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
  • singleton(): ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ดํ›„ ํ•ด๊ฒฐ ์‹œ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜
  • instance(): ๊ธฐ์กด ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ปจํ…Œ์ด๋„ˆ์— ๋ฐ”์ธ๋”ฉ
app/Providers/AppServiceProvider.phpphp
// bind: ๋งค๋ฒˆ ์ƒˆ ์ธ์Šคํ„ด์Šค
$this->app->bind(Service::class, fn() => new Service());

// singleton: ์ „์ฒด ์š”์ฒญ ์ƒ๋ช…์ฃผ๊ธฐ ๋™์•ˆ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค
$this->app->singleton(Cache::class, fn() => new RedisCache());

// instance: ์ด๋ฏธ ์ธ์Šคํ„ด์Šคํ™”๋œ ๊ฐ์ฒด ๋ฐ”์ธ๋”ฉ
$config = new Config(['debug' => true]);
$this->app->instance(Config::class, $config);

์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ ๊ฐœ๋…์— ๋Œ€ํ•œ ์—ฐ์Šต์€ ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ & DI ๋ชจ๋“ˆ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Laravel ๋ฉด์ ‘ ์ค€๋น„๊ฐ€ ๋˜์…จ๋‚˜์š”?

์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ, flashcards, ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์—ฐ์Šตํ•˜์„ธ์š”.

์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ ํŒจํ„ด

Laravel 13์—์„œ๋Š” ๊ธฐ์กด ๋ฐฉ๋ฒ•๊ณผ ํ•จ๊ป˜ Passkey ์ธ์ฆ์ด ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฉด์ ‘๊ด€์€ Sanctum, Passport, ์ •์ฑ…, ๊ฒŒ์ดํŠธ์— ๋Œ€ํ•œ ์ง€์‹์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

Q: Sanctum๊ณผ Passport๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

๊ธฐ๋ŠฅSanctumPassport
์‚ฌ์šฉ ์‚ฌ๋ก€SPA, ๋ชจ๋ฐ”์ผ ์•ฑ, ๊ฐ„๋‹จํ•œ API ํ† ํฐOAuth2 ์„œ๋ฒ„, ์„œ๋“œํŒŒํ‹ฐ ์ ‘๊ทผ
ํ† ํฐ ์œ ํ˜•๊ฐ„๋‹จํ•œ API ํ† ํฐ, ์„ธ์…˜ ๊ธฐ๋ฐ˜OAuth2 ์•ก์„ธ์Šค ํ† ํฐ, ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ
๋ณต์žก๋„์ตœ์†Œํ•œ์˜ ์„ค์ •์™„์ „ํ•œ OAuth2 ๊ตฌํ˜„
ํ† ํฐ ์Šค์ฝ”ํ”„์–ด๋นŒ๋ฆฌํ‹ฐ(๋” ๊ฐ„๋‹จํ•จ)OAuth ์Šค์ฝ”ํ”„

Sanctum์€ ๋Œ€๋ถ€๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. Passport๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์„œ๋“œํŒŒํ‹ฐ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์œ„ํ•œ OAuth2 ์ œ๊ณต์ž ์—ญํ• ์„ ํ•ด์•ผ ํ•  ๋•Œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋น„๊ต๋Š” Laravel Sanctum vs Passport๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Q: ์ •์ฑ…(Policy)๊ณผ ๊ฒŒ์ดํŠธ(Gate)์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๊ฒŒ์ดํŠธ๋Š” ํด๋กœ์ € ๊ธฐ๋ฐ˜ ๊ถŒํ•œ ๋ถ€์—ฌ ํ™•์ธ์ž…๋‹ˆ๋‹ค. ์ •์ฑ…์€ ํŠน์ • ๋ชจ๋ธ์˜ ๊ถŒํ•œ ๋ถ€์—ฌ ๋กœ์ง์„ ๊ทธ๋ฃนํ™”ํ•˜๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

app/Policies/PostPolicy.phpphp
class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
    
    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id 
            || $user->hasRole('admin');
    }
}

// ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์‚ฌ์šฉ
public function update(Request $request, Post $post)
{
    $this->authorize('update', $post); // PostPolicy ์‚ฌ์šฉ
    // ... ์—…๋ฐ์ดํŠธ ๋กœ์ง
}

๊ถŒํ•œ ๋ถ€์—ฌ & ์ •์ฑ… ๋ชจ๋“ˆ์—์„œ ๊ณ ๊ธ‰ ๊ถŒํ•œ ๋ถ€์—ฌ ํŒจํ„ด์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

ํ์™€ ์ž‘์—… ์ฒ˜๋ฆฌ

ํ๋Š” ํ™•์žฅ ๊ฐ€๋Šฅํ•œ Laravel ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ๋ฉด์ ‘๊ด€์€ ์ž‘์—… ์„ค๊ณ„, ์‹คํŒจ ์ฒ˜๋ฆฌ, ํ ๋“œ๋ผ์ด๋ฒ„์— ๋Œ€ํ•œ ์ดํ•ด๋„๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

Q: Laravel์—์„œ ์‹คํŒจํ•œ ์ž‘์—…์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๊นŒ?

app/Jobs/ProcessPodcast.phpphp
class ProcessPodcast implements ShouldQueue
{
    use Queueable;
    
    public int $tries = 3;
    public int $backoff = 60; // ์žฌ์‹œ๋„ ๊ฐ„๊ฒฉ(์ดˆ)
    public int $timeout = 120;
    
    public function handle(): void
    {
        // ์ž‘์—… ๋กœ์ง
    }
    
    public function failed(Throwable $exception): void
    {
        // ๊ด€๋ฆฌ์ž์—๊ฒŒ ์•Œ๋ฆผ, ์™ธ๋ถ€ ์„œ๋น„์Šค์— ๋กœ๊ทธ
        Log::error('ํŒŸ์บ์ŠคํŠธ ์ฒ˜๋ฆฌ ์‹คํŒจ', [
            'podcast_id' => $this->podcast->id,
            'error' => $exception->getMessage()
        ]);
    }
}

์‹คํŒจํ•œ ์ž‘์—…์€ failed_jobs ํ…Œ์ด๋ธ”์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. php artisan queue:retry๋กœ ํŠน์ • ์ž‘์—…์„ ์žฌ์‹œ๋„ํ•˜๊ฑฐ๋‚˜ queue:retry all๋กœ ์ผ๊ด„ ์žฌ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Q: dispatch()์™€ dispatchSync()์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

  • dispatch(): ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ํ์— ์ž‘์—… ์ถ”๊ฐ€
  • dispatchSync(): ํ๋ฅผ ์šฐํšŒํ•˜์—ฌ ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์—์„œ ์ฆ‰์‹œ ์ž‘์—… ์‹คํ–‰

dispatchSync()๋Š” ํ…Œ์ŠคํŠธ๋‚˜ ๊ฒฐ๊ณผ๊ฐ€ ์ฆ‰์‹œ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์š”์ฒญ์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋„๋ก ๋Œ€๋ถ€๋ถ„์˜ ์ž‘์—…์— dispatch()๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Pest๋ฅผ ์‚ฌ์šฉํ•œ Laravel ํ…Œ์ŠคํŠธ

Laravel 13์€ ๊ธฐ๋ณธ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ Pest๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๋ฉด์ ‘๊ด€์€ ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ, ๋ชจํ‚น, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ŠคํŠธ ์ „๋žต์— ๋Œ€ํ•œ ์ดํ•ด๋„๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

Q: ์™ธ๋ถ€ API์— ์˜์กดํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๊นŒ?

tests/Feature/PaymentTest.phpphp
use App\Services\PaymentGateway;
use App\Services\FakePaymentGateway;

test('๊ฒฐ์ œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋จ', function () {
    // ํ…Œ์ŠคํŠธ์šฉ ํŽ˜์ดํฌ ๊ตฌํ˜„ ๋ฐ”์ธ๋”ฉ
    $this->app->bind(
        PaymentGateway::class,
        FakePaymentGateway::class
    );
    
    $response = $this->postJson('/api/payments', [
        'amount' => 1000,
        'currency' => 'usd'
    ]);
    
    $response->assertStatus(200)
        ->assertJson(['status' => 'completed']);
});

test('๊ฒฐ์ œ๊ฐ€ ๊ฒŒ์ดํŠธ์›จ์ด ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•จ', function () {
    $mock = Mockery::mock(PaymentGateway::class);
    $mock->shouldReceive('charge')
        ->once()
        ->andThrow(new PaymentFailedException('์นด๋“œ ๊ฑฐ๋ถ€'));
    
    $this->app->instance(PaymentGateway::class, $mock);
    
    $response = $this->postJson('/api/payments', [
        'amount' => 1000,
        'currency' => 'usd'
    ]);
    
    $response->assertStatus(422);
});

Q: RefreshDatabase์™€ DatabaseTransactions์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

  • RefreshDatabase: ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋‹น ํ•œ ๋ฒˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ณ  ๊ฐ ํ…Œ์ŠคํŠธ๋ฅผ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ž˜ํ•‘
  • DatabaseTransactions: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ด๋ฏธ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๊ฐ ํ…Œ์ŠคํŠธ๋ฅผ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ž˜ํ•‘

RefreshDatabase๋Š” CI/CD ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. DatabaseTransactions๋Š” ์Šคํ‚ค๋งˆ๊ฐ€ ์•ˆ์ •์ ์ผ ๋•Œ ๋กœ์ปฌ ๊ฐœ๋ฐœ์—์„œ ๋” ๋น ๋ฆ…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋Š” Pest๋ฅผ ์‚ฌ์šฉํ•œ Laravel ํ…Œ์ŠคํŠธ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Laravel 13 ๊ด€๋ จ ์งˆ๋ฌธ

๋ฉด์ ‘๊ด€๋“ค์€ Laracon EU 2026์—์„œ ๋ฐœํ‘œ๋œ Laravel 13 ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์ ์  ๋” ๋งŽ์ด ์งˆ๋ฌธํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Q: Laravel AI SDK๋ž€ ๋ฌด์—‡์ด๋ฉฐ ์–ธ์ œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

Laravel AI SDK๋Š” AI ์ž‘์—…์„ ์œ„ํ•œ ํ†ตํ•ฉ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค: ํ…์ŠคํŠธ ์ƒ์„ฑ, ์ž„๋ฒ ๋”ฉ, ๋„๊ตฌ ํ˜ธ์ถœ ์—์ด์ „ํŠธ, ์˜ค๋””์˜ค, ์ด๋ฏธ์ง€ ์ƒ์„ฑ. OpenAI, Anthropic ๋ฐ ๊ธฐํƒ€ ์ œ๊ณต์ž ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ์ถ”์ƒํ™”ํ•ฉ๋‹ˆ๋‹ค.

config/ai.php์—์„œ ๊ธฐ๋ณธ ์ œ๊ณต์ž ์ •์˜php
// ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉ
use Illuminate\Support\Facades\AI;

$response = AI::text('์ด ๊ธฐ์‚ฌ๋ฅผ ๊ฐœ๋ฐœ์ž ๋Œ€์ƒ์œผ๋กœ ์š”์•ฝ')
    ->withContext($articleContent)
    ->generate();

// ์‹œ๋งจํ‹ฑ ๊ฒ€์ƒ‰์šฉ ์ž„๋ฒ ๋”ฉ
$embedding = AI::embeddings($searchQuery)->generate();
$results = Post::query()
    ->nearestNeighbors('embedding', $embedding, 10)
    ->get();

SDK๋Š” ์—ฌ๋Ÿฌ ์ œ๊ณต์ž SDK๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ  AI ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

Q: Laravel 13์—์„œ PHP Attributes๋Š” ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

Laravel 13์—์„œ๋Š” ์ปดํฌ๋„ŒํŠธ ๊ตฌ์„ฑ์„ ์œ„ํ•œ ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ์˜ ๋Œ€์•ˆ์œผ๋กœ PHP 8 Attributes๊ฐ€ ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๋ณ€๊ฒฝ์ด๋ฉฐ ํ”„๋กœํผํ‹ฐ ๊ธฐ๋ฐ˜ ๊ตฌ์„ฑ์€ ๊ณ„์† ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

php
// ๊ธฐ์กด ์ ‘๊ทผ ๋ฐฉ์‹
class SendWelcomeEmail implements ShouldQueue
{
    public $queue = 'emails';
    public $tries = 3;
}

// Attributes๋ฅผ ์‚ฌ์šฉํ•œ Laravel 13
use Illuminate\Contracts\Queue\Attributes\Queue;
use Illuminate\Contracts\Queue\Attributes\Tries;

#[Queue('emails')]
#[Tries(3)]
class SendWelcomeEmail implements ShouldQueue
{
    // ๋” ๊น”๋”ํ•œ ํด๋ž˜์Šค ๋ณธ๋ฌธ
}

Attributes๋Š” IDE ์ง€์›์ด ํ–ฅ์ƒ๋˜๊ณ  ๊ตฌ์„ฑ์„ ํด๋ž˜์Šค ์ •์˜ ์ˆ˜์ค€์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ์Šต์„ ์‹œ์ž‘ํ•˜์„ธ์š”!

๋ฉด์ ‘ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์ง€์‹์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

2026๋…„ Laravel ๋ฉด์ ‘ ํ•ต์‹ฌ ํฌ์ธํŠธ

  • with()๋ฅผ ์‚ฌ์šฉํ•œ ์ฆ‰์‹œ ๋กœ๋”ฉ์„ ๋งˆ์Šคํ„ฐํ•˜๊ณ  ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ N+1 ์ฟผ๋ฆฌ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” strict ๋ชจ๋“œ๋ฅผ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค
  • ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ ๋ฐ”์ธ๋”ฉ์„ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค: ์ผ์‹œ์ ์ธ ๊ฒƒ์—๋Š” bind(), ๊ณต์œ  ์ธ์Šคํ„ด์Šค์—๋Š” singleton(), ์ธํ„ฐํŽ˜์ด์Šค ํ•ด๊ฒฐ์—๋Š” ์ปจํ…์ŠคํŠธ ๋ฐ”์ธ๋”ฉ
  • Sanctum๊ณผ Passport ์‚ฌ์šฉ ์‹œ๊ธฐ๋ฅผ ํŒŒ์•…ํ•ฉ๋‹ˆ๋‹ค: ํผ์ŠคํŠธํŒŒํ‹ฐ ์•ฑ์—๋Š” Sanctum, OAuth2 ์ œ๊ณต์ž ์‹œ๋‚˜๋ฆฌ์˜ค์—๋Š” Passport
  • $tries, $backoff, failed() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•œ ํ ์‹คํŒจ ์ฒ˜๋ฆฌ๋ฅผ ์‹œ์—ฐํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
  • Pest๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์™ธ๋ถ€ ์˜์กด์„ฑ์—๋Š” ๋ชจํ‚น์„ ์‚ฌ์šฉํ•˜๋ฉฐ RefreshDatabase์™€ DatabaseTransactions์˜ ์ฐจ์ด์ ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค
  • Laravel 13 ๊ธฐ๋Šฅ์— ์ต์ˆ™ํ•ด์ง‘๋‹ˆ๋‹ค: ํ†ตํ•ฉ AI ์ž‘์—…์„ ์œ„ํ•œ AI SDK, ๋” ๊น”๋”ํ•œ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์„ฑ์„ ์œ„ํ•œ PHP Attributes, Passkey ์ธ์ฆ
  • ๊ตฌํ˜„๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์—ฐ์Šต์„ ํ•ฉ๋‹ˆ๋‹ค: ๋ฉด์ ‘๊ด€์€ ์•”๊ธฐ๋ณด๋‹ค ์ถ”๋ก ์„ ์ค‘์š”์‹œํ•ฉ๋‹ˆ๋‹ค
์˜ค๋Š˜์˜ ์ฑŒ๋ฆฐ์ง€

Laravel ์ฝ”๋“œ์˜ ๋ฒ„๊ทธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‚˜์š”

์‹ค์ œ ์ฝ”๋“œ ํ•œ ์กฐ๊ฐ, ์ˆจ์€ ๋ฒ„๊ทธ ํ•˜๋‚˜, ํ•˜๋ฃจ ํ•œ ๋ฒˆ. ๊ณ„์ • ์—†์ด ๋ฐ”๋กœ ๋„์ „ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Anthony Fillion-Maillet

์ž‘์„ฑ์ž

Anthony Fillion-Maillet

SharpSkill ์ฐฝ์—…์ž

10๋…„ ์ด์ƒ ํ’€์Šคํƒ ๊ฐœ๋ฐœ์„ ํ•ด์™”์Šต๋‹ˆ๋‹ค. SharpSkill์„ ์šด์˜ํ•˜๋ฉฐ ์ด๊ณณ์— ๊ฒŒ์‹œ๋˜๋Š” ๋ชจ๋“  ๋‚ด์šฉ์— ์ฑ…์ž„์„ ์ง‘๋‹ˆ๋‹ค.

2026๋…„ 9์›” 7์ผ ์—…๋ฐ์ดํŠธ

๊ณต์œ 

๊ด€๋ จ ๊ธฐ์‚ฌ

PHP Laravel ํ”„๋ ˆ์ž„์›Œํฌ ๋ฉด์ ‘ ์งˆ๋ฌธ 2026: Eloquent, ํ, ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด ์™„๋ฒฝ ๊ฐ€์ด๋“œ

PHP Laravel ํ”„๋ ˆ์ž„์›Œํฌ ๋ฉด์ ‘ ์งˆ๋ฌธ 2026: Eloquent, ํ, ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด ์™„๋ฒฝ ๊ฐ€์ด๋“œ

2026๋…„ Laravel ๊ธฐ์ˆ  ๋ฉด์ ‘์—์„œ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” Eloquent ORM, ํ ์„ค๊ณ„, ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ ๊ด€๋ จ ์งˆ๋ฌธ๊ณผ ๋‹ต๋ณ€ ์˜ˆ์‹œ๋ฅผ ์ƒ์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. N+1 ๋ฌธ์ œ ํ•ด๊ฒฐ๋ถ€ํ„ฐ ์žก ๋ฐฐ์นญ, DI ํŒจํ„ด๊นŒ์ง€ ํฌ๊ด„์ ์œผ๋กœ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

Laravel Octane Swoole๊ณผ RoadRunner๋ฅผ ํ™œ์šฉํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™”

Laravel Octane 2026 ์™„์ „ ๊ฐ€์ด๋“œ: Swoole๊ณผ RoadRunner๋ฅผ ํ™œ์šฉํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™”

Laravel Octane์„ ์‚ฌ์šฉํ•œ ๊ณ ์„ฑ๋Šฅ PHP ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์ถ• ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. Swoole๊ณผ RoadRunner์˜ ์ฐจ์ด์ , ์„ค์ • ๋ฐฉ๋ฒ•, ๋ชจ๋ฒ” ์‚ฌ๋ก€, ๋ฉด์ ‘ ๋Œ€๋น„๊นŒ์ง€ ํฌ๊ด„์ ์œผ๋กœ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

Laravel Solutions: Advanced Patterns and Debugging

Laravel ์†”๋ฃจ์…˜: ๊ณ ๊ธ‰ ํŒจํ„ด, ๋””๋ฒ„๊น… ๋ฐ ๋ฉด์ ‘ ๋Œ€๋น„ 2026๋…„ํŒ

Laravel์˜ ๊ณ ๊ธ‰ ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด, ๋””๋ฒ„๊น… ๊ธฐ๋ฒ•, ๋ฉด์ ‘ ๋Œ€๋น„ ์ง€์‹์„ ์™„๋ฒฝํ•˜๊ฒŒ ๋งˆ์Šคํ„ฐํ•ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค ํด๋ž˜์Šค, ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํŒจํ„ด, Telescope๋ฅผ ํ™œ์šฉํ•œ ๋””๋ฒ„๊น…, Laravel ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ์ž์ฃผ ๋‚˜์˜ค๋Š” ๋ฉด์ ‘ ์งˆ๋ฌธ์„ ์ƒ์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค.