跳至主要內容
技術

Laravel 12 起手式:從 Composer 到第一個 Route 的十分鐘

Laravel 12 起手式:從 Composer 到第一個 Route 的十分鐘
PHP/Laravel 完全指南 第 2 / 15 篇

本篇是「PHP/Laravel 完全指南」系列的第 2 / 15 篇。你可以從系列總覽開始閱讀,也可以直接接著看本文。

Laravel 是 PHP 生態系中最受歡迎的框架,沒有之一。它的設計哲學很簡單:讓開發者把時間花在業務邏輯上,而不是重複造輪子。從路由、資料庫、認證、佇列到排程任務,Laravel 全部幫你準備好了——而且 API 設計得優雅到你會覺得寫程式是一種享受。

但在享受之前,你得先讓它跑起來。好消息是,Laravel 的安裝流程已經簡化到一行指令就搞定。

版本說明(2026 年): Laravel 已於 2026-03-17 推出 Laravel 13(最新版,最低需求提升至 PHP 8.3+,主打 AI-native 工作流、JSON:API resources、向量/語意搜尋等)。本章內容以 Laravel 12 為基準撰寫,整本書的範例與目錄結構導覽都以 12 為準;如果你用 composer create-projectlaravel new 預設安裝,現在很可能裝到的是 Laravel 13。兩版的起手式(安裝、Route、Blade、.env)幾乎一致,本章內容仍然適用;差別主要在 Laravel 13 要求 PHP 8.3+,且部分模型/控制器等可改用新的 PHP attribute 寫法。想完全照本章操作,可在 composer create-project 後面指定版本:composer create-project laravel/laravel:"^12.0" jiu-hao-mai

這一章我們要做的事情很明確:裝好 Laravel、搞懂目錄結構、寫出第一個 Route 和 View。十分鐘之後,你的瀏覽器上會出現「揪好買」的首頁——這是我們整本書會一起打造的台灣團購平台專案。

不用擔心目錄裡那一堆資料夾看起來很嚇人。每個資料夾都有它明確的職責,我會一個一個帶你認識。學框架最怕的就是「知其然不知其所以然」,所以我們不只要讓它跑起來,還要搞清楚每一步發生了什麼事。

安裝 Laravel 12:一行指令搞定

確認你已經裝好 PHP 8.2+ 和 Composer(上一章 PHP 快速入門 有教),然後打開終端機:

composer create-project laravel/laravel jiu-hao-mai
cd jiu-hao-mai
php artisan serve

三行指令,打開瀏覽器訪問 http://localhost:8000,你就會看到 Laravel 的預設歡迎頁面。

專案命名: 我們把專案取名叫 jiu-hao-mai(揪好買的拼音),這是整本書會持續開發的團購平台。

另一種安裝方式:Laravel Installer

Laravel 也提供了官方安裝器,它可以在建立專案時互動式地選擇前端堆疊和 Starter Kit:

# 先安裝 Laravel Installer(只需要做一次)
composer global require laravel/installer

# 用 installer 建立專案
laravel new jiu-hao-mai

Installer 會問你幾個問題:要不要 Starter Kit?前端用 React、Vue、Livewire 還是 Svelte?(Laravel 12 用全新的 Starter Kit 取代了舊版的 Breeze 和 Jetstream。)我們這本書在第六章才會加入認證系統,所以現在先選 No starter kit,保持乾淨。

兩種方式的差異

composer create-projectlaravel new
需要先安裝 installer不用
互動式選擇沒有有(Starter Kit、測試框架等)
適合場景快速建立純淨專案需要一步到位設定完整堆疊
CI/CD 環境比較適合較不適合(互動式)

兩種方式建出來的專案結構完全一樣,選你喜歡的就好。

預設資料庫:SQLite

從 Laravel 11 開始,新建專案預設使用 SQLite 作為資料庫——不需要安裝 MySQL,開箱即用。專案根目錄會有一個 database/database.sqlite 檔案,零設定就能開始開發。等到要部署正式環境時,再換成 MySQL 或 PostgreSQL 也很容易(改個 .env 設定就好)。

目錄結構導覽:每個資料夾在幹嘛

cd jiu-hao-mai 之後,你會看到這樣的目錄結構:

