PHPackages                             neckberg/hashdown - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. neckberg/hashdown

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

neckberg/hashdown
=================

A PHP package for translating Markdown to and from PHP associative arrays.

v1.1.0(1y ago)420[1 issues](https://github.com/neckberg/hashdown/issues)MITPHPPHP ^7.4 || ^8.0

Since Mar 29Pushed 1y ago3 watchersCompare

[ Source](https://github.com/neckberg/hashdown)[ Packagist](https://packagist.org/packages/neckberg/hashdown)[ RSS](/packages/neckberg-hashdown/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (6)Dependencies (1)Versions (7)Used By (0)

Hashdown
========

[](#hashdown)

Hashdown reads and parses a strictly formatted .md file into a PHP numeric or associative array - or writes a PHP array or object to a structured .md file.

Why?
----

[](#why)

Markdown's advantages as a documentation syntax are well recognized - but Markdown also offers advantages for serializing and editing arbitrary data. For example, unlike YAML and JSON, Markdown's hierarchical header structure doesn't rely on indentation or brackets - making it an often preferable solution when editing data with multi-line values. And Markdown's code block syntax allows for easy escaping of more complex content.

How it works
------------

[](#how-it-works)

In Hashdown format, each header in a Markdown document represents a key in an associative array, where the content following and corresponding to the header represents the value of the key. For example, the following .md content would yield the PHP associative array beneath:

```
# Name of Food
Twinkie

# Serving size
2 cakes

# Calories per serving
280
```

```
[
  'Name of Food' => 'Twinkie',
  'Serving size' => 2 cakes,
  'Calories per serving' => 280,
]
```

H1s (`#`) become top level keys, while H2s (`##`) become secondary level keys, and so on:

```
# Serving size
## Amount
2

## Unit
Cakes
```

The above becomes:

```
[
  'Serving size' => [
    'Amount' => '2',
    'Unit' => 'Cakes',
  ]
]
```

Skipping a header level (e.g. jumping from `#` to `###`) is not allowed, as this would create an invalid array.

### Lists and Sequential arrays

[](#lists-and-sequential-arrays)

Markdown headers can also be used to produce sequential (rather than associative) arrays. A header with no inline text (e.g. a lone hash `#`) will simply increment the key. The two documents below are equivalent, and correspond with the PHP array beneath:

```
# Ingredients
##
sugar
##
water
##
enriched flour
```

```
# Ingredients
## 0
sugar
## 1
water
## 2
enriched flour
```

```
[
  'Ingredients' => [
    'sugar',
    'water',
    'enriched flour',
  ]
]
```

For list items with scalar values (like those shown above), a shorthand "dash" (`-`), syntax can be used instead of hashes (`#`). The following .md document is equivalent to the two above:

```
# Ingredients
- sugar
- water
- enriched flour
```

"Dash" style list values can span multiple lines. The following list is valid and equivalent to the PHP array shown beneath:

```
- first line,
second line

-
another list item
with multiple lines
```

```
[
  'first line,\nsecond line',
  'another list item\nwith multiple lines'
]
```

But non-scalar values must fall under a "hash" style header. The first example below is valid, but the second is not, as the desired data structure can become ambiguous:

```
#
## Name
Twinkie
## Ingredients
- sugar
- water

#
## Name
Diet Coke
```

```
-
## Name
Twinkie
## Ingredients
- sugar
- water

-
## Name
Diet Coke
```

### Literals and Code blocks

[](#literals-and-code-blocks)

#### Escaping embedded Markdown syntax

[](#escaping-embedded-markdown-syntax)

If you need to represent Markdown as scalar content within your .md document, you can escape it using Markdown's code block syntax.

A "literal" or "code block" section is designated by three or more tick marks (`````). The `data` key below has a child node called `title`, while the `content` node is just a string of Markdown text:

```
# data
## title
A Tale of Two Cities
# content
```
# Chapter 1
It was the best of times...
```
```

#### Expressing whitespace

[](#expressing-whitespace)

Normally, Hashdown ignores blank lines and leading or trailing spaces. For example, the following two documents are equivalent, as the spaces and blank lines in the second document will be removed / ignored by the Hashdown parser:

```
# key
some text
some more text
```

```
# key
  some text

some more text
```

However, if placed within a "literal" block, the leading spaces and blank lines will be preserved:

```
# key
```
  some text

some more text
```
```

#### Escaping / nesting literals

[](#escaping--nesting-literals)

Literals can be nested within literals. The outer-most layer must have the most tick marks. If a literal is initiated with 5 tick marks, anything goes until the next line with 5 tick marks:

```
`````
# This is a literal initiated with 5 tick marks

````
# this is a nested literal, designated by 4 tick marks

```
# this is a doubly nested literal, designated by 3 tick marks

```
````
`````
# This is outside the literal, since the line above has 5 tick marks
```

Code examples
-------------

[](#code-examples)

### Reading from an .md file

[](#reading-from-an-md-file)

Use Hashdown's static `x_read_file` method to read from / deserialize an .md file:

```
use Neckberg\Hashdown\Hashdown;

$x_groceries = Hashdown::x_read_file( '.../Groceries.md' );
```

Given the following `Groceries.md` document, the above code would set `$x_groceries` to the PHP array shown beneath:

```
# Groceries
##
### Name
Twinkie
### Ingredients
- sugar
- water
- enriched flour

##
### Name
Diet Coke
### Ingredients
- carbonated water
- caramel color
- aspartame
```

```
[
  'Groceries' => [
    'Name' => 'Twinkie',
    'Ingredients' => [
      'sugar',
      'water',
      'enriched flour',
    ],
    'Name' => 'Diet Coke',
    'Ingredients' => [
      'carbonated water',
      'caramel color',
      'aspartame',
    ],
  ],
];
```

### Writing to an .md file

[](#writing-to-an-md-file)

Use Hashdown's static `write_to_file` method to write to an .md file.

The php code below will produce a `Groceries.md` file with the content shown beneath:

```
use Neckberg\Hashdown\Hashdown;

$x_groceries = [
  'Groceries' => [
    'Name' => 'Twinkie',
    'Ingredients' => [
      'sugar',
      'water',
      'enriched flour',
    ],
    'Name' => 'Diet Coke',
    'Ingredients' => [
      'carbonated water',
      'caramel color',
      'aspartame',
    ],
  ],
];
Hashdown::write_to_file($x_groceries, '.../Groceries.md');
```

```
# Groceries
## 0
### Name
Twinkie

### Ingredients
- sugar
- water
- enriched flour

## 1
### Name
Diet Coke

### Ingredients
- carbonated water
- caramel color
- aspartame
```

#### Formatting options

[](#formatting-options)

By default, `write_to_file` will use the shorthand "dash" lists and explicitly numbered sequential array items (as shown above). But this behavior can be changed via the 3rd and 4th parameters:

- `b_no_shorthand_lists`, bool: If true, don't use shorthand "dash" syntax for any lists. Only use "hash" syntax.
- `b_omit_numeric_array_keys`, bool: If true, omit explicit key values for sequential numeric arrays.

Assuming the same `$x_groceries` variable defined above, the following calls will produce the output beneath:

##### Allow shorthand "dash" lists, but omit sequential keys where possible

[](#allow-shorthand-dash-lists-but-omit-sequential-keys-where-possible)

```
Hashdown::write_to_file($x_groceries, '.../Groceries.md', false, true);
```

```
# Groceries
##
### Name
Twinkie

### Ingredients
- sugar
- water
- enriched flour

##
### Name
Diet Coke

### Ingredients
- carbonated water
- caramel color
- aspartame
```

##### Only allow "hash" style lists, but show explicit sequential key numbers

[](#only-allow-hash-style-lists-but-show-explicit-sequential-key-numbers)

```
Hashdown::write_to_file($x_groceries, '.../Groceries.md', true, false);
```

```
# Groceries
## 0
### Name
Twinkie

### Ingredients
#### 0
sugar

#### 1
water

#### 2
enriched flour

## 1
### Name
Diet Coke

### Ingredients
#### 0
carbonated water

#### 1
caramel color

#### 2
aspartame
```

##### Only allow "hash" style lists, and omit sequential keys where possible

[](#only-allow-hash-style-lists-and-omit-sequential-keys-where-possible)

```
Hashdown::write_to_file($x_groceries, '.../Groceries.md', false, false);
```

```
# Groceries
##
### Name
Twinkie

### Ingredients
####
sugar

####
water

####
enriched flour

##
### Name
Diet Coke

### Ingredients
####
carbonated water

####
caramel color

####
aspartame
```

### Reading and writing to / from strings and arrays

[](#reading-and-writing-to--from-strings-and-arrays)

In addition to writing and reading directly to and from .md files, you can also manipulate md strings directly, using the following functions:

#### x\_parse\_md\_string

[](#x_parse_md_string)

Accepts a string of Markdown content, and returns a corresponding PHP associative array, or false on failure.

##### Parameters

[](#parameters)

- string `$s_hd_content` String representing a Markdown document
- string `$s_line_delimeter` The string marking the boundary between lines in the file. Default is PHP\_EOL.

#### x\_parse\_md\_lines

[](#x_parse_md_lines)

Accepts an array of Markdown lines, and returns a corresponding PHP associative array, or false on failure.

##### Parameters

[](#parameters-1)

- array `$a_hd_lines` Array of lines of a Markdown document

#### s\_stringify\_x

[](#s_stringify_x)

Accepts a PHP associative array or object, and returns a corresponding Markdown string.

##### Parameters

[](#parameters-2)

- mixed `$x_data` The associative array or object to be converted.
- bool `$b_no_shorthand_lists` If true, don't use shorthand "dash" syntax for any lists
- bool `$b_omit_numeric_array_keys` If true, omit explicit key values for sequential numeric arrays

Testing
-------

[](#testing)

- cd to the directory
- composer install
- run `vendor/bin/phpunit`

###  Health Score

29

—

LowBetter than 60% of packages

Maintenance38

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 91.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~62 days

Recently: every ~78 days

Total

6

Last Release

457d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7ed784e72eda2bdaa709f27aa04877a66ea16a244016c9f74a35079569f8fb4d?d=identicon)[neckberg](/maintainers/neckberg)

---

Top Contributors

[![neckberg](https://avatars.githubusercontent.com/u/10238175?v=4)](https://github.com/neckberg "neckberg (11 commits)")[![dereuromark](https://avatars.githubusercontent.com/u/39854?v=4)](https://github.com/dereuromark "dereuromark (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/neckberg-hashdown/health.svg)

```
[![Health](https://phpackages.com/badges/neckberg-hashdown/health.svg)](https://phpackages.com/packages/neckberg-hashdown)
```

###  Alternatives

[mtdowling/jmespath.php

Declaratively specify how to extract elements from a JSON document

2.0k472.8M135](/packages/mtdowling-jmespathphp)[opis/closure

A library that can be used to serialize closures (anonymous functions) and arbitrary data.

2.6k230.0M283](/packages/opis-closure)[masterminds/html5

An HTML5 parser and serializer.

1.8k242.8M226](/packages/masterminds-html5)[sabberworm/php-css-parser

Parser for CSS Files written in PHP

1.8k191.2M63](/packages/sabberworm-php-css-parser)[michelf/php-markdown

PHP Markdown

3.5k52.4M344](/packages/michelf-php-markdown)[jms/metadata

Class/method/property metadata management in PHP

1.8k152.8M88](/packages/jms-metadata)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
