PHP 매뉴얼
이전 | 6. 장. 변수형 | 다음

# 배열

PHP에서 배열은 실질적으로 순서가 있는 맵이다. 한 맵은 values를 keys로 맵핑하는 타입이다. 이 타입은 몇가지 목적에 의해 옵티마이징될수 있다. 그래서 그 타입을 실제 배열이나 리스트(vector), 해쉬테이블(map의 구현), 딕셔너리(dictionary), 컬렉션(collection), 스택(stack), 큐(queue), 등등으로 사용할수 있다. 다른 PHP 배열을 값으로 갖을수 있기 때문에, 트리(tree)를 아주 쉽게 시뮬레이션할수 있다.

그런 데이터 구조(자료 구조)는 이 매뉴얼의 범위를 벗어난다. 그러나 그들 각각의 예를 최소한 하나는 발견할수 있을것이다. 자세한 정보를 위해 이 광범위한 주제에 대한 참고서적을 제시해줄것이다.

## 문법

### array()함수로 명기

array는 array() 언어-구조에 의해 생성될수 있다. 이 함수는 콤마로 구분되는 몇 개의 ``key` => `value``쌍을 취할수 있다.

    array( [key =>] value
         , ...
         )
    // key may be an integer or string
    // value may be any value

`<?php $arr = array("foo" => "bar", 12 => true); echo $arr["foo"]; // bar echo $arr[12]; // 1 ?>`

`key`는 `integer`나 string타입이 될수 있다. key가 표준적인 integer타입이면, 그 값으로 해석될것이다 (즉, `"8"`은 `8`로 해석되는 반면, `"08"`은 `"08"`로 해석된다). PHP에서 인덱스 배열과 연관 배열 사이는 아무 차이가 없다; 오직 하나의 배열 타입만이 있는데, 그 배열은 정수나 문자열 인덱스를 모두 포함할수 있다.

값은 모든 종류의 PHP 타입이 될수 있다.

`<?php $arr = array("somearray" => array(6 => 5, 13 => 9, "a" => 42)); echo $arr["somearray"][6]; // 5 echo $arr["somearray"][13]; // 9 echo $arr["somearray"]["a"]; // 42 ?>`

주어진 값에 대한 key를 표기하지 않으면, 정수 인덱스의 최대값이 취해져서 새로운 key는 최대값 + 1이 될것이다. 이미 값을 보유하고 있는 key를 지정하게 되면, 그 값은 덮어씌어질것이다.

`<?php // This array is the same as ... array(5 => 43, 32, 56, "b" => 12); // ...this array array(5 => 43, 6 => 32, 7 => 56, "b" => 12); ?>`

주의
PHP 4.3.0에서는 위에서 설명한 인덱스 생성 동작이 변경되었다. 즉, 현재 최대 key가 음수인 배열에 추가동작이 발생하면, 다음 key는 제로 (`0`)가 될것이다. 전에는, 새로운 인덱스는 기존의 가장 큰 key + 1로 되었었다. 양수의 인덱스에는 같은 동작을 한다.

key로 `TRUE`를 사용하는 것은 integer `1` key가 될것이다. key로 `FALSE`를 사용하면 integer `0` key가 될것이다. key로 `NULL`을 사용하면 빈 문자열로 취급될것이다. key로 빈문자열을 사용하는 것은 빈 문자열을 갖는 key를 만들고 그 값을 생성 (또는 덮어씀)한다; 빈 대괄호를 사용하는것과는 다르다.

key로 배열이나 객체를 사용할수 없다. 그렇게 하면 다음과 같은 경고가 발생할것이다: `Illegal offset type`.

### 대괄호 문법을 사용하여 생성/변경

그 안에 값을 명시적으로 표시함으로써 기존의 배열을 변경할수 있다.

이와 같은 일은 대괄호 안에 key를 표시함으로해서 배열에 값을 지정하여 수행한다. key를 빼먹을수도 있고, 그 경우에 변수명에 빈 대괄호("`[]`")를 추가한다.

    $arr[key] = value;
    $arr[] = value;
    // key may be an integer or string
    // value may be any value

`$arr`이 아직 존재하지 않으면, 생성될것이다. 그래서 이 방법이 배열을 표현하는 대안이 된다. 어떤 값을 변경하려면, 그 key로 표현되는 요소에 새로운 값을 지정한다. key/value 쌍을 제거하려면, 그것을 unset()할 필요가 있다.

`<?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 unset($arr); // This deletes the whole array ?>`

> 참고: 위에서 설명한바와 같이, key가 없는 대괄호를 사용한다면, 존재하는 정수 인덱스의 최대값이 취해질것이고, 새로운 key는 최대값의 + 1이 될것이다. 정수 인덱스가 아직 존재하지 않으면, key는 `0`(제로)가 될것이다. 이미 값을 보유하고 있는 key로 지정하면, 그 값은 덮어 씌어질것이다.

