$headers @param list> $rows */ public function render(string $title, array $headers, array $rows): string { $head = implode('', array_map(fn(mixed $value): string => '' . $this->escape($value) . '', $headers)); $body = ''; foreach ($rows as $row) { $body .= '' . implode('', array_map(fn(mixed $value): string => '' . $this->escape($value) . '', $row)) . ''; } return '' . $this->escape($title) . '

' . $this->escape($title) . '

' . $head . '' . $body . '
'; } /** @param list> $rows */ public function renderRecords(string $title, array $rows): string { $headers = $rows === [] ? [] : array_keys($rows[0]); return $this->render($title, $headers, array_map(fn(array $row): array => array_values($row), $rows)); } private function escape(mixed $value): string { return htmlspecialchars((string)($value ?? ''), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } }