Перейти к содержимому
getnextpdf.com

Почему вашему движку PDF место в PHP, а не в сайдкаре

Spec: ISO/IEC 25010:2023, §3.7Spec: ISO 32000-2, §7

Есть два места, где можно создать PDF: внутри вашего процесса PHP или где-то ещё, что вам приходится эксплуатировать. NextPDF создаёт его внутри. Эта страница — обоснование этого выбора: почему внутрипроцессный движок обычно правильный вариант по умолчанию и во что на самом деле обходится шаблон «где-то ещё», когда он оказывается в продакшене.

Это угол зрения архитектуры, а не фреймворка. Как один и тот же движок достигает Laravel, Symfony, CodeIgniter и самостоятельного кода — отдельная история, рассказанная в один движок, любой фреймворк.

Функция PDF редко начинается как система, которую вы эксплуатируете. Она начинается как строка в контроллере: отрисовать этот счёт, вернуть тот отчёт. Шаблон «сайдкар» превращает эту строку в инфраструктуру. Чтобы нарисовать документ, вы теперь запускаете вторую вещь — внешний бинарник, безголовый браузер, отдельный микросервис, — и всё, что нужно этой второй вещи, тоже становится вашей проблемой: её версия, её память, её контейнер, её сеть, её режимы отказа, её вызов на дежурство в 2 часа ночи.

Эта стоимость невидима на демо и неизбежна в продакшене. У движка документов, который живёт в вашем процессе, ничего из этого нет. Вопрос не «может ли сайдкар создать PDF» — конечно, может. Он в том, «что вы подписались эксплуатировать, чтобы туда добраться, и нужно ли это было».

  • Внутри процесса означает отсутствие второй среды выполнения. NextPDF рисует PDF внутри того же воркера PHP, который обработал запрос. Нет подпроцесса для порождения, нет сервиса для развёртывания и ничего лишнего, что нужно держать живым.
  • Сайдкар добавляет эксплуатационную поверхность, которой у вас не было. Связанный браузер или внешний бинарник приносит свою версию, свой след безопасности и свой контейнер — всё это вы теперь исправляете и мониторите.
  • Границы процессов — это там, где всё идёт не так. Холодные старты, тайм-ауты, хрупкая межпроцессная обвязка и данные, покидающие ваш процесс, — это режимы отказа, которых у внутрипроцессного вызова просто нет.
  • Внутри процесса — тестируемо и детерминированно. Движок — это типизированный PHP, который вы можете покрыть модульными тестами, замокать и о котором можно рассуждать, — а не непрозрачный отрисовщик, который вы можете прозондировать, только запустив его и посмотрев на вывод.
  • У настоящего браузера всё ещё есть настоящие применения. Для попиксельно достоверной отрисовки произвольных современных веб-страниц безголовый браузер — честный инструмент, и NextPDF может намеренно делегировать ему. Это шов, а не вариант по умолчанию.

Держите две архитектуры рядом. Внутрипроцессный путь — это вызов функции. Путь сайдкара — это распределённая система в миниатюре, и каждая стрелка между его прямоугольниками — место, которое отказывает независимо от вашего кода.

  1. In-process: call the enginewriteHtml() or the document API runs inside the current PHP worker — no subprocess, no socket.
  2. In-process: receive PDF bytesThe engine returns native PDF content directly; nothing left the process.
  3. Sidecar: serialize and shipMarkup or a request is marshalled out of your process to a binary, browser, or remote service.
  4. Sidecar: cross the boundaryA process spawn or network hop — with a cold start, a timeout, and an IPC contract that can break.
  5. Sidecar: run a second runtimeAn external renderer with its own version, memory profile, and security surface to operate and patch.
  6. Sidecar: deserialize backMarshal the result back in and translate the renderer’s errors into yours.
The in-process path versus the sidecar path. In-process, the PDF is produced by a typed call inside the same PHP worker and returned directly. The sidecar path adds a serialization step, a process or network boundary, an external runtime with its own version and footprint, and a deserialization step back — each a distinct failure mode the in-process call does not have.

