PHP 배열(Arrays)

PHP 배열(Arrays)

PHP의 [배열 함수(array functions)]에 대해 전체 목록이 궁금하다면 문서의 해당 챕터를 보시면 돼요.

PHP의 **배열(array)**은 사실 **순서가 있는 맵(ordered map)**이에요. 맵이란 *값(value)*을 *키(key)*에 연결해주는 타입이죠. 이 타입은 여러 용도에 맞게 최적화되어 있는데요, 배열(리스트, 벡터)로도, 해시 테이블(맵의 구현)로도, 사전(dictionary)으로도, 컬렉션으로도, 스택이나 큐로도 쓸 수 있고 그보다 더도 가능해요. 배열의 값이 또 다른 배열이 될 수 있기 때문에 트리나 다차원 배열도 만들 수 있어요.

이런 자료구조들에 대한 자세한 설명은 이 매뉴얼의 범위를 벗어나기 때문에 다루지 않을게요. 다만 각각에 대해 예시는 최소 하나씩 넣어뒀으니, 더 깊게 알고 싶다면 이 넓은 주제에 대한 많은 문헌을 참고하시면 좋아요.

문법(Syntax)

array()로 지정하기

배열은 array() 언어 구조를 이용해 만들 수 있어요. 쉼표로 구분된 key => value 쌍을 인자로 원하는 만큼 받죠.


array(
    key  => value,
    key2 => value2,
    key3 => value3,
    ...
)

마지막 배열 요소 뒤의 쉼표는 선택 사항이라 생략할 수 있어요. 보통 한 줄짜리 배열에서는 생략하는 편이에요. 즉 array(1, 2)array(1, 2, )보다 선호되죠. 반대로 여러 줄로 작성하는 배열에서는 마지막 쉼표를 쓰는 게 일반적이에요. 나중에 요소를 추가하기가 훨씬 쉬워지거든요.

참고: array()[]로 대체하는 **단축 배열 문법(short array syntax)**도 있어요.

Example #1 — A simple array

<?php
$array1 = array(
    "foo" => "bar",
    "bar" => "foo",
);

// Using the short array syntax
$array2 = [
    "foo" => "bar",
    "bar" => "foo",
];

var_dump($array1, $array2);
?>

키는 [int] 또는 [string] 타입이 될 수 있고, 값은 어떤 타입이든 될 수 있어요.

추가로 다음의 키 형변환(key cast) 규칙이 적용돼요:

  • [String] 중 유효한 10진수 [int]를 담고 있는 경우를 살펴볼게요. 숫자 앞에 + 기호가 붙어있지 않다면 이 문자열은 [int] 타입으로 변환돼요. 예를 들어 키 "8"은 실제로 8로 저장돼요. 반면 "08"은 유효한 10진수 정수가 아니기 때문에 변환되지 않아요.
  • [Float]도 [int]로 변환되는데, 이때 소수 부분은 버려져요. 예를 들어 키 8.7은 실제로 8로 저장되죠.
  • [Bool]도 [int]로 변환돼요. 즉 키 [true]는 실제로 1로, 키 [false]0으로 저장돼요.
  • [Null]은 빈 문자열로 변환돼요. 키 [null]은 실제로 ""로 저장되죠.
  • [Array]와 [object]는 키로 쓸 수 없어요. 이렇게 사용하면 Illegal offset type이라는 경고가 발생해요.

배열 선언에서 여러 요소가 같은 키를 쓰면 다른 것들은 모두 덮어써지고 마지막 것만 남아요.

Example #2 — Type Casting and Overwriting example

<?php
$array = array(
    1    => "a",
    "1"  => "b",
    1.5  => "c",
    true => "d",
);
var_dump($array);
?>

위 예시의 출력은 다음과 같아요.


array(1) {
  [1]=>
  string(1) "d"
}

위 예시의 모든 키는 전부 1로 변환되기 때문에, 새 요소가 추가될 때마다 값이 덮어써져서 마지막에 할당된 값 "d"만 남게 돼요.

PHP 배열은 [int] 키와 [string] 키를 동시에 가질 수 있는데요, PHP는 인덱스 배열과 연관 배열을 구분하지 않기 때문이에요.