> 주의
> PHP 4.3.0에서는 위에서 설명한 인덱스 생성 동작이 변경되었다. 즉, 현재 최대 key가 음수인 배열에 추가동작이 발생하면, 다음 key는 제로 (`0`)가 될것이다. 전에는, 새로운 인덱스는 기존의 가장 큰 key + 1로 되었었다. 양수의 인덱스에는 같은 동작을 한다.

> 이 목적을 위한 최대 정수 key는 현재까지는 배열 안에 존재할 필요가 없다. 단순히 배열을 마지막으로 인덱스 한 이후 어떤 시간내에 배열 안에 존재해야 한다. 다음 예를 보면:

> `<?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 as you
> // might expect).
> $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
>     )

## 유용한 함수

배열을 위한 유용한 함수가 지원된다. 배열 함수 섹션을 볼것.

> 참고: unset()함수는 항상 배열의 key를 unset한다. 배열이 다시 인덱스되지 않을것이라는것에 주의한다. 오직 "가용한 정수 인덱스"를 사용한다면(제로에서 시작해서, 하나씩 증가), array_values()를 사용하여 재인덱싱 효과를 수행할수 있다.

> `<?php $a = array(1 => 'one', 2 => 'two', 3 => 'three'); unset($a[2]); /* will produce an array that would have been defined as $a = array(1 => 'one', 3 => 'three'); and NOT $a = array(1 => 'one', 2 =>'three'); */ $b = array_values($a); // Now b is array(0 => 'one', 1 =>'three') ?>`

foreach 제어 구조는 배열을 위해 특별히 지원되는것이다. 배열 안을 이동하는 가장 빠른 방법을 제공한다.

## 배열이 하는것과 하지 않는것

### 왜 `$foo[bar]`이 잘못인가?

항상 문자열 리터럴 배열 인덱스 주위에는 따옴표를 사용해야 한다. 예를 들면, $foo['bar']을 사용하고 $foo[bar]은 사용하지 말라. 그러나 왜 $foo[bar]이 잘못인가? 오래된 스크립트에서 다음 문법을 볼수 있을것이다:

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

이것은 잘못된것이지만, 동작하다. 그렇다면, 왜 잘못인가? 그 이유는 이 코드가 문자열('bar' - 따옴표 사용) 보다는 정의되지 않은 상수 (bar)를 갖는다는것이다. 그리고 PHP는 미래에 상수를 정의할수 있는데, 불운하게도 이 코드에서, 같은 이름을 갖을수도 있다. 이것은 잘 작동하는 이유는 PHP가 자동으로 bare string(알려진 심벌과 대응되지 않는 따옴표 없는 문자열)을 bare string을 포함하는 문자열로 변환하기 때문이다. `bar`라는 이름으로 정의된 상수가 없으면, PHP는 그것을 `'bar'`로 대치시켜서 사용할것이다.

> 참고: 위 말은 항상 key를 따옴표 처리하라는 것이 아니다. 상수나 변수가 PHP에서 해석되는것을 방지하기 위해 key에서 이들을 따옴표처리하지 않을수 있다.

