Laminas 是 Zend Framework 的延續與社群化版本,維持企業級的穩定與可擴充性。它提供兩條建站路線:傳統 MVC(laminas-mvc) 與 中介層/函式管線式(Mezzio)。本教學用「能上線」為目標,帶你從 0 建立專案、路由、控制器、視圖、DI 工廠與資料庫,最後補充表單驗證與 Mezzio 實戰。
一、安裝與專案骨架
- 系統需求:PHP 8.1+、Composer、啟用常見擴充(pdo、mbstring、openssl)。
- 官方網站: Laminas、 Laminas Docs、 Mezzio Docs
MVC 骨架安裝:
composer create-project laminas/laminas-mvc-skeleton myapp cd myapp php -S 0.0.0.0:8080 -t public Mezzio 骨架安裝:(若你想用中介層架構)
composer create-project mezzio/mezzio-skeleton myapi cd myapi php -S 0.0.0.0:8080 -t public 二、專案結構速覽(MVC)
module/:功能模組(每個模組自帶config、src、view)。config/:全域設定(autoload/*.global.php、*.local.php)。public/:前端入口(index.php)。vendor/:Composer 套件。
三、建立第一個模組與路由(MVC)
1) 建立模組目錄:
mkdir -p module/Blog/{config,src/Controller,view/blog} touch module/Blog/Module.php touch module/Blog/config/module.config.php 2) 註冊模組:在 config/modules.config.php 加入 'Blog'。
3) 設定路由與控制器(module/Blog/config/module.config.php):
<?php use Laminas\Router\Http\Segment; use Blog\Controller\PostController;
return [
'router' => [
'routes' => [
'blog' => [
'type' => Segment::class,
'options' => [
'route' => '/blog[/:id]',
'defaults' => [
'controller' => PostController::class,
'action' => 'index',
],
],
],
],
],
'controllers' => [
'factories' => [
PostController::class => Blog\Factory\PostControllerFactory::class,
],
],
'view_manager' => [
'template_path_stack' => [ DIR . '/../view' ],
],
];
四、控制器與 DI 工廠(MVC)
Laminas 採用 DI 工廠模式(Factory)建立物件,方便注入服務。
1) 控制器(module/Blog/src/Controller/PostController.php):
<?php namespace Blog\Controller;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
use Blog\Service\PostService;
class PostController extends AbstractActionController
{
public function __construct(private PostService $service) {}
public function indexAction()
{
$id = $this->params()->fromRoute('id');
$posts = $id ? [$this->service->find($id)] : $this->service->list();
return new ViewModel(['posts' => $posts]);
}
}
2) 工廠(module/Blog/src/Factory/PostControllerFactory.php):
<?php namespace Blog\Factory;
use Psr\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Blog\Controller\PostController;
use Blog\Service\PostService;
class PostControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $c, $requestedName, array $options = null)
{
return new PostController($c->get(PostService::class));
}
}
3) 服務註冊(module/Blog/config/module.config.php 補充):
return [ // ... 'service_manager' => [ 'factories' => [ Blog\Service\PostService::class => Blog\Factory\PostServiceFactory::class, ], ], ]; 五、服務層與資料庫(TableGateway / PDO)(MVC)
安裝 laminas/laminas-db:
composer require laminas/laminas-db 1) 建立服務(module/Blog/src/Service/PostService.php):
<?php namespace Blog\Service;
use Laminas\Db\TableGateway\TableGatewayInterface;
class PostService
{
public function __construct(private TableGatewayInterface $table) {}
public function list(): array
{
return $this->table->select()->toArray();
}
public function find(int $id): array|null
{
$row = $this->table->select(['id' => $id])->current();
return $row ? (array) $row : null;
}
}
2) 服務工廠(module/Blog/src/Factory/PostServiceFactory.php):
<?php namespace Blog\Factory;
use Psr\Container\ContainerInterface;
use Laminas\Db\Adapter\Adapter;
use Laminas\Db\TableGateway\TableGateway;
use Blog\Service\PostService;
class PostServiceFactory
{
public function __invoke(ContainerInterface $c): PostService
{
$adapter = $c->get(Adapter::class);
$table = new TableGateway('posts', $adapter);
return new PostService($table);
}
}
3) 設定資料庫連線(config/autoload/global.php / local.php):
<?php return [ 'db' => [ 'driver' => 'Pdo_Mysql', 'hostname' => '127.0.0.1', 'database' => 'myapp', 'username' => 'root', 'password' => 'secret', 'charset' => 'utf8mb4', ], 'service_manager' => [ 'factories' => [ Laminas\Db\Adapter\Adapter::class => Laminas\Db\Adapter\AdapterServiceFactory::class, ], ], ]; 六、視圖與模板(MVC)
建立視圖檔(module/Blog/view/blog/post/index.phtml):
<h2>Blog Posts</h2> <ul> <?php foreach ($this->posts as $post): ?> <li> <strong><?= $this->escapeHtml($post['title']) ?></strong> <div><?= $this->escapeHtml($post['excerpt']) ?></div> </li> <?php endforeach; ?> </ul> 七、表單與驗證(InputFilter)
- 安裝:
composer require laminas/laminas-form laminas/laminas-inputfilter laminas/laminas-validator - 在 Service/Controller 中組合 InputFilter,於 POST 前先做
setData()→isValid()。
<?php use Laminas\InputFilter\InputFilter;
$filter = new InputFilter();
$filter->add(['name' => 'title', 'required' => true, 'filters' => [['name' => 'StringTrim']], 'validators' => [['name' => 'StringLength','options' => ['min' => 3]]]]);
$filter->setData($this->params()->fromPost());
if (! $filter->isValid()) {
// 回傳錯誤訊息
}
八、錯誤處理與日誌
- 例外處理:在控制器或中介層捕捉,或使用
Mezzio Problem Details(API 適用)。 - 安裝日誌:
composer require laminas/laminas-log,於工廠注入 Logger。
九、Mezzio(中介層)快速起步
Mezzio 建構在 PSR-7/PSR-15 上,適合 API 與高自由度專案。
- 新增路由(
config/routes.php):
$app->get('/health', App\Handler\HealthCheckHandler::class, 'health'); 處理器(src/App/Handler/HealthCheckHandler.php):
<?php namespace App\Handler;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as Handler;
use Psr\Http\Message\ResponseInterface as Response;
use Laminas\Diactoros\Response\JsonResponse;
class HealthCheckHandler implements Handler
{
public function handle(Request $request): Response
{
return new JsonResponse(['status' => 'ok', 'time' => time()]);
}
}
中介層(Middleware)可用來做驗證、CORS、日誌、錯誤攔截,依序在 config/pipeline.php 排入。
十、部署最佳實務
- Config:把敏感設定放
local.php或環境變數($_ENV)。 - 快取:啟用 OPcache;開啟路由與設定快取(MVC:
config_cache_enabled)。 - Web 伺服器:Nginx/Apache 指向
public/;禁止存取module/與config/。 - 佈署:使用 Composer 安裝
--no-dev、跑資料遷移(Doctrine/自製 SQL)、加上健康檢查路由。
十一、常見踩雷
- 忘記註冊模組:新增模組後一定要在
modules.config.php加上。 - 工廠未綁定:控制器/服務沒在
factories註冊會報「無法建立服務」。 - 視圖路徑錯誤:檔名與資料夾需對應
view/{module}/{controller}/{action}.phtml。 - DB 連線字元集:MySQL 請使用
utf8mb4,避免表情符號亂碼。
十二、學習地圖與資源
- 官方文件: laminas-mvc、 laminas-db、 Mezzio
- 生態套件: laminas-form、 laminas-inputfilter、 laminas-validator
- 升級指引: Zend → Laminas 遷移
結語
如果你偏好穩健的 MVC 與明確的模組化,選 Laminas MVC;若你要高彈性的 API 與中介層管線,選 Mezzio。兩者都延續了 Zend 的工程嚴謹與企業級品質。照本文步驟走,你已具備做出能上線的專案雛形,接著把業務邏輯放進 Service、用表單與驗證把資料關卡守好,Laminas 就能長期托住你的產品。