Example #3 — Mixed int and string keys

<?php
$array = array(
    "foo" => "bar",
    "bar" => "foo",
    100   => -100,
    -100  => 100,
);
var_dump($array);
?>

위 예시의 출력은 다음과 같아요.


array(4) {
  ["foo"]=>
  string(3) "bar"
  ["bar"]=>
  string(3) "foo"
  [100]=>
  int(-100)
  [-100]=>
  int(100)
}

키는 선택 사항이에요. 키를 지정하지 않으면 PHP는 이전에 사용된 가장 큰 [int] 키에 1을 더한 값을 쓰게 돼요.

Example #4 — Indexed arrays without key

<?php
$array = array("foo", "bar", "hello", "world");
var_dump($array);
?>

위 예시의 출력은 다음과 같아요.


array(4) {
  [0]=>
  string(3) "foo"
  [1]=>
  string(3) "bar"
  [2]=>
  string(5) "hello"
  [3]=>
  string(5) "world"
}

일부 요소에만 키를 지정하고 나머지에는 생략하는 것도 가능해요.

Example #5 — Keys not on all elements

<?php
$array = array(
         "a",
         "b",
    6 => "c",
         "d",
);
var_dump($array);
?>

위 예시의 출력은 다음과 같아요.


array(4) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [6]=>
  string(1) "c"
  [7]=>
  string(1) "d"
}

마지막 값 "d"가 키 7을 받은 걸 볼 수 있어요. 그 이유는 그 앞에서 가장 큰 정수 키가 6이었기 때문이에요.

Example #6 — Complex Type Casting and Overwriting example 키 형변환과 요소 덮어쓰기의 모든 경우의 수를 담은 예시예요.

<?php
$array = array(
    1    => 'a',
    '1'  => 'b', // the value "a" will be overwritten by "b"
    1.5  => 'c', // the value "b" will be overwritten by "c"
    -1 => 'd',
    '01'  => 'e', // as this is not an integer string it will NOT override the key for 1
    '1.5' => 'f', // as this is not an integer string it will NOT override the key for 1
    true => 'g', // the value "c" will be overwritten by "g"
    false => 'h',
    '' => 'i',
    null => 'j', // the value "i" will be overwritten by "j"
    'k', // value "k" is assigned the key 2. This is because the largest integer key before that was 1
    2 => 'l', // the value "k" will be overwritten by "l"
);

var_dump($array);
?>

위 예시의 출력은 다음과 같아요.


array(7) {
  [1]=>
  string(1) "g"
  [-1]=>
  string(1) "d"
  ["01"]=>
  string(1) "e"
  ["1.5"]=>
  string(1) "f"
  [0]=>
  string(1) "h"
  [""]=>
  string(1) "j"
  [2]=>
  string(1) "l"
}

Example #7 — Negative index example 음수 정수 키 n을 할당하면, PHP는 다음 키를 n+1로 지정해줘요.

<?php
$array = [];

$array[-5] = 1;
$array[] = 2;

var_dump($array);
?>

위 예시의 출력은 다음과 같아요.


array(2) {
  [-5]=>
  int(1)
  [-4]=>
  int(2)
}

Warning PHP 8.3.0 이전에는 음수 정수 키 n을 할당하면 다음 키가 0으로 지정됐어요. 따라서 위 예시의 출력은 다음과 같았죠:


array(2) {
  [-5]=>
  int(1)
  [0]=>
  int(2)
}

대괄호 문법으로 배열 요소에 접근하기

배열 요소는 array[key] 문법으로 접근할 수 있어요.

Example #8 — Accessing array elements

<?php
$array = array(
    "foo" => "bar",
    42    => 24,
    "multi" => array(
         "dimensional" => array(
             "array" => "foo"
         )
    )
);

var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array["multi"]["dimensional"]["array"]);
?>

위 예시의 출력은 다음과 같아요.


string(3) "bar"
int(24)
string(3) "foo"

참고: PHP 8.0.0 이전에는 대괄호와 중괄호를 배열 요소 접근에 서로 바꿔 쓸 수 있었어요. (위 예시에서 $array[42]$array{42}가 같은 동작을 했죠.) 중괄호 문법은 PHP 7.4.0부터 폐기(deprecated)되었고, PHP 8.0.0부터는 지원되지 않아요.

