Arrays7 min readExamples run on PHP 8.5.10

compact()

Learn how PHP 8.4 compact() builds an associative array from named variables, how nested name lists work, and what happens with undefined variables.

Signature

compact(array|string $var_name, array|string ...$var_names): array

Purpose

compact() turns a set of local variables into an associative array. You give it the names of variables, and it returns an array where each name is a key and the variable's current value is the matching value. It is the conceptual opposite of extract(), which unpacks array entries into variables.

The function is handy when you have already computed several values and want to return them together, pass them to a template, or serialize them, without writing ['id' => $id, 'name' => $name] by hand.

Signature

Parameters

  • $var_name: a string naming a variable, or an array of names. At least one argument is required.
  • ...$var_names: any number of additional strings or arrays of names.

Names are written without the leading $. They are case-sensitive, just like variables. An array of names may itself contain further arrays, and compact() walks through them recursively. There are no default values, because every argument is a name to look up.

The lookup happens in the current symbol table, meaning the scope where compact() is called. Inside a function it sees that function's parameters and local variables, not globals.

Return value and failure cases

The function returns an array. Keys appear in the order the names are processed, and values are copies of the variables' current contents.

If a name refers to a variable that does not exist, PHP issues an E_WARNING and leaves that name out of the result. This warning behavior applies since PHP 8.0. In PHP 7.3 it was an E_NOTICE, and before that unset names were skipped silently. The call does not throw an exception, so code that ignores warnings can end up with a smaller array than intended.

A variable that exists but holds null is not missing. It is included with a null value.

Example 1: names and nested name lists

This mixes a single name with an array of names. The order in the result follows the order of the arguments.

Example
<?php
$city = "San Francisco";
$state = "CA";
$event = "SIGGRAPH";
$locationVars = ["city", "state"];
$result = compact("event", $locationVars);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"event":"SIGGRAPH","city":"San Francisco","state":"CA"}

Example 2: returning values from a function

Parameters count as local variables, so they can be named too. Note that $note is null yet still appears in the output.

Example
<?php
function makeUser(int $id, string $name): array {
    $active = true;
    $note = null;
    return compact('id', 'name', 'active', 'note');
}

echo json_encode(makeUser(7, "Ada"), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"id":7,"name":"Ada","active":true,"note":null}

Example 3: an undefined variable

Here a custom error handler reports the warning level instead of printing a message that contains file paths. The missing name is simply absent from the result.

Example
<?php
set_error_handler(function (int $errno, string $errstr): bool {
    echo $errno === E_WARNING ? "warning raised\n" : "other level\n";
    return true;
});

$present = 1;
$result = compact('present', 'absent');
restore_error_handler();

echo json_encode($result), "\n";
Output
warning raised
{"present":1}

Edge cases

  • Scope matters. Only variables visible in the calling scope are found. A global variable is not seen inside a function unless it was imported into that scope.
  • Superglobals cannot be passed. Arrays such as $_GET or $_SERVER may not be named in compact() from within a function.
  • Null is a value. Unlike isset(), compact() cares whether the variable exists, not whether it is non-null.
  • Values are copied. Changing the returned array afterward does not change the original variables.
  • Dynamic names are possible but fragile. You can build the list of names at runtime, yet a typo then becomes a runtime warning rather than something static analysis easily catches.

Common mistakes

  1. Including the dollar sign. compact('$name') looks for a variable literally called $name, which is not what you want. Write compact('name').
  2. Passing values instead of names. compact($name) uses the contents of $name as a variable name. This is occasionally intended, but usually a bug.
  3. Ignoring warnings. A misspelled name silently shrinks the result in production if warnings are hidden. Treat the warning as a bug signal.
  4. Expecting global lookup. Calling compact() in a function does not read global variables.
  5. Overusing it. For two or three values an explicit array literal is clearer and easier to refactor with an IDE.
  • extract() imports array entries into the current symbol table as variables, the reverse operation.
  • array_merge() and the + operator combine the result of compact() with other arrays.
  • get_defined_vars() returns every variable in the current scope, instead of a chosen few.

Recap

compact() builds an associative array from variable names in the current scope. Pass names without $, singly or in nested arrays. Existing variables, including those set to null, are included. Names that do not exist raise an E_WARNING since PHP 8.0 and are omitted from the result.

Tested examples

Names and nested name lists
<?php
$city = "San Francisco";
$state = "CA";
$event = "SIGGRAPH";
$locationVars = ["city", "state"];
$result = compact("event", $locationVars);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"event":"SIGGRAPH","city":"San Francisco","state":"CA"}
Returning values from a function
<?php
function makeUser(int $id, string $name): array {
    $active = true;
    $note = null;
    return compact('id', 'name', 'active', 'note');
}

echo json_encode(makeUser(7, "Ada"), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"id":7,"name":"Ada","active":true,"note":null}
An undefined variable raises a warning
<?php
set_error_handler(function (int $errno, string $errstr): bool {
    echo $errno === E_WARNING ? "warning raised\n" : "other level\n";
    return true;
});

$present = 1;
$result = compact('present', 'absent');
restore_error_handler();

echo json_encode($result), "\n";
Output
warning raised
{"present":1}