Нет второй среды выполнения для эксплуатации. Шаблон сайдкара — это две системы, надевшие костюм одной функции. Связанный wkhtmltopdf, сервис безголового Chromium, отдельный микросервис отрисовки — каждый из них среда выполнения со своим ритмом выпусков и своими багами. Вы наследуете всё это. Внутрипроцессный движок поставляется как зависимость Composer; он обновляется так же, как и любая другая библиотека в вашем composer.json, без демона, образа или сокета, добавленных в ваше развёртывание.

Дрейф версий и более широкая поверхность безопасности. Связанный браузер — это большая, быстро движущаяся кодовая база с постоянным потоком бюллетеней безопасности. Закрепите его — и он гниёт; отслеживайте его — и он бурлит. Так или иначе, это целая веб-платформа отрисовщика, сидящая в вашей цепочке поставки ради одного документа. Внутрипроцессный движок на PHP — это сфокусированная библиотека кода, который вы можете прочитать; его поверхность безопасности — это PHP, который вы уже запускаете, а не вторая платформа, которую вы теперь тоже запускаете.

Данные остаются внутри границы вашего процесса. Когда вы вызываете внешнюю программу, содержимое документа — которое часто и есть ровно те чувствительные данные, ради переноса которых PDF существует, — пересекает границу. Оно записывается в канал, аргумент, временный файл или сетевой сокет к сервису. Каждое из них — место, где можно утечь, случайно залогировать или оставить после себя. Внутри процесса данные никогда не покидают воркер, который ими владеет. Радиус поражения — один процесс, а не флот.

Хрупкая обвязка, холодные старты и тайм-ауты. Межпроцессные и сетевые вызовы отказывают так, как вызов функции не может: подпроцесс, который не запустился, сокет, который завис, тайм-аут, который вы угадали неправильно, холодный старт при всплеске трафика. Каждому нужна политика повтора, предохранитель и бюджет. Внутрипроцессная отрисовка либо возвращает байты, либо бросает типизированное исключение, которое вы ловите на следующей строке. Нет частичного сетевого состояния, которое нужно согласовывать.

Наблюдаемость и тестирование становятся труднее за границей. Сбой в сайдкаре приходит как код выхода, обрезанная строка лога или 500 от сервиса, которым вы не управляете. Воспроизвести его означает воспроизвести всю ту среду. Внутрипроцессный движок наблюдаем инструментами, которые вы уже используете, — трассировка стека, отладчик, профилировщик, — и он тестируем так же, как и остальной ваш PHP. Эта тестируемость — именованное свойство качества ПО: ISO/IEC 25010 помещает её под поддерживаемость (Spec: ISO/IEC 25010:2023, §3.7), и внутрипроцессная библиотека удовлетворяет ей гораздо более напрямую, чем отрисовщик, который вы можете задействовать, только запустив его.

PDF, на котором эти тесты что-то утверждают, — это определённая структура, а не чёрный ящик. Файл PDF имеет специфицированную раскладку объектов и файла (Spec: ISO 32000-2, §7), и внутрипроцессный движок выдаёт эту структуру из кода, который вы можете прочитать, — поэтому эталонный или структурный тест проверяет байты, произведённые известной функцией, а не вывод внешней программы, который вы можете лишь наблюдать.

Вся суть умещается в несколько строк. Нет клиента, нет базового URL, нет проверки работоспособности и нет политики повтора — потому что нет второй системы.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// The engine runs inside this very process. No subprocess is spawned,
// no socket is opened, and the report data never leaves the worker.
$document = Document::createStandalone();
$document->setTitle('Quarterly Report');
$document->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">Quarterly Report</h1>
<p>Rendered <strong>in-process</strong> by PHP — no browser, no sidecar.</p>
HTML;
$document->writeHtml($html);
// PDF bytes are returned directly. There is no boundary to marshal across,
// so there is no timeout, cold start, or deserialization step to handle.
$bytes = $document->getPdfData();

Сопоставьте форму версии с сайдкаром — не её код, её эксплуатационную форму. Ей нужны установленный и достижимый бинарник или сервис, сериализованный и отправленный запрос, выбранный тайм-аут, путь отказа для случая, когда отрисовщик холодный или лежит, и маршалированный обратно результат. Ничего из этого нет в фрагменте выше, потому что ничего из этого не существует, когда движок — это библиотека.