Example #9 — Array dereferencing

<?php
function getArray() {
    return array(1, 2, 3);
}

$secondElement = getArray()[1];

var_dump($secondElement);
?>

참고: 정의되지 않은 배열 키에 접근하는 것은 다른 어떤 정의되지 않은 변수에 접근하는 것과 같아요. [E_WARNING] 수준의 오류 메시지(PHP 8.0.0 이전에는 [E_NOTICE] 수준)가 발생하고, 결과는 [null]이 돼요.

참고: [string]이 아닌 스칼라 값을 배열 역참조(array dereference)하면 [null]이 나와요. PHP 7.4.0 이전에는 오류 메시지가 발생하지 않았는데, PHP 7.4.0부터 [E_NOTICE]가, PHP 8.0.0부터는 [E_WARNING]이 발생해요.

대괄호 문법으로 배열 만들기·수정하기

기존 [array]는 그 안에 값을 명시적으로 설정해 수정할 수 있어요.

값을 배열에 할당하면서 대괄호 안에 키를 지정하면 되는데요, 키는 생략할 수도 있어요. 그 경우 빈 대괄호 []가 됩니다.


$arr[key] = value;
$arr[] = value;
// key may be an int or string
// value may be any value of any type

만약 $arr이 아직 존재하지 않거나 [null]이나 [false]로 설정되어 있다면 새로 만들어지기 때문에, 이 방법은 배열을 만드는 또 하나의 방법이 되기도 해요. 다만 이 방식은 권장되지 않아요. $arr에 이미 어떤 값(예를 들어 요청 변수에서 온 [string])이 들어 있다면 그 값이 그대로 남아 있어서, []가 사실은 [string 접근 연산자]를 의미하게 될 수도 있거든요. 변수는 항상 직접 할당으로 초기화하는 편이 더 좋아요.

참고: PHP 7.1.0부터 문자열에 빈 인덱스 연산자를 적용하면 치명적인 오류가 발생해요. 이전에는 문자열이 조용히 배열로 변환됐었죠.

참고: PHP 8.1.0부터 [false] 값에서 새 배열을 만드는 것은 폐기(deprecated)되었어요. [null]이나 정의되지 않은 값에서 새 배열을 만드는 것은 여전히 허용돼요.

특정 값을 바꾸려면 그 요소에 키를 사용해 새 값을 할당하면 돼요. 키/값 쌍을 제거하려면 그 요소에 [unset()] 함수를 호출하면 되고요.

Example #10 — Using Square Brackets with Arrays

<?php
$arr = array(5 => 1, 12 => 2);

$arr[] = 56;    // This is the same as $arr[13] = 56;
                // at this point of the script

$arr["x"] = 42; // This adds a new element to
                // the array with key "x"

unset($arr[5]); // This removes the element from the array

var_dump($arr);

unset($arr);    // This deletes the whole array

var_dump($arr);
?>

참고: 키를 지정하지 않으면 키는 기존에 존재하는 가장 큰 정수 인덱스에 1을 더한 값이 돼요. 배열에 양의 정수 인덱스가 하나도 없다면 키는 0이 되죠. PHP 8.3.0부터는 음수 정수가 될 수도 있어요.

이때 사용되는 가장 큰 정수 키가 현재 [array]에 반드시 존재할 필요는 없다는 점을 기억해두세요. 배열이 마지막으로 다시 인덱싱(re-index)된 이후 어느 시점에 그 키가 존재했기만 하면 돼요. 다음 예시를 보면 이해가 쉬울 거예요.

<?php
// Create a simple array.
$array = array(1, 2, 3, 4, 5);
print_r($array);

// Now delete every item, but leave the array itself intact:
foreach ($array as $i => $value) {
    unset($array[$i]);
}
print_r($array);

// Append an item (note that the new key is 5, instead of 0).
$array[] = 6;
print_r($array);

// Re-index:
$array = array_values($array);
$array[] = 7;
print_r($array);
?>

