Formatters
Formatters are responsible for converting array data into various output formats like JSON, XML, YAML, CSV, and plain text. All formatters implement the FormatterInterface and can be used directly or through the Serialize class.
Overview
The PHP Serializer library provides several built-in formatters:
- JsonFormatter - Converts data to JSON format
- XmlFormatter - Converts data to XML format with customization options
- YamlFormatter - Converts data to YAML format
- CsvFormatter - Converts data to CSV format
- PlainTextFormatter - Converts data to plain text with customization options
Using Formatters
Direct Usage
You can use formatters directly by instantiating them and calling the process() method:
use ByJG\Serializer\Formatter\JsonFormatter;
use ByJG\Serializer\Formatter\XmlFormatter;
$data = [
'name' => 'John Doe',
'email' => '[email protected]',
'age' => 30
];
// Direct formatter usage
echo (new JsonFormatter())->process($data);
echo (new XmlFormatter())->process($data);
Through Serialize Class
Alternatively, use the Serialize class for a more convenient API:
use ByJG\Serializer\Serialize;
$result = Serialize::from($data)->toJson();
$result = Serialize::from($data)->toXml();
$result = Serialize::from($data)->toYaml();
$result = Serialize::from($data)->toCsv();
$result = Serialize::from($data)->toPlainText();
Built-in Formatters
JsonFormatter
The simplest formatter that converts data to JSON format using PHP's native json_encode().
use ByJG\Serializer\Formatter\JsonFormatter;
$formatter = new JsonFormatter();
echo $formatter->process($data);
// Output:
// {"name":"John Doe","email":"[email protected]","age":30}
Features:
- No configuration options
- Uses PHP's
json_encode()with default settings - Handles both arrays and objects
XmlFormatter
Converts data to XML format with extensive customization options.
Basic Usage
use ByJG\Serializer\Formatter\XmlFormatter;
$data = [
'name' => 'John Doe',
'email' => '[email protected]'
];
$formatter = new XmlFormatter();
echo $formatter->process($data);
// Output:
// <?xml version="1.0"?>
// <root>
// <name>John Doe</name>
// <email>[email protected]</email>
// </root>
Configuration Methods
1. withRootElement(string $rootElement): XmlFormatter
Customizes the XML root element name (default: "root").
$xml = (new XmlFormatter())
->withRootElement("user")
->process($data);
// Output:
// <?xml version="1.0"?>
// <user>
// <name>John Doe</name>
// <email>[email protected]</email>
// </user>
2. withListElement(string $listElement): XmlFormatter
Customizes the element name for array items (default: "item").
$users = [
['name' => 'John', 'age' => 30],
['name' => 'Jane', 'age' => 25]
];
$xml = (new XmlFormatter())
->withRootElement("users")
->withListElement("user")
->process($users);
// Output:
// <?xml version="1.0"?>
// <users>
// <user>
// <name>John</name>
// <age>30</age>
// </user>
// <user>
// <name>Jane</name>
// <age>25</age>
// </user>
// </users>
3. withListElementSuffix(): XmlFormatter
Adds numeric suffixes to list element names for better identification.
$xml = (new XmlFormatter())
->withRootElement("users")
->withListElement("user")
->withListElementSuffix() // Enables numeric suffixes
->process($users);
// Output:
// <?xml version="1.0"?>
// <users>
// <user0>
// <name>John</name>
// <age>30</age>
// </user0>
// <user1>
// <name>Jane</name>
// <age>25</age>
// </user1>
// </users>
Complete Example
$products = [
['id' => 1, 'name' => 'Laptop', 'price' => 999],
['id' => 2, 'name' => 'Mouse', 'price' => 25]
];
$xml = (new XmlFormatter())
->withRootElement("catalog")
->withListElement("product")
->withListElementSuffix()
->process($products);
YamlFormatter
Converts data to YAML format using the Symfony YAML component.
use ByJG\Serializer\Formatter\YamlFormatter;
$data = [
'name' => 'John Doe',
'email' => '[email protected]',
'roles' => ['admin', 'user']
];
$formatter = new YamlFormatter();
echo $formatter->process($data);
// Output:
// name: John Doe
// email: [email protected]
// roles:
// - admin
// - user
Features:
- No configuration options
- Uses Symfony YAML component
- Handles nested arrays and objects elegantly
CsvFormatter
Converts data to CSV (Comma-Separated Values) format.
Basic Usage
use ByJG\Serializer\Formatter\CsvFormatter;
$users = [
['name' => 'John Doe', 'email' => '[email protected]', 'age' => 30],
['name' => 'Jane Smith', 'email' => '[email protected]', 'age' => 25]
];
$formatter = new CsvFormatter();
echo $formatter->process($users);
// Output:
// name,email,age
// "John Doe",[email protected],30
// "Jane Smith",[email protected],25
Behavior
- Headers: Automatically generates headers from the keys of the first array element
- Single Arrays: If you pass a single associative array, it's automatically wrapped in an array
- Empty Arrays: Returns an empty string
- Escape Character: Uses backslash (
\\) as the escape character - Multidimensional Support: Handles arrays of arrays; nested objects are not supported
Example with Single Object
$user = ['name' => 'John', 'email' => '[email protected]'];
echo (new CsvFormatter())->process($user);
// Output:
// name,email
// John,[email protected]
PlainTextFormatter
Converts data to plain text format with extensive customization options.
Basic Usage
use ByJG\Serializer\Formatter\PlainTextFormatter;
$data = [
'name' => 'John Doe',
'email' => '[email protected]',
'age' => 30
];
$formatter = new PlainTextFormatter();
echo $formatter->process($data);
// Output:
// John Doe
// [email protected]
// 30
Configuration Methods
1. withBreakLine(string $breakLine): PlainTextFormatter
Customizes the line break character/string (default: "\n").
$text = (new PlainTextFormatter())
->withBreakLine(" | ")
->process($data);
// Output: John Doe | [email protected] | 30 |
2. withStartOfLine(string $startOfLine): PlainTextFormatter
Adds a prefix to the start of each line (default: "").
$text = (new PlainTextFormatter())
->withStartOfLine("- ")
->process($data);
// Output:
// - John Doe
// - [email protected]
// - 30
3. withIgnorePropertyName(bool $ignorePropertyName): PlainTextFormatter
Controls whether property names are included in the output (default: true).
$text = (new PlainTextFormatter())
->withIgnorePropertyName(false) // Include property names
->process($data);
// Output:
// name=John Doe
// [email protected]
// age=30
HTML List Example
Create an HTML list using PlainTextFormatter:
$data = ['Apple', 'Banana', 'Orange'];
$html = (new PlainTextFormatter())
->withStartOfLine("<li>")
->withBreakLine("</li>\n")
->process($data);
echo "<ul>\n" . $html . "</ul>";
// Output:
// <ul>
// <li>Apple</li>
// <li>Banana</li>
// <li>Orange</li>
// </ul>
Complete Example
$products = [
'Laptop' => 999,
'Mouse' => 25,
'Keyboard' => 75
];
$text = (new PlainTextFormatter())
->withIgnorePropertyName(false)
->withStartOfLine("* ")
->withBreakLine("\n")
->process($products);
// Output:
// * Laptop=999
// * Mouse=25
// * Keyboard=75
FormatterInterface
All formatters implement the FormatterInterface, which defines a single method:
namespace ByJG\Serializer\Formatter;
interface FormatterInterface
{
/**
* Process the serializable data and return formatted output
*
* @param array|object $serializable The data to format
* @return string|bool The formatted output
*/
public function process(array|object $serializable): string|bool;
}
Creating Custom Formatters
You can create custom formatters by implementing the FormatterInterface:
Example: HTML Table Formatter
namespace MyApp\Formatters;
use ByJG\Serializer\Formatter\FormatterInterface;
use ByJG\Serializer\Serialize;
class HtmlTableFormatter implements FormatterInterface
{
private bool $includeHeaders = true;
private string $tableClass = '';
public function withTableClass(string $class): self
{
$this->tableClass = $class;
return $this;
}
public function withoutHeaders(): self
{
$this->includeHeaders = false;
return $this;
}
public function process(array|object $serializable): string|bool
{
// Convert object to array if needed
if (is_object($serializable)) {
$serializable = Serialize::from($serializable)->toArray();
}
// Ensure we have an array of arrays
if (empty($serializable)) {
return '<table></table>';
}
$isMulti = is_array(reset($serializable));
if (!$isMulti) {
$serializable = [$serializable];
}
// Start table
$class = $this->tableClass ? " class=\"{$this->tableClass}\"" : '';
$html = "<table{$class}>\n";
// Add headers
if ($this->includeHeaders) {
$headers = array_keys(reset($serializable));
$html .= " <thead>\n <tr>\n";
foreach ($headers as $header) {
$html .= " <th>" . htmlspecialchars($header) . "</th>\n";
}
$html .= " </tr>\n </thead>\n";
}
// Add rows
$html .= " <tbody>\n";
foreach ($serializable as $row) {
$html .= " <tr>\n";
foreach ($row as $value) {
$html .= " <td>" . htmlspecialchars($value) . "</td>\n";
}
$html .= " </tr>\n";
}
$html .= " </tbody>\n</table>";
return $html;
}
}
Using the Custom Formatter
use MyApp\Formatters\HtmlTableFormatter;
$users = [
['name' => 'John Doe', 'email' => '[email protected]'],
['name' => 'Jane Smith', 'email' => '[email protected]']
];
$html = (new HtmlTableFormatter())
->withTableClass('table table-striped')
->process($users);
echo $html;
Example: Markdown Formatter
namespace MyApp\Formatters;
use ByJG\Serializer\Formatter\FormatterInterface;
use ByJG\Serializer\Serialize;
class MarkdownFormatter implements FormatterInterface
{
public function process(array|object $serializable): string|bool
{
if (is_object($serializable)) {
$serializable = Serialize::from($serializable)->toArray();
}
if (empty($serializable)) {
return '';
}
// Check if it's a list of objects
$isMulti = is_array(reset($serializable));
if (!$isMulti) {
// Single object - format as key-value pairs
$markdown = '';
foreach ($serializable as $key => $value) {
$markdown .= "**{$key}**: {$value}\n\n";
}
return $markdown;
}
// Multiple objects - format as table
$headers = array_keys(reset($serializable));
// Create header row
$markdown = '| ' . implode(' | ', $headers) . " |\n";
// Create separator
$markdown .= '| ' . implode(' | ', array_fill(0, count($headers), '---')) . " |\n";
// Create data rows
foreach ($serializable as $row) {
$markdown .= '| ' . implode(' | ', array_values($row)) . " |\n";
}
return $markdown;
}
}
Using the Markdown Formatter
use MyApp\Formatters\MarkdownFormatter;
$users = [
['name' => 'John Doe', 'role' => 'Admin'],
['name' => 'Jane Smith', 'role' => 'User']
];
echo (new MarkdownFormatter())->process($users);
// Output:
// | name | role |
// | --- | --- |
// | John Doe | Admin |
// | Jane Smith | User |
Best Practices
1. Choose the Right Formatter
- JsonFormatter: API responses, data storage, JavaScript integration
- XmlFormatter: Legacy systems, SOAP services, RSS feeds
- YamlFormatter: Configuration files, human-readable data
- CsvFormatter: Data exports, spreadsheet compatibility
- PlainTextFormatter: Log files, simple displays, custom text formats
2. Use Configuration Methods
Take advantage of formatter configuration methods to customize output:
// Good - customized for your use case
$xml = (new XmlFormatter())
->withRootElement("products")
->withListElement("product")
->process($data);
// Less ideal - generic root element
$xml = (new XmlFormatter())->process($data);
3. Method Chaining
All configuration methods support fluent interfaces:
$text = (new PlainTextFormatter())
->withBreakLine("\n")
->withStartOfLine("* ")
->withIgnorePropertyName(false)
->process($data);
4. Combine with Serialize Modifiers
Use Serialize modifiers before formatting:
$json = Serialize::from($user)
->withIgnoreProperties(['password', 'secret'])
->withDoNotParseNullValues()
->toJson();
5. Custom Formatters
When built-in formatters don't meet your needs:
- Implement
FormatterInterface - Support method chaining with configuration
- Handle both arrays and objects
- Consider edge cases (empty data, nested structures)
Performance Considerations
Caching
Formatters don't cache results. If you're formatting the same data multiple times, cache the output:
// Bad - formats twice
$json1 = (new JsonFormatter())->process($data);
$json2 = (new JsonFormatter())->process($data);
// Good - format once, reuse
$json = (new JsonFormatter())->process($data);
$result1 = $json;
$result2 = $json;
Large Datasets
For large datasets, consider:
- CSV: Most efficient for tabular data
- JSON: Good balance of speed and features
- XML: Can be verbose and slower for large datasets
Memory Usage
Formatters process data in memory. For very large datasets:
- Use streaming APIs if available
- Process data in chunks
- Consider database exports instead of in-memory formatting
Related Components
- Serialize - Main serialization class that uses formatters
- ObjectCopy - Copy data between objects before formatting
- BaseModel - Model base class with
toArray()for formatting