PHP still runs roughly 72% of all websites whose server-side language is known, and a growing share of that traffic is JSON, not HTML. Yet the framework you pick to expose that JSON in 2026 determines whether you ship in a week or spend three months arguing about serializer groups. API Platform just shipped 5.0.6, Slim is quietly sitting on 12,280 GitHub stars with a 4.15.3 release in November 2026, and Laminas API Tools — the enterprise option — has 36 stars and a last release in January 2026. Those three numbers tell you almost everything you need to know, but not quite.

TL;DR: The 30-Second Verdict

Pick API Platform if your API is a data model with HTTP on top — entities, filters, pagination, OpenAPI, GraphQL, all generated from PHP attributes. Pick Slim if your API is a handful of endpoints behind a PSR-15 middleware stack and you want to understand every line of the request lifecycle. Do not pick Laminas API Tools for a new project in 2026 — its admin UI is powerful, but 36 stars and one release in the last two years means you are your own support contract. Migrate existing Laminas installs to API Platform 5 if you can.

Side-by-Side Comparison

DimensionAPI PlatformSlimLaminas API Tools
Latest release5.0.64.15.31.7.0
GitHub stars2,58112,28036
LicenseMITMITBSD-3-Clause
Last commit2026-11-062026-11-012026-01-27
OpenAPI specGenerated automatically from attributesYou write it (or bolt on a generator)Generated by the admin module
GraphQLBuilt inNot includedNot included
Admin UISeparate (React) or Symfony bundleNoneBuilt in (development tool)
Learning curveMedium — Symfony knowledge helps a lotLow — one AppFactory, one routerHigh — module manager, Zend-era concepts
Container footprint~700 MB full stack (PHP-FPM + Postgres + Caddy)~120 MB (PHP-FPM + your code)~450 MB
Best fitDomain-driven REST/GraphQL backendsMicroservices, webhooks, thin gatewaysLong-lived enterprise APIs

Decision Matrix: Pick in 10 Seconds

Your situationRecommendedWhy
20+ related resources with filters, pagination, validationAPI PlatformYou get all of it from attribute annotations — hand-writing it is weeks of work
5 endpoints, one database, deployed in a single containerSlimNothing to configure, nothing to upgrade, nothing to learn
You need a browsable admin to manage API endpointsLaminas API ToolsIts admin module is the only one of the three with a GUI for endpoint definitions
Team already writes Symfony servicesAPI PlatformIt is a Symfony bundle; your DI, security and console knowledge transfers directly
You must expose the same data as REST and GraphQLAPI PlatformGraphQL comes free with the same resource definition
You are proxying or aggregating other servicesSlimMiddleware-first design, no ORM assumptions
Greenfield project in 2026 with no legacyAPI Platform or SlimLaminas’ ecosystem activity is too thin to bet a new product on

API Platform 5.0 — The Data Model Is the API

API Platform’s pitch is that you describe a resource once and get REST, GraphQL, OpenAPI, Hydra, pagination, filtering and validation out of the other end. In 5.x that description lives in PHP attributes on your entity classes — no YAML, no XML.

Bootstrap the full stack (API + Postgres + Caddy) with the official skeleton:

1
2
3
4
5
composer create-project api-platform/api-platform my-api
cd my-api
docker compose up -d
# API:     http://localhost:8000
# Docs:    http://localhost:8000/docs

API Platform welcome screen showing the generated API entrypoint

The skeleton ships a composer.json requiring api-platform/core: ^5.0 and a docker-compose.yml with php, database (Postgres 16) and caddy services. A minimal resource looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
// src/Entity/Invoice.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity]
#[ApiResource(
    operations: [new Get(), new GetCollection(), new Post()],
    paginationItemsPerPage: 30
)]
class Invoice
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 40)]
    #[Assert\NotBlank]
    private string $number = '';

    #[ORM\Column(type: 'decimal', precision: 12, scale: 2)]
    #[Assert\Positive]
    private string $total = '0.00';

    public function getId(): ?int { return $this->id; }
    public function getNumber(): string { return $this->number; }
    public function setNumber(string $number): self { $this->number = $number; return $this; }
    public function getTotal(): string { return $this->total; }
    public function setTotal(string $total): self { $this->total = $total; return $this; }
}

Run php bin/console doctrine:schema:update --force (or a Doctrine migration), and you immediately have GET /api/invoices, GET /api/invoices/{id}, POST /api/invoices, a Hydra/JSON-LD representation, an OpenAPI 3.1 document at /docs, and — if you enable it — a GraphQL endpoint. Filters are one attribute away:

1
2
3
4
5
6
7
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;

#[ApiResource]
#[SearchFilter(['number', 'customer.name'])]
#[DateFilter(['createdAt'])]
class Invoice { /* ... */ }

Where it hurts: API Platform assumes Doctrine. If your data lives in a legacy schema you cannot map, or in an event-sourced store, you will spend more time fighting state providers than writing endpoints. The full Docker stack also costs real memory — budget 1 GB RAM before you add workers.

Slim 4.15 — Routing, Middleware, Done

Slim does one thing: it takes a PSR-7 request, runs it through a PSR-15 middleware pipeline, dispatches it to a handler, and returns a PSR-7 response. That is the entire mental model, and it fits on a napkin.

1
2
composer require slim/slim
composer require slim/psr7   # PSR-7 implementation for AppFactory auto-detection
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
// public/index.php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();
$app->addBodyParsingMiddleware();
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);

$app->get('/health', function (Request $req, Response $res) {
    $res->getBody()->write(json_encode(['status' => 'ok']));
    return $res->withHeader('Content-Type', 'application/json');
});