위 예시의 출력은 다음과 같아요.


Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
)
Array
(
)
Array
(
    [5] => 6
)
Array
(
    [0] => 6
    [1] => 7
)

배열 구조 분해(Array destructuring)

배열은 [](PHP 7.1.0부터) 또는 [list()] 언어 구조를 사용해 구조 분해할 수 있어요. 이 구조들을 이용하면 배열을 서로 다른 변수들로 분해할 수 있죠.

Example #11 — Array Destructuring

<?php
$source_array = ['foo', 'bar', 'baz'];

[$foo, $bar, $baz] = $source_array;

echo $foo, PHP_EOL;    // prints "foo"
echo $bar, PHP_EOL;    // prints "bar"
echo $baz, PHP_EOL;    // prints "baz"
?>

배열 구조 분해는 [foreach]에서도 쓸 수 있는데, 다차원 배열을 순회하면서 분해할 때 유용해요.

Example #12 — Array Destructuring in Foreach

<?php
$source_array = [
    [1, 'John'],
    [2, 'Jane'],
];

foreach ($source_array as [$id, $name]) {
    echo "{$id}: '{$name}'\n";
}
?>

변수를 제공하지 않으면 해당 배열 요소는 무시돼요. 배열 구조 분해는 항상 인덱스 0부터 시작하죠.

Example #13 — Ignoring Elements

<?php
$source_array = ['foo', 'bar', 'baz'];

// Assign the element at index 2 to the variable $baz
[, , $baz] = $source_array;

echo $baz;    // prints "baz"
?>

PHP 7.1.0부터는 연관 배열도 구조 분해할 수 있어요. 인덱스를 명시적으로 지정할 수 있기 때문에 숫자 인덱스 배열에서 원하는 요소를 더 쉽게 골라낼 수도 있죠.

Example #14 — Destructuring Associative Arrays

<?php
$source_array = ['foo' => 1, 'bar' => 2, 'baz' => 3];

// Assign the element at index 'baz' to the variable $three
['baz' => $three] = $source_array;

echo $three, PHP_EOL;  // prints 3

$source_array = ['foo', 'bar', 'baz'];

// Assign the element at index 2 to the variable $baz
[2 => $baz] = $source_array;

echo $baz, PHP_EOL;    // prints "baz"
?>

배열 구조 분해는 두 변수의 값을 손쉽게 바꿔치기(swap)하는 데에도 쓸 수 있어요.

Example #15 — Swapping Two Variable

<?php
$a = 1;
$b = 2;

[$b, $a] = [$a, $b];

echo $a, PHP_EOL;    // prints 2
echo $b, PHP_EOL;    // prints 1
?>

참고: 전개 연산자(...)는 할당에서 지원되지 않아요.

참고: 정의되지 않은 배열 키에 접근하는 것은 다른 어떤 정의되지 않은 변수에 접근하는 것과 같아요. [E_WARNING] 수준의 오류 메시지(PHP 8.0.0 이전에는 [E_NOTICE] 수준)가 발생하고, 결과는 [null]이 돼요.

참고: 스칼라 값을 구조 분해하면 모든 변수에 [null]이 할당돼요.

유용한 함수(Useful functions)

배열 작업에 쓸모 있는 함수가 꽤 많아요. [배열 함수(array functions)] 섹션을 참고해보세요.

참고: [unset()] 함수는 [array]에서 키를 제거할 수 있게 해줘요. 다만 배열이 다시 인덱싱되지는 않는다는 점을 알아두세요. 정말 "제거하고 옮기는(remove and shift)" 동작이 필요하다면 [array_values()] 함수를 사용해 배열을 다시 인덱싱하면 돼요.

Example #16 — Unsetting Intermediate Elements

<?php
$a = array(1 => 'one', 2 => 'two', 3 => 'three');

/* will produce an array that would have been defined as
   $a = array(1 => 'one', 3 => 'three');
   and NOT
   $a = array(1 => 'one', 2 =>'three');
*/
unset($a[2]);
var_dump($a);

$b = array_values($a);
// Now $b is array(0 => 'one', 1 =>'three')
var_dump($b);
?>