jiu-hao-mai/
├── app/                 # 🧠 你的應用程式核心
│   ├── Http/
│   │   └── Controllers/ # Controller(處理 HTTP 請求的邏輯)
│   ├── Models/          # Eloquent Model(資料庫對應的 PHP 類別)
│   └── Providers/       # Service Provider(應用程式啟動設定)
├── bootstrap/           # 框架啟動程式(通常不需要動)
│   └── app.php          # 應用程式設定與 Middleware 註冊
├── config/              # 設定檔(database, mail, cache 等)
├── database/
│   ├── factories/       # Model Factory(測試資料產生器)
│   ├── migrations/      # Migration(資料表版本控制)
│   ├── seeders/         # Seeder(填充測試資料)
│   └── database.sqlite  # 預設的 SQLite 資料庫
├── public/              # 唯一對外公開的目錄(index.php 在這)
├── resources/
│   ├── css/             # CSS 原始檔
│   ├── js/              # JavaScript 原始檔
│   └── views/           # Blade 模板(HTML)
├── routes/
│   ├── console.php      # Artisan 自訂指令與排程
│   └── web.php          # 🌐 網頁路由(最常編輯的檔案之一)
│   # 注意:api.php 預設不存在,需要時執行 php artisan install:api
├── storage/             # 日誌、快取、上傳檔案
├── tests/               # 測試程式碼
├── .env                 # 環境變數(不進版控)
├── .env.example         # 環境變數範本(進版控)
├── artisan              # Artisan CLI 入口
├── composer.json        # PHP 相依套件
└── package.json         # 前端相依套件

Laravel 11+ 的精簡骨架: 如果你看過舊版 Laravel 的教學,可能會好奇 app/Http/Kernel.phpapp/Console/Kernel.php 去哪了?從 Laravel 11 開始,框架採用了精簡的應用程式骨架——Kernel 的設定被移到 bootstrap/app.php,Middleware 的註冊也在那裡。少了很多「看了不知道要幹嘛」的檔案,新手友善度大幅提升。

你最常碰的五個位置

位置用途頻率
routes/web.php定義 URL 路由每天
app/Http/Controllers/處理請求邏輯每天
app/Models/資料庫 Model經常
resources/views/Blade 模板(HTML)經常
database/migrations/資料表結構變更每次改資料庫

其他目錄在你需要的時候自然會碰到,現在不用記。

與其他框架的對照

如果你從其他框架轉過來,這張表幫你快速對應:

概念LaravelExpress (Node.js)Django (Python)Rails (Ruby)
路由routes/web.phpapp.js / router filesurls.pyconfig/routes.rb
控制器app/Http/Controllers/route handlersviews.pyapp/controllers/
模板resources/views/ (Blade)views/ (EJS/Pug)templates/app/views/ (ERB)
ORM Modelapp/Models/ (Eloquent)(Prisma/Sequelize)models.pyapp/models/
資料庫遷移database/migrations/(Prisma/Knex)migrations/db/migrate/
設定config/ + .env.envsettings.pyconfig/

php artisan:你的 Laravel 瑞士刀

artisan 是 Laravel 的命令列工具,它能幫你做幾乎所有事情——從產生程式碼到管理資料庫、從清快取到啟動開發伺服器。

# 查看所有可用指令
php artisan list

# 啟動開發伺服器
php artisan serve

# 產生 Controller
php artisan make:controller ProductController

# 產生 Model(順便建 migration 和 factory)
php artisan make:model Product -mf

# 執行資料庫 migration
php artisan migrate

# 列出所有已註冊的路由
php artisan route:list

# 清除各種快取
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear

# 進入互動式 PHP Shell(像 Node.js 的 REPL 或 Python 的 interactive shell)
php artisan tinker

Tinker:你的即時測試場

tinker 是 Laravel 內建的互動式 REPL,讓你可以直接操作 Model、測試邏輯、查詢資料庫——不用啟動瀏覽器:

php artisan tinker

