Strings7 min readExamples run on PHP 8.5.10

parse_str()

Learn how PHP 8.4 parse_str() turns a URL query string into an array, including decoding, nested keys, name mangling and common pitfalls.

Signature

parse_str(string $string, array &$result): void

Purpose

parse_str() reads a string that is formatted like the query part of a URL, such as page=2&sort=name, and fills an array with the pairs it finds. It is useful when a query string reaches your code as plain text, for example from a stored link, a log line or a test fixture, rather than through $_GET.

Signature

Parameters and defaults

  • $string is the text to parse. Give it only the query portion, without the leading ?. If you have a whole URL, extract the query first, for example with parse_url().
  • $result is passed by reference. PHP assigns a new array to it that holds the extracted keys and values. It has no default, and it has been mandatory since PHP 8.0.0. Older code that omitted it created variables in the current scope. That style was deprecated in PHP 7.2 and no longer works, so always pass a result variable.

Return value and failure behavior

The function returns void, so the result lives only in the variable you passed. Writing $data = parse_str($q, $data); is a mistake because the assigned value would be null. Malformed input does not throw an exception. PHP extracts what it can. The function is also affected by the max_input_vars directive, whose default is 1000. If a string holds more variables than the limit allows, PHP emits an E_WARNING and leaves out the extra ones.

Every value is already URL-decoded using the same rules as urldecode(). This means + becomes a space and %C3%A3 becomes the matching UTF-8 character.

Example 1: basic pairs and list syntax

A key that ends in [] collects its values into a list, in the order they appear.

Example
<?php
parse_str("first=value&arr[]=foo+bar&arr[]=baz", $output);
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"first":"value","arr":["foo bar","baz"]}

Notice that foo+bar arrives as foo bar.

Example 2: name mangling and percent decoding

Spaces and dots in parameter names are converted to underscores. This follows the rules for PHP variable names, and it applies even when you use the recommended $result argument. Values are decoded, so non-ASCII text encoded as UTF-8 percent sequences comes back readable.

Example
<?php
parse_str("My Value=Something&user.name=Ana&city=S%C3%A3o+Paulo", $output);
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"My_Value":"Something","user_name":"Ana","city":"São Paulo"}

If you expected a key named user.name, look for user_name instead.

Example 3: nested keys, duplicates and empty values

Bracket syntax with a name inside builds an associative sub-array. When the same plain key appears twice, the later value replaces the earlier one. A name with no equals sign, or with nothing after it, produces an empty string.

Example
<?php
parse_str("a[b]=1&a[c]=2&x=1&x=2&flag&empty=", $output);
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"a":{"b":"1","c":"2"},"x":"2","flag":"","empty":""}

All the scalar values are strings, including the digits, because a query string carries no type information.

Edge cases

  • Everything is a string. Convert with (int), filter_var() or similar if you need numbers or booleans.
  • Repeated keys without brackets overwrite. Use name[]= if you want to keep every value.
  • Bracket keys are interpreted. Input controlled by a user can create nested arrays, so validate the shape of the result before you rely on it.
  • Too many variables. Anything beyond max_input_vars is dropped with a warning.
  • Only the query is parsed. A leading ? or a full URL becomes part of the first key. Strip or extract the query first.

Common mistakes

  1. Calling the function with a single argument. This is an error in PHP 8, because $result is required.
  2. Using the return value. It is always null.
  3. Searching the result for keys with dots or spaces. They have been changed to underscores.
  4. Decoding the values a second time with urldecode(). This can corrupt data that legitimately contains a percent sign or a plus sign after the first decoding.
  5. Trusting types and structure. A parameter you expect to be text may arrive as an array if the client sends name[]=x.
  • http_build_query() does the reverse and creates a query string from an array.
  • parse_url() splits a URL into scheme, host, path, query and fragment.
  • urldecode() decodes a single encoded string.
  • pathinfo() describes file path parts, which is useful alongside URL handling.

Recap

parse_str() converts a query string into an array stored in the variable you pass by reference. It decodes values, mangles spaces and dots in names into underscores, builds nested arrays from bracket syntax, lets later duplicates win, and returns nothing. Always pass the result argument and validate what comes back.

Tested examples

Basic pairs and list syntax
<?php
parse_str("first=value&arr[]=foo+bar&arr[]=baz", $output);
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"first":"value","arr":["foo bar","baz"]}
Name mangling and percent decoding
<?php
parse_str("My Value=Something&user.name=Ana&city=S%C3%A3o+Paulo", $output);
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"My_Value":"Something","user_name":"Ana","city":"São Paulo"}
Nested keys, duplicates and empty values
<?php
parse_str("a[b]=1&a[c]=2&x=1&x=2&flag&empty=", $output);
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"a":{"b":"1","c":"2"},"x":"2","flag":"","empty":""}