Laminas (Zend Framework)

技术栈
后端框架
phpenterprisecomponentsmvcmiddlewarepsr

概览

Laminas (Zend Framework)\n\nLaminas 是 Zend Framework 的继任者,由 Linux Foundation 托管的 PHP 企业级框架。它采用组件化架构,提供 60+ 独立可用的 PHP 包,完全遵循 PSR 标准。\n\n### 核心特性\n\n- 组件化架构:60+ 独立组件,按需选用(如 laminas-db、laminas-mail)\n- MVC 和中间件:同时支持传统 MVC 和 PSR-15 中间件模式\n- PSR 标准:全面遵循 PHP-FIG 标准\n- Mezzio:微框架/中间件框架,轻量灵活\n- API Tools:企业级 API 构建工具\n- 服务管理器:强大的 DI 容器\n- 数据库:laminas-db 抽象层 + ORM\n- 企业支持:长期 LTS 版本,适合大型项目

安装

1. 环境准备

  • OS:Linux / macOS / Windows
  • PHP:>= 8.1
  • PHP 扩展:json, mbstring, PDO, reflection, intl
  • Composer:最新稳定版
  • 数据库:MySQL 5.7+ / PostgreSQL 10+ / SQLite
  • 可选:Apache/nginx(生产部署)

2. 安装命令

Laminas MVC 骨架

composer create-project laminas/laminas-mvc-skeleton my-app
cd my-app

Mezzio 微框架(推荐 API 项目)

composer create-project mezzio/mezzio-skeleton my-api
cd my-api
# 选择安装选项:FastRoute / Whoops / 模块

独立组件安装(按需)

# 数据库组件
composer require laminas/laminas-db

# 邮件组件
composer require laminas/laminas-mail

# 认证组件
composer require laminas/laminas-authentication

# API Tools
composer require laminas-api-tools/api-tools

启动开发服务器

php -S localhost:8080 -t public/

3. 常见安装问题

缺少开发服务器支持

composer require --dev laminas/laminas-development-mode
composer development-enable

数据库驱动缺失

composer require laminas/laminas-db-adapter

权限问题

chmod -R 775 data/cache/

国内镜像

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

示例

Hello World:Mezzio (Laminas 微框架)

目标

使用 Mezzio 微框架创建最小 API,展示 Handler、路由和中间件模式。

完整代码

1. 创建项目(选择 FastRoute + Whoops + 最小模块)

composer create-project mezzio/mezzio-skeleton hello-api
cd hello-api

2. 创建 Hello Handler

mkdir -p src/App/Handler

src/App/Handler/HelloHandler.php

<?php

namespace App\Handler;

use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class HelloHandler implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        return new JsonResponse([
            'message' => 'Hello, Vibe!',
            'framework' => 'Mezzio (Laminas)',
            'php_version' => PHP_VERSION,
            'timestamp' => date('c'),
        ]);
    }
}

3. 创建带参数的 Greet Handler

src/App/Handler/GreetHandler.php

<?php

namespace App\Handler;

use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class GreetHandler implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $name = $request->getAttribute('name', 'World');

        return new JsonResponse([
            'message' => "Hello, {$name}!",
            'powered_by' => 'Mezzio',
        ]);
    }
}

4. 注册路由 — config/routes.php

use App\Handler\HelloHandler;
use App\Handler\GreetHandler;

return function (Application $app, MiddlewareFactory $factory, ContainerInterface $container): void {
    $app->get('/api/hello', HelloHandler::class, 'hello');
    $app->get('/api/hello/{name}', GreetHandler::class, 'greet');
};

运行步骤

composer serve
# 或 php -S localhost:8080 -t public/

预期输出

curl http://localhost:8080/api/hello
# {"message":"Hello, Vibe!","framework":"Mezzio (Laminas)","php_version":"8.2.0","timestamp":"..."}

curl http://localhost:8080/api/hello/World
# {"message":"Hello, World!","powered_by":"Mezzio"}

教程

Laminas MVC 入门教程:博客应用

1. 背景