>>> $user = new App\Models\User;
=> App\Models\User {#1234}

>>> config('app.name')
=> "Laravel"

>>> now()->format('Y-m-d')
=> "2026-06-08"

>>> exit

JS 開發者的類比: tinker 就像 Node.js 的 node interactive shell,但它自動載入了整個 Laravel 應用程式。Python 開發者可以想像成 python manage.py shell

make 指令:程式碼產生器

make 系列指令是你最常用的 artisan 指令。它們按照 Laravel 的慣例幫你產生檔案,省掉手動建立和複製貼上:

php artisan make:controller    # Controller
php artisan make:model         # Eloquent Model
php artisan make:migration     # 資料庫遷移
php artisan make:middleware     # Middleware
php artisan make:request        # Form Request(表單驗證)
php artisan make:policy         # 授權 Policy
php artisan make:command        # 自訂 Artisan 指令
php artisan make:event          # Event
php artisan make:listener       # Event Listener
php artisan make:job            # Queue Job
php artisan make:mail           # Mail
php artisan make:notification   # Notification
php artisan make:test           # 測試

不用全背,需要的時候 php artisan list make 查就好。

Route 基礎:URL 對應到程式碼

打開 routes/web.php,你會看到預設內容:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

一行就把根路徑 / 對應到 welcome 這個 Blade view。這就是 Laravel 路由的核心概念:定義 URL → 指定處理邏輯 → 回傳 Response

基本路由寫法

// GET 請求
Route::get('/about', function () {
    return view('about');
});

// POST 請求
Route::post('/contact', function () {
    // 處理表單提交
    return redirect('/thank-you');
});

// 帶參數的路由
Route::get('/products/{id}', function (string $id) {
    return "商品編號:{$id}";
});

// 可選參數
Route::get('/products/{category?}', function (?string $category = null) {
    return $category ? "分類:{$category}" : '所有商品';
});

路由搭配 Controller

在真實專案中,我們不會把邏輯寫在路由檔裡(那會變成一坨義大利麵)。取而代之,我們用 Controller 來處理:

php artisan make:controller PageController

這會在 app/Http/Controllers/ 產生一個檔案:

<?php

namespace App\Http\Controllers;

class PageController extends Controller
{
    public function home()
    {
        return view('home');
    }

    public function about()
    {
        return view('about');
    }
}

然後在路由裡指向 Controller:

use App\Http\Controllers\PageController;

Route::get('/', [PageController::class, 'home']);
Route::get('/about', [PageController::class, 'about']);

Express 開發者注意: Laravel 的路由語法是 Route::get('/path', [Controller::class, 'method'])。第二個參數不是 callback,而是一個陣列 [類別, 方法名]。這跟 Express 的 router.get('/path', controller.method) 概念一樣,語法不同。

查看所有路由

php artisan route:list
GET|HEAD  / ...................................................... PageController@home
GET|HEAD  /about ................................................. PageController@about

這個指令會列出所有已註冊的路由、HTTP 方法和對應的 Controller,debug 時超級好用。

Blade 初體驗:你的第一個 View

Blade 是 Laravel 的模板引擎。如果你用過 EJS(Express)、Jinja2(Python)或 ERB(Rails),概念完全一樣——在 HTML 裡嵌入動態資料。

Blade 檔案放在 resources/views/,副檔名是 .blade.php

基本語法

<!-- resources/views/home.blade.php -->
<!DOCTYPE html>
<html lang="zh-TW">
  <head>
    <meta charset="UTF-8" />
    <title>{{ $title }}</title>
  </head>
  <body>
    <h1>{{ $title }}</h1>
    <p>{{ $description }}</p>

    {{-- 這是 Blade 註解,不會輸出到 HTML --}}
    @if($products->count() > 0)
    <ul>
      @foreach($products as $product)
      <li>{{ $product->name }} - ${{ $product->price }}</li>
      @endforeach
    </ul>
    @else
    <p>目前沒有商品</p>
    @endif
  </body>
</html>

Blade 語法速查

語法用途類比
{{ $var }}輸出並自動 HTML 跳脫EJS 的 <%= var %>
{!! $html !!}輸出原始 HTML(不跳脫)EJS 的 <%- html %>
@if / @else / @endif條件判斷Jinja2 的 {% if %}
@foreach / @endforeach迴圈Jinja2 的 {% for %}
@extends('layout')繼承版面Jinja2 的 {% extends %}
@section / @yield定義/填充區塊Jinja2 的 {% block %}
{{-- 註解 --}}Blade 註解<!-- --> 但不輸出

從 Controller 傳資料給 View

// 在 Controller 裡
public function home()
{
    return view('home', [
        'title' => '揪好買 JiuHaoMai',
        'description' => '台灣最有溫度的團購平台',
    ]);
}

view() 的第二個參數是一個陣列,key 會變成 View 裡的變數名。'title' => '揪好買' 在 Blade 裡就是 $title

也可以用 compact() 語法糖:

public function home()
{
    $title = '揪好買 JiuHaoMai';
    $description = '台灣最有溫度的團購平台';

    return view('home', compact('title', 'description'));
}

Layout 機制:避免重複的 HTML

每個頁面都寫一遍 <html><head><body> 很蠢。Blade 的 Layout 機制幫你解決這個問題:

<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="zh-TW">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@yield('title', '揪好買') | 揪好買 JiuHaoMai</title>
  </head>
  <body>
    <nav>
      <a href="/">首頁</a>
      <a href="/about">關於我們</a>
    </nav>

    <main>@yield('content')</main>

    <footer>
      <p>&copy; 2026 揪好買 JiuHaoMai</p>
    </footer>
  </body>
</html>
<!-- resources/views/home.blade.php -->
@extends('layouts.app')
@section('title', '首頁')
@section('content')
<h1>歡迎來到揪好買</h1>
<p>台灣最有溫度的團購平台</p>
@endsection

@extends 指定要繼承哪個 layout,@section 填入 layout 裡 @yield 留下的空位。概念跟 Django 的 template inheritance 一模一樣。

.env 設定:環境變數管理

專案根目錄的 .env 檔案是 Laravel 的環境設定中心。所有敏感資訊(資料庫密碼、API Key、第三方服務密鑰)都放在這裡,而不是寫死在程式碼中。

# .env(節錄重要設定)
APP_NAME="揪好買"
APP_ENV=local
APP_KEY=base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
APP_DEBUG=true
APP_URL=http://localhost:8000

DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=jiu_hao_mai
# DB_USERNAME=root
# DB_PASSWORD=

MAIL_MAILER=log

在程式碼中讀取環境變數

// 方法一:env() 函式(只在 config 檔中使用)
// config/app.php
'name' => env('APP_NAME', '揪好買'),

// 方法二:config() 函式(在應用程式中使用)
$appName = config('app.name'); // '揪好買'

重要規則: 永遠不要在 Controller 或 Model 裡直接呼叫 env()。原因是 Laravel 在 production 會快取 config,env() 會回傳 null。正確做法是在 config/*.php 裡用 env() 讀取,然後在程式碼裡用 config() 存取。這個坑我保證你遲早會踩到,所以現在就記住。

.env vs .env.example

檔案進版控用途
.env❌ 不進真正的環境變數(含密碼)
.env.example✅ 進環境變數範本(不含真實值)

團隊開發時,新成員 clone 專案後會複製 .env.example.env,然後填入自己的設定。

cp .env.example .env
php artisan key:generate  # 產生 APP_KEY

與其他框架的比較

框架環境變數設定系統
Laravel.env + config/*.phpconfig('key')
Express.env + dotenv 套件process.env.KEY
Djangosettings.py + django-environsettings.KEY

Laravel 的 .env + config 兩層架構看起來多一步,但好處是 config 可以快取(php artisan config:cache),production 下效能更好。

揪好買專案啟動:建立首頁

理論講完了,讓我們動手把「揪好買」的首頁做出來。

Step 1:建立 Controller

php artisan make:controller PageController

編輯 app/Http/Controllers/PageController.php

<?php

namespace App\Http\Controllers;

class PageController extends Controller
{
    public function home()
    {
        return view('home', [
            'title' => '揪好買 JiuHaoMai',
            'description' => '台灣最有溫度的團購平台——找好物、揪好友、一起買更划算!',
            'features' => [
                ['icon' => '🛒', 'title' => '輕鬆開團', 'desc' => '三步驟建立團購,分享連結就能揪人'],
                ['icon' => '👥', 'title' => '揪團省更多', 'desc' => '人數越多折扣越大,好康大家一起享'],
                ['icon' => '🔔', 'title' => '到貨通知', 'desc' => '成團、付款、出貨,每一步都即時通知你'],
            ],
        ]);
    }
}

Step 2:建立 Layout

建立 resources/views/layouts/app.blade.php

<!DOCTYPE html>
<html lang="zh-TW">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@yield('title', '揪好買') | 揪好買 JiuHaoMai</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      body {
        font-family: -apple-system, 'Noto Sans TC', sans-serif;
        color: #1a1a2e;
      }
      nav {
        background: #16213e;
        padding: 1rem 2rem;
      }
      nav a {
        color: #e2e2e2;
        text-decoration: none;
        margin-right: 1.5rem;
        font-weight: 500;
      }
      nav a:hover {
        color: #0f9b8e;
      }
      .brand {
        font-size: 1.25rem;
        font-weight: 700;
        color: #0f9b8e;
      }
      main {
        max-width: 800px;
        margin: 0 auto;
        padding: 2rem;
      }
      footer {
        text-align: center;
        padding: 2rem;
        color: #666;
        font-size: 0.875rem;
      }
    </style>
  </head>
  <body>
    <nav>
      <a href="/" class="brand">🛒 揪好買</a>
      <a href="/about">關於我們</a>
    </nav>

    <main>@yield('content')</main>

    <footer>
      <p>&copy; 2026 揪好買 JiuHaoMai — 用 Laravel 12 打造</p>
    </footer>
  </body>
</html>

Step 3:建立首頁 View

建立 resources/views/home.blade.php

@extends('layouts.app')
@section('title', '首頁')
@section('content')
<div style="text-align: center; padding: 3rem 0;">
  <h1 style="font-size: 2.5rem; margin-bottom: 0.5rem;">{{ $title }}</h1>
  <p style="font-size: 1.25rem; color: #666;">{{ $description }}</p>
</div>

<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; margin-top: 2rem;">
  @foreach($features as $feature)
  <div style="text-align: center; padding: 2rem; border: 1px solid #eee; border-radius: 12px;">
    <div style="font-size: 2.5rem;">{{ $feature['icon'] }}</div>
    <h3 style="margin: 0.75rem 0 0.5rem;">{{ $feature['title'] }}</h3>
    <p style="color: #666; font-size: 0.9rem;">{{ $feature['desc'] }}</p>
  </div>
  @endforeach
</div>

<div style="text-align: center; margin-top: 3rem;">
  <p style="color: #999;">🚧 更多功能開發中——跟著這本書一起打造!</p>
</div>
@endsection

Step 4:設定路由

編輯 routes/web.php

<?php

use App\Http\Controllers\PageController;
use Illuminate\Support\Facades\Route;

Route::get('/', [PageController::class, 'home']);

Step 5:啟動!

php artisan serve

打開 http://localhost:8000,你應該會看到:

  • 頂部導航列,有「揪好買」品牌名和連結
  • 大標題「揪好買 JiuHaoMai」
  • 三個功能特色卡片:輕鬆開團、揪團省更多、到貨通知
  • 底部版權資訊

恭喜,你的第一個 Laravel 應用正在運行了。

剛才發生了什麼?

讓我們追蹤一下這個 request 的旅程(下一章會更深入):

  1. 瀏覽器發送 GET /localhost:8000
  2. Laravel 的 public/index.php 接收 request
  3. 路由系統查 routes/web.php,找到 GET / 對應 PageController@home
  4. PageController::home() 執行,準備資料,呼叫 view('home', [...])
  5. Blade 引擎渲染 resources/views/home.blade.php(套用 layout)
  6. 最終 HTML 回傳給瀏覽器

這六步就是 Laravel 處理每一個 HTTP request 的基本流程。下一章我們會深入 Request Lifecycle,了解 Middleware 和 Service Container 如何在這個流程中扮演角色。

小結:十分鐘後你已經會什麼了

讓我們盤點一下這一章學到的東西:

  • 安裝 Laravel——composer create-projectlaravel new,一行搞定
  • 目錄結構——知道 routes/app/Http/Controllers/resources/views/database/ 各自的職責
  • Artisan CLI——servemake:controllerroute:listtinker
  • 路由系統——在 routes/web.php 定義 URL,對應到 Closure 或 Controller
  • Blade 模板——{{ }} 輸出資料、@if/@foreach 控制流程、@extends/@yield 版面繼承
  • 環境設定——.env 存放敏感資訊,config() 讀取設定,永遠不在 Controller 裡直接呼叫 env()
  • 實作——「揪好買」首頁已經跑起來了

下一章,我們要揭開 Laravel 的「魔法」面紗——Request Lifecycle、Service Container 和 Middleware。聽起來很抽象,但理解這些概念之後,你才能真正駕馭這個框架,而不只是「它 work 了但我不知道為什麼」。

留言討論

esc
輸入關鍵字搜尋文章...
查看收藏 →