티스토리 뷰



프로그래밍 과정에서 배열만큼 많이 활용되고 편리한 데이터 구조체는 없을 것입니다. 배열은 모든 원소의 데이터 타입이 동일한 데이터 집합으로 정의할 수 있으며 인덱스에 의해서 각 원소를 접근할 수 있습니다. PHP에서는 좀더 유연한 형태의 배열을 다룰 수 있으며 스트링과 같은 기본 타입 뿐만아니라 복잡한 클래스 오브젝트도 배열의 원소로 사용할 수 있습니다.

그런데, 배열을 사용하다보면 편리하기는 하지만 배열은 PHP 환경 파일에서 설정한 메모리 허용 용량 내에서만 사용할 수 있기 때문에 파일 용량이 크거나 배열 크기가 커지는 경우에는 프로그램이 메모리 한계에 부딛혀 비정상 종료되는 상황이 벌어질 수 있습니다.


그래서 대용량 배열을 메모리에 저장하지 않고 디스크에 저장해서 용량의 크기에 관계없이 정상적인 프로그램 동작을 수행할 수 있도록 한 것입니다. 파일에 저장하기 전에는 클래스 오브젝트를 serialize 함수를 사용해서 스트링으로 변환하고 반대로 디스크에 있는 배열의 개별 원소에 접근할 때는 파일에서 읽은 스트링은 unserialize 함수를 사용해서 클래스로 전환시켜주는 것입니다. 

$biblios = array();
foreach($records as $record) {
    $biblio = new Biblio();
    //......
    array_push($biblios, $biblio);
}
//......
foreach ($biblios as $biblio) {
    foreach ($biblio->getBiblioFields() as $field) {
        echo ''.H($field->getTag()).'';
        //......
    }
}

위의 코드 예제는 메모리 배열을 사용하는 예제입니다. $biblios라는 배열에 Biblio 클래스 오브젝트를 array_push라는 PHP 함수를 사용해서 추가하고 이후에 $biblios 배열에 있는 내용에서 하나씩 끄집어 내어 작업을 수행하는 로직입니다. 메모리 한계에 도달하면 클래스 오브젝트를 만드는 과정이나 배열에 집어넣는 과정에서 비정상 종료됩니다. 이런 한계를 파일과 serialize/unserialize 함수를 사용해서 변경한 코드는 아래와 같습니다.

$bibfp = tmpfile();
foreach($records as $record) {
    $biblio = new Biblio();
    //......
    fputs($bibfp, serialize($biblio)."\n");
}
//......
fseek($bibfp, 0, SEEK_SET);
while (($readrec = fgets($bibfp))!==FALSE) {
    $biblio = unserialize($readrec);
    foreach ($biblio->getBiblioFields() as $field) {
        echo ''.H($field->getTag()).'';
        //......
    }
}
fclose($bibfp);

tmpfile()함수는 PHP 내장 함수로 임시 파일을 생성하여 그 파일 핸들을 리턴합니다. 특정 파일에 대해서 fopen()함수를 호출한 것과 동일한 기능을 발휘합니다. 차이점이라면 tmpfile()함수로 생성한 임시파일은 fclose() 함수로 파일 핸들을 닫으면 파일이 자동 삭제 된다는 점입니다. 만약 웹 서버에 접근할 때 마다 사용하는 구조체나 클래스 데이터를 재사용할 필요가 있거나 캐싱으로 속도를 향상시키고 싶다면 임시 파일 대신에 임의의 일반 파일이나 캐시에 대해서 유사한 기술을 활용할 수 있을 것입니다.

fseek()함수를 중간에 사용한 이유는 파일 포인터를 파일의 처음으로 이동시키기 위한 것으로 위의 예제에서는 배열을 모든 원소를 fputs/fgets 함수로 차례대로 저장하고 차례대로 읽었지만 각 원소의 크기를 동일하게 fwrite로 저장하고 fseek()함수로 원소의 인덱스에 해당하는 파일 위치를 지정하여 쓰기/읽기 하여 파일에 대해서도 메모리와 동일하게 인덱싱으로 배열 원소에 접근할 수 있습니다. 위의 예제에서는 각 클래스 오브젝트에 개행 문자("\n")를 붙여 라인단위로 읽을 수 있도록 했습니다.

serialize/unserialize 함수는 PHP의 어떠한 데이터에도 적용할 수 있습니다.


댓글
댓글쓰기 폼
«   2022/11   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함