[foreach] 제어 구조는 바로 [array]를 위해 존재한다고 볼 수 있어요. 배열을 쉽게 순회할 수 있는 방법을 제공하죠.

배열의 좋은 습관과 나쁜 습관(Array do's and don'ts)

$foo[bar]는 틀린 걸까요?

문자열 리터럴 배열 인덱스에는 항상 따옴표를 붙여야 해요. 예를 들어 $foo['bar']는 올바른데 $foo[bar]는 그렇지 않죠. 그런데 왜 그럴까요? 오래된 스크립트에서는 이런 문법을 자주 마주치곤 해요:

<?php
$foo[bar] = 'enemy';
echo $foo[bar];
// etc
?>

이건 틀린 코드인데도 동작하죠. 그 이유는 이 코드가 [string]인 'bar'(따옴표에 주목하세요)가 아니라 정의되지 않은 상수(undefined constant) bar를 가리키고 있기 때문이에요. PHP는 알려진 어떤 기호에도 해당하지 않는 따옴표 없는 [string]인 **베어 문자열(bare string)**을 자동으로 그 내용을 담은 [string]으로 변환해주거든요. 예를 들어 bar라는 상수가 정의되어 있지 않다면 PHP는 [string] 'bar'를 대신 넣어서 사용해요.

Warning 정의되지 않은 상수를 베어 문자열로 취급하는 이 폴백(fallback)은 [E_NOTICE] 수준의 오류를 발생시켰어요. PHP 7.2.0부터는 폐기(deprecated)되어 [E_WARNING] 수준의 오류를 발생시키고, PHP 8.0.0부터는 아예 제거되어 [Error] 예외를 던져요.

그렇다고 해서 항상 키에 따옴표를 붙이라는 뜻은 아니에요. [constants]나 [variables]인 키에는 따옴표를 붙이면 안 돼요. PHP가 그것을 해석하지 못하게 되거든요.

Example #17 — Key Quoting

<?php
error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('html_errors', false);

// Simple array:
$array = array(1, 2);
$count = count($array);

for ($i = 0; $i < $count; $i++) {
    echo "\nChecking $i: \n";
    echo "Bad: " . $array['$i'] . "\n";
    echo "Good: " . $array[$i] . "\n";
    echo "Bad: {$array['$i']}\n";
    echo "Good: {$array[$i]}\n";
}
?>

위 예시의 출력은 다음과 같아요.


Checking 0:
Notice: Undefined index:  $i in /path/to/script.html on line 9
Bad:
Good: 1
Notice: Undefined index:  $i in /path/to/script.html on line 11
Bad:
Good: 1

Checking 1:
Notice: Undefined index:  $i in /path/to/script.html on line 9
Bad:
Good: 2
Notice: Undefined index:  $i in /path/to/script.html on line 11
Bad:
Good: 2

이 동작을 더 잘 보여주는 예시를 몇 개 더 볼게요.

Example #18 — More Examples

<?php
// Show all errors
error_reporting(E_ALL);

$arr = array('fruit' => 'apple', 'veggie' => 'carrot');

// Correct
echo $arr['fruit'], PHP_EOL;  // apple
echo $arr['veggie'], PHP_EOL; // carrot

// Incorrect. This does not work and throws a PHP Error because
// of an undefined constant named fruit
//
// Error: Undefined constant "fruit"
try {
    echo $arr[fruit];
} catch (Error $e) {
    echo get_class($e), ': ', $e->getMessage(), PHP_EOL;
}

// This defines a constant to demonstrate what's going on.  The value 'veggie'
// is assigned to a constant named fruit.
define('fruit', 'veggie');

// Notice the difference now
echo $arr['fruit'], PHP_EOL;  // apple
echo $arr[fruit], PHP_EOL;    // carrot

// The following is okay, as it's inside a string. Constants are not looked for
// within strings, so no error occurs here
echo "Hello $arr[fruit]", PHP_EOL;      // Hello apple

// With one exception: braces surrounding arrays within strings allows constants
// to be interpreted
echo "Hello {$arr[fruit]}", PHP_EOL;    // Hello carrot
echo "Hello {$arr['fruit']}", PHP_EOL;  // Hello apple

// Concatenation is another option
echo "Hello " . $arr['fruit'], PHP_EOL; // Hello apple
?>
<?php
// This will not work, and will result in a parse error, such as:
// Parse error: parse error, expecting T_STRING' or T_VARIABLE' or T_NUM_STRING'
// This of course applies to using superglobals in strings as well
print "Hello $arr['fruit']";
print "Hello $_GET['foo']";
?>

[syntax] 섹션에서 설명했듯이 대괄호([]) 안의 내용은 **표현식(expression)**이어야 해요. 즉 이런 코드는 동작한다는 뜻이죠:

<?php
echo $arr[somefunc($bar)];
?>

이 예시는 함수의 반환값을 배열 인덱스로 사용하는 경우예요. PHP는 상수도 알고 있죠:

<?php
$error_descriptions[E_ERROR]   = "A fatal error has occurred";
$error_descriptions[E_WARNING] = "PHP issued a warning";
$error_descriptions[E_NOTICE]  = "This is just an informal notice";
?>

[E_ERROR]도 첫 번째 예시의 bar처럼 유효한 식별자라는 점을 눈여겨보세요. 그런데 사실 마지막 예시는 다음과 같이 쓰는 것과 같아요:

<?php
$error_descriptions[1] = "A fatal error has occurred";
$error_descriptions[2] = "PHP issued a warning";
$error_descriptions[8] = "This is just an informal notice";
?>

왜냐하면 [E_ERROR]1과 같기 때문이죠.

그렇다면 도대체 왜 나쁜 걸까요?

언젠가 PHP 팀이 또 다른 상수나 키워드를 추가할 수도 있고, 다른 코드의 어떤 상수가 간섭할 수도 있기 때문이에요. 예를 들어 emptydefault 같은 단어를 이런 식으로 쓰는 것은 이미 틀렸어요. 그 둘은 [예약 키워드(reserved keywords)]이거든요.

참고: 다시 강조하지만, 큰따옴표 문자열 안에서는 배열 인덱스에 따옴표를 붙이지 않아도 유효해요. "$foo[bar]"는 유효하죠. 자세한 이유는 위 예시들과 [문자열 안에서의 변수 파싱] 섹션을 참고하세요.

배열로 변환하기(Converting to array)

[int], [float], [string], [bool], [resource] 타입 어느 것이든 값을 [array]로 변환하면 인덱스가 0인 단일 요소를 가진 배열이 돼요. 그 요소의 값은 변환된 스칼라 값이죠. 즉 (array) $scalarValue는 정확히 array($scalarValue)와 같아요.

[object]를 [array]로 변환하면 결과는 객체의 프로퍼티들을 요소로 가진 배열이 돼요. 키는 멤버 변수 이름이 되는데, 몇 가지 주목할 만한 예외가 있어요: 정수 프로퍼티는 접근할 수 없고, private 변수는 변수 이름 앞에 클래스 이름이 붙으며, protected 변수는 변수 이름 앞에 *가 붙어요. 이렇게 앞에 붙는 값들은 양쪽에 NUL 바이트를 가지게 되죠. 초기화되지 않은 [타입이 지정된 프로퍼티(typed properties)]는 조용히 버려져요.

Example #19 — Converting to an Array

<?php

class A {
    private $B;
    protected $C;
    public $D;
    function __construct()
    {
        $this->{1} = null;
    }
}

var_export((array) new A());
?>

위 예시의 출력은 다음과 같아요.


array (
  '' . "\0" . 'A' . "\0" . 'B' => NULL,
  '' . "\0" . '*' . "\0" . 'C' => NULL,
  'D' => NULL,
  1 => NULL,
)

NUL 때문에 예상 밖의 동작이 발생할 수 있어요.

Example #20 — Casting an Object to an Array

<?php

class A {
    private $A; // This will become '\0A\0A'
}

class B extends A {
    private $A; // This will become '\0B\0A'
    public $AA; // This will become 'AA'
}

var_dump((array) new B());
?>

PHP 8.0에서 위 예시의 출력:


array(3) {
  ["BA"]=>
  NULL
  ["AA"]=>
  NULL
  ["AA"]=>
  NULL
}

PHP 8.1에서 위 예시의 출력:


