Skip to content

Instantly share code, notes, and snippets.

@T99
Last active December 12, 2022 17:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save T99/2290bdb9887cd1f140266f159ab82692 to your computer and use it in GitHub Desktop.
Save T99/2290bdb9887cd1f140266f159ab82692 to your computer and use it in GitHub Desktop.
Generate an ASCII/text-based table string in PHP from a given input set of data.
<?php
/**
* Returns true if the input array appears to be an associative array, otherwise
* returning false.
*
* @param array $input The array being tested.
* @return bool true if the input array appears to be an associative array,
* otherwise returning false.
*/
function isArrayAssociative(array $input): bool {
return (
$input !== [] &&
array_keys($input) !== range(0, count($input) - 1)
);
}
/**
* Returns an array of strings, representing the values of the input array after
* each being converted to a string.
*
* @param array $input The input array to map to a string array.
* @param string $value_when_null The string value to use for null values.
* @return string[]
*/
function toStringArray(array $input, string $value_when_null = ""): array {
return array_map(
callback: fn($value): string => match (gettype($value)) {
"boolean" => $value ? "true" : "false",
"integer", "double" => strval($value),
"string" => $value,
"array" => arrayToString($value, $value_when_null),
"NULL" => $value_when_null,
default => "<" . gettype($value) . ">",
},
array: $input,
);
}
/**
* Returns a string that represents the contents of the provided array with a
* comma separated list of values.
*
* @param array $input The input array for which to generate a string.
* @param string $value_when_null The string value to use for null values.
* @return string A string that represents the contents of the provided array
* with a comma separated list of values.
*/
function arrayToString(array $input, string $value_when_null = "null"): string {
$array_contents_string = join(
separator: ", ",
array: toStringArray($input, $value_when_null),
);
return "[$array_contents_string]";
}
/**
* Returns a string containing an ASCII table.
*
* @param array $data An array of data to populate the resulting table with.
* @param array | null $headers An optional array of 'headers' to use when
* building the resulting table. If this array is a simple string array, it will
* be used to narrow and potentially re-order the result set according to the
* order and presence of a given column within this array. If this array is
* associative, the keys of the array will function similarly to what was just
* described, while the values of each key will be used as a replacement for
* the header for the column being described.
* @return string A string containing an ASCII table.
*/
function toASCIITable(array $data, array $headers = null): string {
$result = "";
if (count($data) <= 0) return $result;
else if (isArrayAssociative($data)) {
$data_keys = array_keys($data);
$data_values = toStringArray(array_values($data));
$max_key_length = max(array_map(
callback: fn($key): int => strlen($key),
array: $data_keys,
));
$max_value_length = max(array_map(
callback: fn($value): int => strlen($value),
array: $data_values,
));
$horizontal_separator = join("", [
"+-",
str_repeat("-", $max_key_length),
"-+-",
str_repeat("-", $max_value_length),
"-+",
]);
$result .= "$horizontal_separator\n";
$result .= join("\n", array_map(
fn($key, $value): string => join("", [
"| ",
str_pad($key, $max_key_length),
" | ",
str_pad($value, $max_value_length),
" |\n",
$horizontal_separator,
]),
$data_keys, $data_values,
));
$result .= "\n";
return $result;
}
$data = array_map(
callback: fn($row) => is_object($row) ? get_object_vars($row) : $row,
array: $data,
);
if (!is_null($headers) && isArrayAssociative($headers)) {
$header_columns = array_keys($headers);
$header_titles = array_values($headers);
} else {
$header_columns = $headers ?? array_keys($data[0]);
$header_titles = $header_columns;
}
$data = array_map(
callback: fn($row): array => toStringArray(array_filter(
array: $row,
callback: fn($key): bool => in_array($key, $header_columns),
mode: ARRAY_FILTER_USE_KEY,
)),
array: $data,
);
$column_widths = array_map(
callback: fn($text): int => strlen($text),
array: $header_titles,
);
foreach ($data as $row) {
for ($i = 0; $i < count($column_widths); $i++) {
$row[$header_columns[$i]] ??= "";
$column_widths[$i] = max(
$column_widths[$i],
strlen($row[$header_columns[$i]]),
);
}
}
$horizontal_separator = join("", [
"+",
join("+", array_map(
callback: fn($width): string => str_repeat("-", $width + 2),
array: $column_widths,
)),
"+"
]);
$result .= "$horizontal_separator\n";
$result .= join("", [
"| ",
join(" | ", array_map(
fn($header_title, $width): string => str_pad($header_title, $width),
$header_titles, $column_widths,
)),
" |\n",
$horizontal_separator,
"\n",
]);
foreach ($data as $row) {
$result .= join("", [
"| ",
join(" | ", array_map(
fn($column, $width): string => str_pad($row[$column] ?? "", $width),
$header_columns, $column_widths,
)),
" |\n",
$horizontal_separator,
"\n",
]);
}
return $result;
}
@T99
Copy link
Author

T99 commented Dec 12, 2022

Example 1: Basic associative array

<?php

echo toASCIITable([
    "here" => "is some",
    "example" => 1024,
    "data" => true,
    "for you" => false,
]);