$app->post('/webhooks/github', function (Request $req, Response $res) {
    $payload = $req->getParsedBody();
    $signature = $req->getHeaderLine('X-Hub-Signature-256');
    // verify HMAC, enqueue job, return 202
    $res->getBody()->write(json_encode(['accepted' => true]));
    return $res->withStatus(202)->withHeader('Content-Type', 'application/json');
});

$app->run();

Serve it behind PHP-FPM with nginx — the only non-obvious part is that every unknown path must be handed to index.php, otherwise your routes 404:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
server {
    listen 80;
    server_name api.example.com;
    root /var/www/api/public;
    index index.php;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Where it hurts: Slim gives you no OpenAPI, no pagination, no validation layer, no serializer. Every one of those is a PSR-compatible package you choose and maintain yourself. That is freedom at 5 endpoints and a liability at 50.

Laminas API Tools 1.7 — The Enterprise Admin Nobody Maintains

Laminas API Tools (formerly Apigility) is the only framework here with a web-based admin UI for defining endpoints. You build resources, configure content negotiation, and wire validators through a browser instead of writing configuration files. For a certain generation of enterprise PHP teams, that was a genuine selling point.

1
2
3
4
5
composer create-project -sdev laminas-api-tools/api-tools-skeleton path/to/install
cd path/to/install
composer development-enable
php -S 0.0.0.0:8080 -t public public/index.php
# Admin UI: http://localhost:8080/admin

The skeleton’s README is refreshingly honest about the operational traps: the admin must not run with an opcode cache enabled (APC, OpCache) or it can corrupt API definitions, and Apache forbids %2F and %5C in URI paths, so the admin needs a tuned vhost. The admin is explicitly a development tool — you composer development-disable before production.

Where it hurts: 36 stars, a 1.7.0 release in January 2026, and a module-manager architecture rooted in the Zend Framework era. It works, but you are maintaining a stack whose community has largely moved to Symfony and Laravel. For an existing install with 80 endpoints, migrating is expensive; for anything new, it is a bet against the ecosystem.

Pitfalls, Migration Notes and Performance Traps

1. API Platform’s Docker stack is not production-shaped. The skeleton is a developer environment: Caddy with a self-signed cert, Postgres with a default password, Xdebug enabled. Strip Xdebug (RUN pecl uninstall xdebug or remove the ini) before benchmarking — it routinely halves throughput.

2. Slim returns 404s behind nginx until you add try_files. This is the single most common Slim deployment bug. Slim has no .htaccess equivalent, so the web server must route unknown paths to index.php.

3. Migrating from Laminas API Tools to API Platform is a rewrite, not a port. Laminas resource definitions live in module config; API Platform definitions live in PHP attributes on entities. Budget for re-modelling, and keep the same URL structure so clients survive the move.

4. Do not put an ORM behind a webhook receiver. If you pick Slim for webhooks, write the payload to a queue (Redis, AMQP) and return 202 in under 50 ms. Synchronous Doctrine writes inside a webhook handler will time out under burst traffic — GitHub retries, and you get duplicates.

5. Serializer depth is a latency cliff. API Platform’s default serialization embeds related resources. On a resource with three collections, one GET /api/orders can trigger dozens of queries. Enable #[ApiResource(forceEager: false)] plus explicit #[Groups] and watch your query count, not your average response time.

6. Pin your PHP minor version. API Platform 5 requires PHP 8.2+, Slim 4.15 supports 8.1–8.4, Laminas API Tools still carries code paths written for PHP 7.4-era module managers. Mixing them in one monorepo is asking for two different opcache strategies.

Why Self-Host Your API Layer at All?

Managed API gateways price per request, and that pricing model punishes exactly the workloads PHP is good at: many small, chatty endpoints. A €12/month VPS runs all three of these frameworks comfortably for tens of thousands of requests per hour, and you keep the database, the logs and the OpenAPI document under your own control.

If you are tuning the runtime underneath, our PHP application server comparison covers Swoole, RoadRunner and FrankenPHP — the difference between 400 and 4,000 requests per second on the same framework. If your deployment depends on private Composer packages, the Composer repository guide shows how to run Satis or Private Packagist alternatives yourself. And if the API you are building fronts a storefront, the self-hosted PHP e-commerce comparison covers Sylius, Bagisto and Spree in the same depth.

FAQ

Is API Platform overkill for a small API? Yes, usually. API Platform earns its complexity when you have 10+ related resources, need filtering and pagination, and want an OpenAPI document that stays in sync automatically. Under five endpoints, Slim will be faster to build and far easier to debug.

Can Slim generate an OpenAPI document? Not by itself. Slim is a router and middleware dispatcher. You either write the OpenAPI YAML by hand, use zircote/swagger-php with attribute annotations, or generate a spec from your PSR-7 handlers. Budget extra time for keeping the spec and code in sync.

Is Laminas API Tools dead? Not dead, but thinly maintained. Version 1.7.0 shipped in January 2026 and the repository has 36 stars. Security fixes arrive, features do not. Use it to maintain existing APIs; do not start new ones on it.

Which one is fastest? Raw throughput is governed by the runtime, not the framework: all three compile to the same opcodes and run behind PHP-FPM. In practice Slim has the lowest per-request overhead (no metadata layer, no ORM bootstrapping), API Platform the highest unless you enable its production cache, and Laminas sits between them. See the application server comparison for numbers that actually move the needle.

Do I need Docker to run any of these? No. All three install with Composer and run under PHP-FPM. Docker only helps API Platform, whose skeleton ships a complete compose stack for local development.

Can I expose REST and GraphQL from one codebase? Only API Platform does this natively — enable the GraphQL module and the same #[ApiResource] definition serves both. With Slim or Laminas you would add a separate GraphQL server (Webonyx GraphQL-PHP) and maintain two schemas.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com