array(3) {
  ["AA"]=>
  NULL
  ["BA"]=>
  NULL
  ["AA"]=>
  NULL
}

위 결과는 마치 AA라는 키가 두 개 있는 것처럼 보이지만, 사실 그중 하나는 실제로 '\0A\0A'예요.

[null]을 [array]로 변환하면 빈 [array]가 돼요.

비교하기(Comparing)

배열은 [array_diff()] 함수와 [배열 연산자(array operators)]를 사용해 비교할 수 있어요.

배열 언패킹(Array unpacking)

...가 앞에 붙은 배열은 배열 정의 중에 그 자리에서 펼쳐져요. 펼칠 수 있는 것은 [Traversable]을 구현한 배열과 객체뿐이에요. ...를 사용한 배열 언패킹은 PHP 7.4.0부터 사용할 수 있는데, 이것을 전개 연산자(spread operator)라고도 불러요.

여러 번 펼칠 수도 있고, ... 연산자 앞이나 뒤에 일반 요소를 추가할 수도 있어요.

Example #21 — Simple array unpacking

<?php
// Using short array syntax.
// Also, works with array() syntax.
$arr1 = [1, 2, 3];
$arr2 = [...$arr1]; // [1, 2, 3]
$arr3 = [0, ...$arr1]; // [0, 1, 2, 3]
$arr4 = [...$arr1, ...$arr2, 111]; // [1, 2, 3, 1, 2, 3, 111]
$arr5 = [...$arr1, ...$arr1]; // [1, 2, 3, 1, 2, 3]

function getArr() {
  return ['a', 'b'];
}
$arr6 = [...getArr(), 'c' => 'd']; // ['a', 'b', 'c' => 'd']

var_dump($arr1, $arr2, $arr3, $arr4, $arr5, $arr6);
?>

... 연산자로 배열을 언패킹하는 것은 [array_merge()] 함수의 의미론을 따르는 방식으로 동작해요. 즉 나중에 나온 문자열 키가 앞선 것을 덮어쓰고, 정수 키는 다시 번호가 매겨지죠.

Example #22 — Array unpacking with duplicate key

<?php
// string key
$arr1 = ["a" => 1];
$arr2 = ["a" => 2];
$arr3 = ["a" => 0, ...$arr1, ...$arr2];
var_dump($arr3); // ["a" => 2]

// integer key
$arr4 = [1, 2, 3];
$arr5 = [4, 5, 6];
$arr6 = [...$arr4, ...$arr5];
var_dump($arr6); // [1, 2, 3, 4, 5, 6]
// Which is [0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6]
// where the original integer keys have not been retained.
?>

참고: 정수도 문자열도 아닌 키는 [TypeError]를 던져요. 그런 키는 [Traversable] 객체에 의해서만 만들어질 수 있어요.

참고: PHP 8.1 이전에는 문자열 키를 가진 배열을 언패킹하는 것이 지원되지 않았어요.

<?php

$arr1 = [1, 2, 3];
$arr2 = ['a' => 4];
$arr3 = [...$arr1, ...$arr2];
// Fatal error: Uncaught Error: Cannot unpack array with string keys in example.php:5

$arr4 = [1, 2, 3];
$arr5 = [4, 5];
$arr6 = [...$arr4, ...$arr5]; // works. [1, 2, 3, 4, 5]
?>

예시(Examples)

PHP의 배열 타입은 정말 다재다능해요. 몇 가지 예시를 볼게요.

Example #23 — Array Versatility

<?php
// This:
$a = array( 'color' => 'red',
            'taste' => 'sweet',
            'shape' => 'round',
            'name'  => 'apple',
            4        // key will be 0
          );

$b = array('a', 'b', 'c');

var_dump($a, $b);

// . . .is completely equivalent with this:
$a = array();
$a['color'] = 'red';
$a['taste'] = 'sweet';
$a['shape'] = 'round';
$a['name']  = 'apple';
$a[]        = 4;        // key will be 0

$b = array();
$b[] = 'a';
$b[] = 'b';
$b[] = 'c';

// After the above code is executed, $a will be the array
// array('color' => 'red', 'taste' => 'sweet', 'shape' => 'round',
// 'name' => 'apple', 0 => 4), and $b will be the array
// array(0 => 'a', 1 => 'b', 2 => 'c'), or simply array('a', 'b', 'c').

var_dump($a, $b);
?>

Example #24 — Using array()

<?php
// Array as (property-)map
$map = array( 'version'    => 4,
              'OS'         => 'Linux',
              'lang'       => 'english',
              'short_tags' => true
            );
var_dump($map);

// strictly numerical keys
// this is the same as array(0 => 7, 1 => 8, ...)
$array = array( 7,
                8,
                0,
                156,
                -10
              );
var_dump($array);

$switching = array(         10, // key = 0
                    5    =>  6,
                    3    =>  7,
                    'a'  =>  4,
                            11, // key = 6 (maximum of integer-indices was 5)
                    '8'  =>  2, // key = 8 (integer!)
                    '02' => 77, // key = '02'
                    0    => 12  // the value 10 will be overwritten by 12
                  );
var_dump($switching);

// empty array
$empty = array();
var_dump($empty);
?>

Example #25 — Collection

<?php
$colors = array('red', 'blue', 'green', 'yellow');

foreach ($colors as $color) {
    echo "Do you like $color?\n";
}

?>

위 예시의 출력은 다음과 같아요.


Do you like red?
Do you like blue?
Do you like green?
Do you like yellow?

배열의 값을 직접 바꾸고 싶다면 참조(reference)로 전달하면 돼요.

Example #26 — Changing element in the loop

<?php
$colors = array('red', 'blue', 'green', 'yellow');

foreach ($colors as &$color) {
    $color = mb_strtoupper($color);
}
unset($color); /* ensure that following writes to
$color will not modify the last array element */

print_r($colors);
?>

위 예시의 출력은 다음과 같아요.


Array
(
    [0] => RED
    [1] => BLUE
    [2] => GREEN
    [3] => YELLOW
)

이 예시는 인덱스가 1부터 시작하는 배열을 만들어요.

Example #27 — One-based index

<?php
$firstquarter = array(1 => 'January', 'February', 'March');
print_r($firstquarter);
?>

위 예시의 출력은 다음과 같아요.


Array
(
    [1] => January
    [2] => February
    [3] => March
)

Example #28 — Filling an array

<?php
// fill an array with all items from a directory
$handle = opendir('.');
while (false !== ($file = readdir($handle))) {
    $files[] = $file;
}
closedir($handle);

var_dump($files);
?>

[Array]에는 순서가 있어요. 이 순서는 다양한 정렬 함수를 사용해 바꿀 수 있고, 자세한 내용은 [배열 함수(array functions)] 섹션에서 확인할 수 있어요. [count()] 함수로 배열의 항목 개수를 셀 수도 있죠.

Example #29 — Sorting an array

<?php
sort($files);
print_r($files);
?>

[array]의 값은 무엇이든 될 수 있기 때문에, 또 다른 [array]가 될 수도 있어요. 덕분에 재귀적이거나 다차원인 [array]를 만들 수 있죠.

Example #30 — Recursive and multi-dimensional arrays

<?php
$fruits = array ( "fruits"  => array ( "a" => "orange",
                                       "b" => "banana",
                                       "c" => "apple"
                                     ),
                  "numbers" => array ( 1,
                                       2,
                                       3,
                                       4,
                                       5,
                                       6
                                     ),
                  "holes"   => array (      "first",
                                       5 => "second",
                                            "third"
                                     )
                );
var_dump($fruits);

// Some examples to address values in the array above
echo $fruits["holes"][5];    // prints "second"
echo $fruits["fruits"]["a"]; // prints "orange"
unset($fruits["holes"][0]);  // remove "first"

// Create a new multi-dimensional array
$juices["apple"]["green"] = "good";
var_dump($juices);
?>

[Array] 할당은 항상 **값 복사(value copying)**로 이루어져요. [참조 연산자(reference operator)]를 사용하면 배열을 참조로 복사할 수 있죠.

Example #31 — Array Copying

<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
             // $arr1 is still array(2, 3)

$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same

var_dump($arr1, $arr2, $arr3);
?>