Results in:

+---------+---------+
| here    | is some |
+---------+---------+
| example | 1024    |
+---------+---------+
| data    | true    |
+---------+---------+
| for you | false   |
+---------+---------+

Example 2: Basic multidimensional array

<?php

echo toASCIITable([
    [
        "one" => "1",
        "two" => "2",
        "three" => "3",
    ],
    [
        "one" => 11,
        "two" => 22,
        "three" => 33,
    ],
    [
        "one" => "1",
        "two" => "12",
        "three" => "123",
    ],
]);

Results in:

+-----+-----+-------+
| one | two | three |
+-----+-----+-------+
| 1   | 2   | 3     |
+-----+-----+-------+
| 11  | 22  | 33    |
+-----+-----+-------+
| 1   | 12  | 123   |
+-----+-----+-------+

Example 3: Multidimensional array with provided headers

<?php

echo toASCIITable([
    [
        "one" => "1",
        "two" => "2",
        "three" => "3",
    ],
    [
        "one" => 11,
        "two" => 22,
        "three" => 33,
    ],
    [
        "one" => "1",
        "two" => "12",
        "three" => "123",
    ],
], [
    "one",
    "three",
]);

Results in:

+-----+-------+
| one | three |
+-----+-------+
| 1   | 3     |
+-----+-------+
| 11  | 33    |
+-----+-------+
| 1   | 123   |
+-----+-------+

Example 4: Multidimensional array with provided headers and titles

<?php

echo toASCIITable([
    [
        "one" => "1",
        "two" => "2",
        "three" => "3",
    ],
    [
        "one" => 11,
        "two" => 22,
        "three" => 33,
    ],
    [
        "one" => "1",
        "two" => "12",
        "three" => "123",
    ],
], [
    "one" => "ONE!",
    "three" => "3",
]);

Results in:

+------+-------+
| ONE! | 3     |
+------+-------+
| 1    | 3     |
+------+-------+
| 11   | 33    |
+------+-------+
| 1    | 123   |
+------+-------+

Example 5: Basic object array

<?php

echo toASCIITable([
    (object) [
        "id" => 1,
        "user" => "johnsmith",
        "name" => "John Smith",
        "age" => 35,
        "email" => "johns@example.com",
    ],
    (object) [
        "id" => 5,
        "user" => "honks",
        "name" => "Honks McGee",
        "email" => "honks@clowns.net",
    ],
    (object) [
        "id" => 4,
        "user" => "foodbar",
        "phone" => "+12345678901",
        "email" => "foo@dbar.com",
    ],
]);

Results in:

+----+-----------+-------------+-----+-------------------+
| id | user      | name        | age | email             |
+----+-----------+-------------+-----+-------------------+
| 1  | johnsmith | John Smith  | 35  | johns@example.com |
+----+-----------+-------------+-----+-------------------+
| 5  | honks     | Honks McGee |     | honks@clowns.net  |
+----+-----------+-------------+-----+-------------------+
| 4  | foodbar   |             |     | foo@dbar.com      |
+----+-----------+-------------+-----+-------------------+

Example 6: Object array with provided headers

<?php

echo toASCIITable([
    (object) [
        "id" => 1,
        "user" => "johnsmith",
        "name" => "John Smith",
        "age" => 35,
        "email" => "johns@example.com",
    ],
    (object) [
        "id" => 5,
        "user" => "honks",
        "name" => "Honks McGee",
        "email" => "honks@clowns.net",
    ],
    (object) [
        "id" => 4,
        "user" => "foodbar",
        "phone" => "+12345678901",
        "email" => "foo@dbar.com",
    ],
], [
    "id",
    "name",
    "age",
]);

Results in:

+----+-------------+-----+
| id | name        | age |
+----+-------------+-----+
| 1  | John Smith  | 35  |
+----+-------------+-----+
| 5  | Honks McGee |     |
+----+-------------+-----+
| 4  |             |     |
+----+-------------+-----+

Example 7: Object array with provided headers and titles

<?php

echo toASCIITable([
    (object) [
        "id" => 1,
        "user" => "johnsmith",
        "name" => "John Smith",
        "age" => 35,
        "email" => "johns@example.com",
    ],
    (object) [
        "id" => 5,
        "user" => "honks",
        "name" => "Honks McGee",
        "email" => "honks@clowns.net",
    ],
    (object) [
        "id" => 4,
        "user" => "foodbar",
        "phone" => "+12345678901",
        "email" => "foo@dbar.com",
    ],
], [
    "id" => "User ID",
    "user" => "Username",
    "name" => "Name",
    "phone" => "Phone Number",
]);

Results in:

+---------+-----------+-------------+--------------+
| User ID | Username  | Name        | Phone Number |
+---------+-----------+-------------+--------------+
| 1       | johnsmith | John Smith  |              |
+---------+-----------+-------------+--------------+
| 5       | honks     | Honks McGee |              |
+---------+-----------+-------------+--------------+
| 4       | foodbar   |             | +12345678901 |
+---------+-----------+-------------+--------------+

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment