Использование compat-legacy в продакшене
Адаптер можно безопасно использовать в обработчиках Hypertext Transfer Protocol (HTTP), обработчиках очередей и длительно работающих процессах. Он безопаснее устаревшего TCPDF 6.2.13, потому что устраняет два наиболее вероятных риска в продакшене: прямую запись в буфер вывода и die() при ошибке. На этой странице описано, как правильно использовать его в эксплуатации.
Перед выходом в продакшен выполните аудит строгого режима, описанный в /integrations/tcpdf-compat/migration/, и разверните систему с выключенным строгим режимом.
Обработка вывода в обработчиках очередей и обработчиках запросов
Заголовок раздела «Обработка вывода в обработчиках очередей и обработчиках запросов»Устаревший Output() в TCPDF напрямую пишет в активный буфер вывода. Это может повредить ответы в HTTP-фреймворках и нарушить работу обработчиков очередей. Поэтому адаптер направляет вывод через безопасный мост назначения.
Выберите назначение, подходящее для вызывающего кода:
| Контекст | Назначение | Почему |
|---|---|---|
| Обработчик очереди, который пишет в хранилище | Output($path, 'F') | Записывает файл и возвращает пустую строку. С буфером не взаимодействует. |
| Сгенерировать, затем attach/upload | Output($name, 'S') | Возвращает байты Portable Document Format (PDF); вы сами решаете, куда их отправить. |
| Вложение в электронное письмо | Output($name, 'E') | Возвращает тело Multipurpose Internet Mail Extensions (MIME) в кодировке base64 с Content-Type: application/pdf. |
| HTTP-ответ, которым вы управляете | Output($name, 'S') | Вы получаете байты, затем задаёте собственные заголовки и тело. |
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;use NextPDF\Compat\Tcpdf\TCPDF;
/** * Render an invoice in a queue worker. Returns the storage path. * * @throws \RuntimeException on a render failure (Error() throws, not die()). */function renderInvoiceJob(array $invoice, string $storageDir): string{ $pdf = new TCPDF('P', 'mm', 'A4'); $pdf->SetFont('helvetica', '', 12); $pdf->AddPage(); $pdf->Cell(0, 10, 'Invoice ' . $invoice['number'], 0, 1);
$path = $storageDir . '/invoice-' . $invoice['number'] . '.pdf';
try { $pdf->Output($path, 'F'); // writes file, no buffer pollution } catch (TcpdfNotImplementedException $e) { // Only reachable if strict mode is on — it must NOT be in production. throw new \RuntimeException('Adapter strict-mode gap in production: ' . $e->getMessage(), 0, $e); } catch (\RuntimeException $e) { // Error() throws RuntimeException instead of die(). throw new \RuntimeException('PDF render failed: ' . $e->getMessage(), 0, $e); }
return $path;}В обработчике HTTP предпочитайте 'S' и задавайте заголовки самостоятельно:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();$pdf->AddPage();$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Report');
$bytes = $pdf->Output('report.pdf', 'S');
header('Content-Type: application/pdf');header('Content-Length: ' . strlen($bytes));header('Content-Disposition: inline; filename="report.pdf"');echo $bytes;Обработка сбоев
Заголовок раздела «Обработка сбоев»Error() выбрасывает RuntimeException и никогда не вызывает die(). Это ключевое изменение для эксплуатации по сравнению с устаревшим TCPDF.
- Оборачивайте каждую точку входа в отрисовку в
try/catch. - Преобразуйте исключение в ошибку по контракту вашего приложения, например HTTP 5xx, сбой задания, повтор или dead-letter.
- Не рассчитывайте, что процесс завершится при сбое отрисовки; этого не произойдёт.
Если TcpdfNotImplementedException появляется в периодическом задании continuous integration (CI) со строгим режимом (рекомендуется), это полезная находка. Значит, какой-то путь кода полагается на неподдерживаемый параметр TCPDF. Рассматривайте это как задачу по миграции, а не как нестабильный тест.
Жизненный цикл и управление ресурсами
Заголовок раздела «Жизненный цикл и управление ресурсами»- Документ формирует байты PDF лениво, при первом вызове вывода.
Close()вызывать необязательно; вызов кэширует байты.Open()— безопасная пустая операция. endPage()ничего не делает, поскольку NextPDF управляет жизненным циклом страниц. Удалите его из горячих циклов; он не приносит пользы.- Позвольте сборщику мусора PHP убирать адаптер между заданиями.
_destroy()сбрасывает кэшированные данные адаптера, но явно вызывать его в обычных циклах обработчика не требуется. - Создавайте новый адаптер для каждого документа. Не используйте один экземпляр адаптера повторно для не связанных между собой документов в длительно работающем обработчике; состояние документа привязано к экземпляру.
Рекомендации по производительности
Заголовок раздела «Рекомендации по производительности»- Адаптер — это тонкий слой делегирования; основные затраты приходятся на движок, а не на адаптер.
- Определяйте устаревшие константы один раз при загрузке.
LegacyDefaults::register()иLegacyBootstrap::enableAliases()идемпотентны и защищены, поэтому повторные вызовы обходятся дёшево. Определять константы при каждом запросе — пустая трата ресурсов. - В небраузерных контекстах предпочитайте
Output(..., 'S')или'F'вместо'I'/'D'. Пути inline/download формируют вывод в обход фреймворка; в обработчике это обычно нежелательно. - При массовой генерации профилируйте движок, а не адаптер. Собственные накладные расходы адаптера в расчёте на страницу малы по сравнению с отрисовкой.
Параллелизм
Заголовок раздела «Параллелизм»- Каждый экземпляр адаптера независим и хранит собственное состояние документа. Параллелизм на уровне процесса или обработчика безопасен, если каждая единица работы использует собственный экземпляр адаптера.
- Механизмы идемпотентности в
LegacyBootstrapиLegacyDefaultsиспользуют статическое состояние, локальное для процесса; они безопасны в типичных моделях PHP per-request/per-worker. Они не предназначены для совместного использования изменяемого состояния между потоками.
Контрольный список перед выходом в продакшен
Заголовок раздела «Контрольный список перед выходом в продакшен»- Аудит строгого режима завершён; продакшен работает с выключенным строгим режимом.
- Все точки входа в отрисовку обёрнуты в
try/catchдляRuntimeException(без расчёта наdie()). - Обработчики используют
Output(..., 'F')или'S'и никогда не используют inline-путь. - Устаревшие константы определены один раз при загрузке, до первого создания объекта.
- Настроено периодическое задание CI со строгим режимом для отлова регрессий.
- Побайтовые проверки в тестах пересчитаны заново (см. /integrations/tcpdf-compat/migration/).
См. также
Заголовок раздела «См. также»- /integrations/tcpdf-compat/security-and-operations/ — шифрование, подход к подписанию и усиление защиты
- /integrations/tcpdf-compat/troubleshooting/ — типичные сбои в продакшене и их устранение
- /integrations/tcpdf-compat/configuration/ — строгий режим и порядок работы с константами
- /integrations/tcpdf-compat/migration/ — аудит перед выходом в продакшен