Частое предположение — что «настоящая» отрисовка PDF обязательно означает браузер, поэтому внутри процесса — это, должно быть, игрушечная версия. Это переворачивает компромисс наоборот. Браузер — правильный инструмент, когда вам нужна точная, попиксельно достоверная отрисовка произвольного современного веб-содержимого. Он — неправильный вариант по умолчанию для работы документального типа, которую большинство команд на самом деле делает, — счета, отчёты, выписки, договоры, — где раскладка известна, данные ваши, а корректность проверяется валидатором, а не на глаз. Для такой работы эксплуатационный вес сайдкара не покупает вам ничего, чего внутрипроцессный движок уже не даёт, и стоит вам всего из разделов выше.

Зеркальное заблуждение — то, которое эта страница тщательно избегает совершать: утверждение, что внутрипроцессный движок отрисовывает «весь веб» как браузер. Это не так, и NextPDF не притворяется, что это так. Его внутрипроцессный конвейер HTML — это согласованное со спецификацией подмножество, сфокусированное на раскладке документов, с задокументированными границами — честный охват изложен в конвейере HTML. Когда вам действительно нужна полная браузерная достоверность, это намеренное, явное делегирование, а не тихий откат.

Внутри процесса — правильный вариант по умолчанию. Это не универсальное утверждение, что подпроцесс никогда не оправдан. Там, где документ действительно требует точной отрисовки произвольного современного CSS, который внутрипроцессный движок не покрывает, делегирование безголовому браузеру — правильный выбор, и NextPDF поддерживает этот путь намеренно, с ограниченным сетевым доступом, как шов, а не как вариант по умолчанию. Эти двое не соперники; это разные инструменты для разных задач.

Эта страница доказывает архитектуру, а не матрицу поддержки CSS. Какой именно HTML и CSS покрывает внутрипроцессный конвейер, определяется кодом движка и его тестами соответствия и документируется вместе с этим конвейером — а не обещается здесь. «Внутри процесса» описывает путь отрисовки по умолчанию; это не утверждение, что каждый возможный путь избегает подпроцесса.

Поверхность возможностей остаётся простой: внутрипроцессный движок — это Core, а путь делегирования браузеру — опциональное расширение, независимое от издания.

Where the PDF is rendered — edition availability
EditionAvailability
CoreCore отрисовывает PDF внутри процесса на PHP — без подпроцесса, бинарника или сайдкара по умолчанию.
ProПуть делегирования безголовому браузеру — опциональное дополнительное расширение, независимое от уровня издания.
EnterpriseПуть делегирования безголовому браузеру — опциональное дополнительное расширение, независимое от уровня издания.
  • Конвейер HTML — честный охват внутрипроцессного движка и то, когда именно делегирование браузеру правильно.
  • Один движок, любой фреймворк — дополняющая ось: как один и тот же внутрипроцессный движок достигает каждого фреймворка PHP без отдельной библиотеки на каждый стек.
  • Эксплуатация NextPDF в продакшене — как выглядит работа внутрипроцессного движка изо дня в день, без лишней среды выполнения для эксплуатации.
  • Память и потоковая передача — как движок держит внутрипроцессную генерацию ограниченной под нагрузкой.
  • Внутрипроцессная генерация — создание PDF внутри того же воркера PHP, который обрабатывает запрос, без подпроцесса, сокета или внешнего сервиса.
  • Сайдкар — отдельная среда выполнения, работающая рядом с вашим приложением, чтобы делать одну работу; здесь — внешний бинарник, безголовый браузер или микросервис, который отрисовывает PDF вне вашего процесса.
  • Холодный старт — задержка и всплеск ресурсов, возникающие, когда подпроцесс или сервис должен быть запущен с нуля, прежде чем он сможет обслужить первый запрос.
  • IPC — межпроцессное взаимодействие: каналы, сокеты, временные файлы или сетевые вызовы, используемые для передачи данных в отдельный процесс и из него, и повторяющийся источник хрупких, трудных для отладки сбоев.
  • Шов делегирования браузеру — опциональный, явный путь, который передаёт отрисовку безголовому браузеру ради точной достоверности, с заблокированным сетевым доступом к подресурсам; намеренный выбор, а не вариант по умолчанию.