> `<?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

위 사실을 설명하는 몇가지 예제 코드:

`<?php
// Let's show all errors
error_reporting(E_ALL);
$arr = array('fruit' => 'apple', 'veggie' => 'carrot');
// Correct
print $arr['fruit']; // apple
print $arr['veggie']; // carrot
// Incorrect. This works but also throws a PHP error of
// level E_NOTICE because of an undefined constant named fruit
//
// Notice: Use of undefined constant fruit - assumed 'fruit' in...
print $arr[fruit]; // apple
// Let's define a constant to demonstrate what's going on. We
// will assign value 'veggie' to a constant named fruit.
define('fruit', 'veggie');
// Notice the difference now
print $arr['fruit']; // apple
print $arr[fruit]; // carrot
// The following is okay as it's inside a string. Constants are not
// looked for within strings so no E_NOTICE error here
print "Hello $arr[fruit]"; // Hello apple
// With one exception, braces surrounding arrays within strings
// allows constants to be looked for
print "Hello {$arr[fruit]}"; // Hello carrot
print "Hello {$arr['fruit']}"; // Hello apple
// This will not work, results 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 autoglobals in strings as well
print "Hello $arr['fruit']";
print "Hello $_GET['foo']";
// Concatenation is another option
print "Hello " . $arr['fruit']; // Hello apple
?>`

`E_NOTICE` 레벨 에러(`E_ALL`로 설정) 를 보이기 위해 error_reporting()함수를 쓸때, 다음과 같은 에러를 보게 될것이다. 기본값으로, error_reporting은 그들을 보여주지 않는다.

문법 섹션에서 설명한대로, 대괄호('`[`' 과 '`]`') 사이에 표현식이 존재해야 한다. 이 말의 의미는 다음과 같은 코드를 쓸수 있다는 뜻이다:

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

배열 인덱스로 값을 돌려주는 함수를 사용하는 예를 보인다. 전에 `E_*`와 같은 것을 보았듯이, PHP는 상수들을 알고 있다.

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

첫번째 예의`bar`처럼, `E_ERROR`는 유효한 식별자라는것에 주의한다. 그러나 위 예는 다음과 같다:

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

왜냐하면 `E_ERROR`는 `1`과 같기때문이다 etc.

위 예에서 이미 설명했듯이, `$foo[bar]`은 작동하지만 잘못되었다. 이 코드는 작동한다. 왜냐하면 이 문법에서 `bar`는 상수 표현으로 인식될수도 있기 때문이다. 하지만, 이 경우에 `bar`란 이름을 갖는 상수는 존재하지 않는다. PHP는 문자그대로 `bar`를 표시했다고 인식해서 문자열 `"bar"`으로 보기 때문이다. 따옴표 쓰는것을 잊었다고 인식한다.

#### 그래서 그것이 왜 나쁜가?

미래의 어떤 시점에서, PHP 팀은 또다른 상수나 키워드를 추가할수도 있거나, 애플리케이션안에 또다른 상수를 사용할수도 있다. 그러면 이 경우에 어려움에 빠지게 된다. 예를 들면, `empty`와 `default`워드는 이런 이유로 사용할수 없다. 왜냐하면 그들은 특별한 예약 키워드이기 때문이다.

> 참고: 배반복하지만, 큰따옴표로 둘러싼 string안에서 `"$foo[bar]"`이 유효하도록 따옴표를 배열 인덱스에 둘러싸지 않는것이 유효한다. 그 이유에 대한 상세 설명을 위해 위 예제코드를 보는 것은 물론 문자열 안에서 해석되는 변수에 관한 섹션도 참고할것.

## 배열로 변환

다른 타입을 갖는: integer, float, string, boolean, resource, 어떤 값을 array로 변환한다면, 한개의 요소를 갖는 (인덱스 0) 배열을 얻을수 있다. 그 구성요소는 스칼라 값이다.

object를 배열로 변환하면, 각 객체의 속성(멤버 변수)를 배열의 구성요소로서 취할수 있다. key는 멤버 변수명이 된다.

`NULL`값을 배열로 변환하면, 빈 배열을 얻을수 있다.

## 비교하기

array_diff()와 배열 연산자를 사용하여 배열을 비교할 수 있습니다.

## 예제 코드

PHP에서 배열 타입은 다용도로 쓰인다. 그래서 여기서 배열의 완벽한 능력을 보이기 위해 몇가지 예제 코드를 보일것이다.

`<?php
// this
$a = array( 'color' => 'red',
'taste' => 'sweet',
'shape' => 'round',
'name' => 'apple',
4 // key will be 0
);
// is completely equivalent with
$a['color'] = 'red';
$a['taste'] = 'sweet';
$a['shape'] = 'round';
$a['name'] = 'apple';
$a[] = 4; // key will be 0
$b[] = 'a';
$b[] = 'b';
$b[] = 'c';
// will result in the array array(0 => 'a' , 1 => 'b' , 2 => 'c'),
// or simply array('a', 'b', 'c')
?>`

예 6-4. array() 사용하기

`<?php
// Array as (property-)map
$map = array( 'version' => 4,
'OS' => 'Linux',
'lang' => 'english',
'short_tags' => true
);
// strictly numerical keys
$array = array( 7,
8,
0,
156,
-10
);
// this is the same as array(0 => 7, 1 => 8, ...)
$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
);
// empty array
$empty = array();
?>`

예 6-5. 컬렉션

`<?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?

현재까지 배열의 값을 이런 루프 안에서 직접 변경하는 것은 불가능하다는 것에 주의해야 한다. 다음과 같은 편법이 있다:

예 6-6. 컬렉션

`<?php foreach ($colors as $key => $color) { // won't work: //$color = strtoupper($color); // works: $colors[$key] = strtoupper($color); } print_r($colors); ?>`

출력은:

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

이 예제 코드는 one-based 배열을 생성한다.

예 6-7. One-based index

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

출력은:

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

예 6-8. 배열 채우기

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

배열은 순서가 있다. 다양한 정력함수를 사용하여 그 순서를 변경할수도 있다. 더 자세한 정보는 배열 함수섹션을 참고. count()함수를 사용하여 배열 내의 아이템 수를 셀수 있다.

예 6-9. 배열 정렬하기

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

배열의 값은 어느것이든 될수 있기 때문에, 또한 다른 배열이 될수 있다. 이 방식으로 재귀적이고 다차원인 배열을 만들수 있다.

예 6-10. 재귀적이고 다차원인 배열

`<?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"
)
);
// 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";
?>`

배열 지정은 항상 값 복사에 관련되어 있다는 것을 알고 있어야 한다. 참조에 의해 배열을 복사하려면 참조 연산자를 사용하여야 한다.

`<?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 ?>`

이전 | 처음으로 | 다음
문자열 | 위로 | 객체