Laminas MVC 是企业级 PHP 开发的经典选择。本教程通过构建博客应用,掌握 MVC 骨架中的 Module、Controller、Service 和 ORM。

2. 前置概念

概念 说明
Module Laminas 的模块单元,每个功能一个模块
ModuleManager 加载和配置模块
ServiceManager DI 容器,管理服务实例
TableGateway 数据库表抽象模式

3. 分步操作

步骤一:创建项目

composer create-project laminas/laminas-mvc-skeleton blog-app
cd blog-app
composer development-enable

步骤二:创建 Blog 模块

# 模块目录结构
mkdir -p module/Blog/src/{Controller,Model,Form}
mkdir -p module/Blog/view/blog/blog

module/Blog/Config/module.config.php

<?php
namespace Blog;

use Laminas\Router\Http\Segment;

return [
    'router' => [
        'routes' => [
            'blog' => [
                'type' => Segment::class,
                'options' => [
                    'route' => '/blog[/:action[/:id]]',
                    'defaults' => [
                        'controller' => Controller\BlogController::class,
                        'action' => 'index',
                    ],
                ],
            ],
        ],
    ],
    'controllers' => [
        'factories' => [
            Controller\BlogController::class => function ($container) {
                return new Controller\BlogController($container->get('BlogTable'));
            },
        ],
    ],
    'view_manager' => [
        'template_path_stack' => [
            'blog' => __DIR__ . '/../view',
        ],
    ],
];

module/Blog/Module.php

<?php
namespace Blog;

class Module
{
    public function getConfig(): array
    {
        return include __DIR__ . '/Config/module.config.php';
    }
}

步骤三:创建数据库和 TableGateway

module/Blog/src/Model/Post.php

<?php
namespace Blog\Model;

class Post
{
    public int $id;
    public string $title;
    public string $content;
    public string $created_at;

    public function exchangeArray(array $data): void
    {
        $this->id = (int) ($data['id'] ?? 0);
        $this->title = $data['title'] ?? '';
        $this->content = $data['content'] ?? '';
        $this->created_at = $data['created_at'] ?? date('Y-m-d H:i:s');
    }
}

module/Blog/src/Model/BlogTable.php

<?php
namespace Blog\Model;

use Laminas\Db\TableGateway\TableGateway;
use Laminas\Db\Sql\Select;

class BlogTable
{
    public function __construct(private TableGateway $tableGateway) {}

    public function fetchAll(): iterable
    {
        return $this->tableGateway->select(function (Select $select) {
            $select->order('created_at DESC');
        });
    }

    public function getPost(int $id): ?Post
    {
        return $this->tableGateway->select(['id' => $id])->current() ?: null;
    }

    public function savePost(Post $post): void
    {
        $data = [
            'title' => $post->title,
            'content' => $post->content,
        ];

        if ($post->id === 0) {
            $this->tableGateway->insert($data);
        } else {
            $this->tableGateway->update($data, ['id' => $post->id]);
        }
    }
}

步骤四:创建控制器

module/Blog/src/Controller/BlogController.php

<?php
namespace Blog\Controller;

use Blog\Model\BlogTable;
use Blog\Model\Post;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class BlogController extends AbstractActionController
{
    public function __construct(private BlogTable $table) {}

    public function indexAction(): ViewModel
    {
        return new ViewModel(['posts' => $this->table->fetchAll()]);
    }

    public function addAction()
    {
        $request = $this->getRequest();
        if ($request->isPost()) {
            $post = new Post();
            $post->exchangeArray($request->getPost()->toArray());
            $this->table->savePost($post);
            return $this->redirect()->toRoute('blog');
        }
        return new ViewModel();
    }
}

步骤五:注册模块

config/modules.config.php

return [
    'Laminas\ZendFrameworkBridge',
    'Laminas\Router',
    'Application',
    'Blog',  // ← 新增
];

4. 验证

php -S localhost:8080 -t public/
# 访问 http://localhost:8080/blog

5. 思考题

  1. 如何用 Laminas Form 代替手动表单?
  2. 如何使用 AbstractRestfulController 构建 REST API?
  3. 如何集成 Doctrine ORM 替代 TableGateway?