제 1 주 PHP 하십니까?
제 2 주 PHP를 이용한 개발기간의 단축
제 3 주 PHP와 오라클을 이용한 엔터프라이즈 애플리케이션 개발
제 4 주 PHP, 어른이 되다
제 5 주 오라클/PHP 환경의 확장
제 6 주 PHP 5 Data Object (PDO) Abstraction Layer와 오라클
제 7 주 PHP 5, 오라클, 그리고 미래

히치하이커를 위한 PHP 가이드①

PHP 하십니까?


Rasmus Lerdorf│PHP의 창시자, Yahoo! Inc. 인프라스트럭처 엔지니어

요즘 PHP의 인기가 대단합니다. 2004년 2월 [www.netcraft.com]의 조사결과에 의하면 전체 47,173,415 도메인 중 15,205,474 개 도메인이 PHP를 사용하고 있다고 합니다. 이는 전체 도메인 수의 32 퍼센트에 달하는 수치이며, 여전히 PHP의 인기는 가라앉을 조짐을 보이지 않고 있습니다.

PHP의 초기 개발 과정

필자는 지금으로부터 10년 전 PHP의 개발 작업을 시작했습니다. 당시만 해도 “오픈 소스”라는 용어는 만들어지지도 않았고, GPL과 Free Software의 개념이 대중에게 널리 알려지지도 않은 상태였습니다. 다른 오픈 소스 프로젝트의 성공 사례들이 그러하듯, PHP의 개발 동기 역시 결코 철학적이거나 자아도취적인 것이 아니었습니다. PHP는 실제 환경에서의 웹 관련 문제를 해결하기 위한 툴로써 개발되었습니다. 1994년만 해도 극히 제한적인 수의 웹 개발 툴만이 제공되고 있던 상황이었습니다. 필자는 당시 C 또는 Perl로 웹 사이트를 위한 다이내믹 컴포넌트를 개발하면서, 모듈 간의 코드의 중복 현상이 너무 심각하다는 사실을 발견했습니다. 필자는 성능적인 이유에서 Perl과 C의 사용을 자제하고 있었습니다. Perl을 스탠드얼론 CGI로 실행하는 과정에서의 fork+exec 오버헤드가 지나치게 심각했기 때문입니다.

최초의 PHP 비공개 버전은, 오픈 소스 프로젝트에서 재활용 가능한 C 함수들을 포함하는 C 라이브러리의 형태로 개발되었습니다. 필자는 HTML 파일의 태그를 식별한 후 백엔드 C 함수를 호출하는 단순한 형태의 “state-machine-driven” 파서(parser)를 개발하였습니다. 이 코드는 “Personal Home Page Tools”라는 이름의 패키지로 공개되었습니다. 패키지에 포함된 각각의 툴은 개인 홈 페이지 작성 과정의 일반적인 문제들을 해결하기 위한 사례로써 활용되었습니다. 나중에 필자는 패키지의 일부를 분리하여 FI(Form Interpreter)라는 이름으로 공개하게 됩니다. FI는 폼(form)이 제출되었을 때 수행되는 공통 작업을 구현하기 위한 툴입니다. FI 코드의 몇 가지 예가 아래와 같습니다:

<!--getenv HTTP_USER_AGENT--> <!--ifsubstr $exec_result Mozilla--> Hey, you are using Netscape!<p> <!--endif--> <!--sql database select * from table where user='$username'--> <!--ifless $numentries 1--> Sorry, that record does not exist<p> <!--endif exit--> Welcome <!--$user-->!<p> You have <!--$index:0--> credits left in your account.<p> <!--include /text/footer.html-->

필자가 FI에 구현한 파서는 형편없는 수준이었습니다. 때문에 보다 개선된 파서의 개발이 필요했습니다. 필자는 <!-- cmd --> 신택스 대신 <? cmd >신택스를 적용하고, Personal Home Page 코드의 일부를 FI 툴에 적용한 PHP/FI라는 이름의 패키지를 1995년에 공개했습니다. (PHP/FI라는 이름은 “TCP/IP”를 흉내 내어 지어본 것입니다.) 그 후 몇 년 동안 PHP/FI도 인터넷과 함께 성장했습니다. 1997년, 이스라엘의 Zeev Suraski와 Andi Gutmans가 필자에게 연락하여 자신들이 개발한 파싱 엔진을 새로운 PHP 버전에 적용할 생각이 없는지 물어 왔습니다. 나는 PHP/FI 패치/코드 제공자들과의 협력을 통해 PHP 버전 3를 완성하고 1998년 중반에 공개하였습니다. 당시는 PHP의 개발 역사에서 가장 중요한 전환점이었습니다. PHP가 단 한 사람에 의한 프로젝트로 남았다면, 또 서로 안면이 없는 사람들끼리 한데 모여 공동 목표를 위해 협력할 수 있는 방안이 마련되지 않았다면, PHP는 결코 성공할 수 없었을 것입니다. 2004년 상반기에 PHP 5.0이 발표될 때까지 코드 제공자의 수는 갈수록 늘어 갔습니다.

프로그래밍 언어의 “미운 오리 새끼"

PHP에 대한 대중의 평가는 크게 엇갈립니다. 언어 순수주의자들은 PHP에 포함된 많은 기능의 구현 수준이 불완전하고, 코드 일관성이 부족하다는 문제를 지적합니다. 반면, 실용주의자들은 PHP가 마치 자신들의 마음을 읽기라도 한 것처럼 웹 관련 문제를 완벽하게 해결해 준다고 말합니다.

순수주의자들은, PHP의 함수 이름이 대소문자를 구분하지 않는 반면 변수는 대소문자를 구분한다는 점, 내장 함수의 명명 방식에 일관성이 없다는 점, PHP 개발자들이 준수해야 하는 강제적인 언어 구조가 제공되지 않는다는 점 등을 지적하면서 난잡한 코드가 작성될 가능성이 높다고 비판합니다. 이러한 비판에 대해서는 필자로서도 반박할 수 없습니다. 하지만 PHP가 이러한 형태로 개발된 이유와 배경에 대해서는 설명할 수 있을 것입니다.

먼저, 함수 명의 대소문자 구분 문제에 대해 이야기해 보겠습니다: 이야기는 PHP의 최초 버전이 개발되던 시점으로 거슬러 올라갑니다. 웹 초기 시절에는 (당시만 해도 XHTML이 개발되기 훨씬 전이었습니다) HTML 마크업 태그를 대문자로 표기하는 것이 일반적이었습니다. 하지만 태그가 대소문자를 구분하지 않았기 때문에, 실제로 작성되는 방식은 제각각이었습니다. 필자는 PHP 태그가 다른 HTML 마크업 태그와 같은 특성을 갖기를 원했습니다. PHP 태그가 대소문자를 구분하지 않게 된 것은 이런 이유가 있었기 때문입니다. 이후 PHP가 발전하면서 변수가 활용되기 시작했습니다. 새로운 변수에 대소문자 구분 규칙을 추가하는 것은 하위 호환성 면에서 문제가 될 것이 없었습니다. 하지만 함수 호출의 용도로만 활용되는 기존의 PHP 태그에 새로운 규칙을 추가하게 되는 경우, 이전에 작성된 스크립트를 새로운 버전의 PHP에서 사용할 수 없게 된다는 문제가 있었습니다. 어차피 서로 다른 태그를 대소문자 만으로 구분하는 경우는 거의 없으니 큰 문제가 될 것이 없었습니다. 지금 돌이켜 본다면, PHP의 사용자가 많지 않던 초기에 하위 호환성을 무시하고 새로운 규칙을 적용하는 것이 옳았다고 판단하게 됩니다. 하지만 당시만 해도 PHP가 이만큼 성장하리라고 예상할 수 있는 사람은 아무도 없었습니다.

함수 표기의 경우, 다른 언어와 API로부터 아이디어를 빌려오는 방법을 사용했습니다. 굳이 PHP 함수에 strlen(), substr() 등의 이름 대신 str_len(), sub_str()과 같은 이름을 붙이는 것도 우스울 것입니다. stripslashes()와 같이 긴 이름을 갖는 함수의 경우, 가독성을 높이기 위해 StripSlashes()와 같이 표기하기도 했습니다. 또 msql_connect()의 경우 로우 레벨 데이타베이스 API의 표기법을 그대로 차용하여 소문자로 표기했습니다 (miniSQL은 PHP가 최초로 지원한 데이타베이스입니다). 이러한 소스에 이미 친숙한 사용자들은 PHP의 표기 방식에 만족스러운 반응을 보였습니다. PHP는 독립적인 언어라기 보다는, 웹 서버와 백엔드 툴 간의 인터페이스의 성격이 강했습니다. PHP를 독립적인 언어로 인식하게 된 오늘날, PHP의 일관성이 부분적으로 결여되어 있는 것처럼 보이는 것은 이러한 이유가 있었기 때문입니다.

다음으로 프로그래밍 구조에 대한 규칙이 존재하지 않는다는 지적에 대해서 이야기해 보겠습니다. 필자는 개인적으로, 특정한 문제 해결 방식만을 강요하는 프로그래밍 프레임워크에 대해 매우 부정적인 시각을 갖고 있습니다. 필자가 구조와 프레임워크의 중요성을 무시한다는 것이 아니라, 개발자들이 자신의 환경에 가장 적합한 방법을 직접 선택할 수 있어야 한다는 의미입니다. 이 문제에 대해서는 PHP 프로젝트에 적용 가능한 아키텍처에 대해 논의하면서 다시 언급하기로 하겠습니다.

PHP는 “미인 대회”에 참가할 목적으로 만들어진 언어가 아닙니다. 또 프로그래밍 패러다임의 혁신을 의도한 것도 아니었습니다. PHP는 단 한 가지 문제, 즉 웹 개발을 지원하기 위해 설계된 언어입니다. “지저분한” 문제는 “지저분한” 툴로 해결하는 것이 좋을 수 있습니다. 좀 더 “단정한” 툴로도 같은 문제를 해결할 수는 있겠지만, “지저분한” 툴을 사용하는 경우 보다 적은 리소스로 보다 신속하게 해결할 가능성이 높아집니다. PHP가 오랜 세월 동안 “형식보다 기능이 우선"이라는 원칙을 고집스럽게 지켜온 이유는 여기에 있습니다.

프로그램 설계를 위한 조언

PHP는 “preforking multiprocess” 환경을 지원하는 Apache 1.3.x 웹 서버에 직접 연결하는 방법으로 가장 많이 활용되고 있습니다. PHP는 Java와 달리 JVM과 같은 스탠드얼론 프로세스를 제공하지 않습니다. PHP는 스크립트의 파싱 및 실행 작업을 직접 수행한다는 점에서 Perl, Python과 같은 스크립팅 언어와 유사합니다.

PHP에서 중앙집중적인 컨트롤 프로세스가 제공되지 않는다는 사실은 경우에 따라 장점이 될 수도 있고 단점이 될 수도 있습니다. PHP의 “shared-nothing” 아키텍처에서 각 요청은 다른 요청과 완전히 독립적으로 처리되므로, 무한한 수평적 확장성의 구현이 가능합니다. PHP로 구현된 환경을 확장하는 것은 매우 쉽습니다. 공유 데이타 저장소가 필요한 경우라면, 데이타베이스 복제 환경을 이용하여 그 규모를 필요한 만큼 확장할 수 있습니다. 로드 밸런싱 환경을 구현하거나 서버의 요청 사항을 다른 서버에 배포해야 하는 경우라면, 프론트 엔드 밸런스를 적용하면 됩니다. 중앙집중적인 컨트롤 프로세스가 없다는 것은, 시스템 병목 요소가 존재하지 않는다는 의미로 해석될 수도 있습니다. PHP와 일반적인 “애플리케이션 서버”의 가장 중요한 차이점은 여기에 있다고 할 수 있습니다.


[oarch1.png] 하이엔드 PHP 환경을 위한 아키텍쳐

위 다이어그램에서는 외부 요청이 로드 밸런싱 장비를 통해 다수의 웹 서버로 전달되고 있습니다. 데이타 저장소의 경우, 읽기 전용 데이타베이스 복제본을 각 웹 서버에 저장하는 형태로 구현하는 것도 가능합니다. 또는 다양한 요청을 처리하기 위해 용도별로 여러 개의 데이타베이스를 생성할 수도 있습니다.

PHP 코드의 구조화

웹 문제를 해결하기 위한 툴은 PHP 말고도 여러 가지가 있습니다. 다른 툴의 경우 매우 제한적인 문제만을 해결하며, 문제 해결 과정에서 사용자에게 구조적인 접근 방식을 강요하는 경향을 보입니다. PHP가 다른 툴과 비교했을 때 갖는 장점 중 하나는, PHP의 경우 개발자에게 어떠한 구조도 강요하지 않으며, 각각의 기능을 구현하기 위한 가장 쉬운 접근법을 선택할 수 있게 한다는 사실입니다. 한 예로, PHP는 백엔드 데이타베이스와의 커뮤니케이션을 위한 함수를 제공하고 있습니다. PHP의 데이타베이스 연결 함수는 각 데이타베이스 제품 별로 독립적으로 구현됩니다. PHP는 다른 백엔드 데이타베이스와의 코드 공유 또는 일관성을 위해 성능을 희생하는 접근법을 선택하지 않습니다. 파일 레이아웃의 측면에서도 개발자가 PHP 애플리케이션의 구조를 자유롭게 선택할 수 있게 하였습니다..

PHP가 특정 구조를 강요하지 않는다고 해서, PHP 애플리케이션을 개발할 때 구조적인 접근법을 사용하지 않아도 된다는 것은 아닙니다. 대규모 PHP 애플리케이션을 구조화하는 방법에 대해 개발자들이 문의해 올 때, 필자가 추천하는 방법 중 하나가 아래와 같습니다.

+--------------------------------+ | HTML TEMPLATES | | $DOC_ROOT/*.php | +--------------------------------+ | TEMPLATE HELPERS | | $DOC_ROOT/*.inc | +--------------------------------+ | BUSINESS LOGIC | | /usr/local/php/*.inc | +--------------------------------+ | C/C++ CORE CODE | | /usr/local/lib/php/*.so | +--------------------------------+

위의 4계층 접근법에는 여러 가지 장점이 있습니다. 먼저, 프로젝트의 각 담당자 업무를 기준으로 한 컨텐트의 구분이 가능합니다. 웹 프론트-엔드 개발자는 탑다운(top-down) 방식으로, 백엔드 엔지니어는 바텀업(bottom-up) 방식으로 작업을 수행하게 되며, 각 담당자의 업무는 “template helpers” 계층에서만 다소 중복됩니다. 또 HTML 파일은 document_root에, HTML을 포함하지 않는 파일은 document_root 외부에 저장함으로써, HTML을 포함하는 컨텐트를 별도로 관리할 수 있습니다.

최상위 “HTML template” 계층의 경우, 간단한 함수 호출 및 include 문을 제외하고는 PHP 코드가 거의 사용되지 않습니다. 일반적으로 이 계층의 파일은 HTML 편집 툴을 이용해 편집합니다. 두 번째로 “template helpers” 계층에서는 비즈니스 로직 간의 인터페이스와 레이아웃이 정의됩니다. 이 계층에서는 start_table(), show_user_record()과 같은 함수가 사용되며, 템플릿 개발자의 작업 편의성을 도모하기 위한 코드가 구현됩니다.

“business-logic” 계층은 HTML 코드를 전혀 포함하지 않습니다. 이 계층에서는 SQL 쿼리, 또는 사용자가 개발한 PHP 비즈니스 로직 코드가 구현됩니다. 이 계층에서 사용되는 함수의 예로 get_user_record()를 들 수 있습니다. 이 함수는 ID를 매개변수로 하는 SQL 쿼리를 수행하고, 실행 결과를 어레이의 형태로 반환합니다. 이렇게 반환된 결과는 다른 함수에 의해 HTML 태그가 추가된 형태로 디스플레이 됩니다.

마지막 “C/C++” 계층에서는 프로젝트에 관련된 커스텀 백엔드 코드를 구현합니다. 이 계층이 전혀 사용되지 않는 경우도 많습니다. 하지만 C/C++ 라이브러리를 활용해야 하는 경우라면, 라이브러리와의 인터페이스를 위한 PHP extension를 이 계층에서 구현할 수 있습니다. PHP 코드로 작성한 비즈니스 로직 함수의 실행 속도가 너무 느린 경우에도 이 계층을 이용할 수 있을 것입니다.

PHP 개발자의 채용 및 교육에 관해

PHP는 새로운 언어가 아닙니다. 새로운 개념이 사용되지도 않았습니다. 따라서 C, C++, Perl, Java에 친숙한 개발자라면 누구나 PHP를 쉽게 배울 수 있습니다. 필자는 PHP 개발자를 뽑을 때, 지원자의 PHP 지식보다는 C/C++ 스킬을 중점적으로 평가합니다. PHP에 대해 알고 있는 사람보다는 프로그램 경험이 풍부한 개발자가 더 도움이 되기 때문입니다. C 또는C++을 다룰 수 있는 개발자라면, PHP를 배우는 것은 식은 죽 먹기입니다. 물론 두 가지 언어에 모두 경험이 있다면 더할 나위가 없을 것입니다.

목적에 맞게 활용하자

요구사항에 적합한 툴을 선택하는 것도 중요합니다. 필자가 경험한 기업들 중 일부는, PHP를 과신한 나머지 모든 환경에 천편일률적으로 PHP를 적용하고 있었습니다. PHP는 모든 문제를 해결할 수 있는 범용적인 언어가 아니며, 웹 환경을 위한 프론트엔드 스크립팅 언어로써 활용될 때 그 유용성이 극대화됩니다. 웹 사이트의 트래픽이 그리 많지 않다면, 백엔드 환경의 대부분을 PHP로 구현할 수도 있을 것입니다. 하지만 최적의 성능을 보장하려면 C, C++과 같은 컴파일 언어를 부분적으로 활용할 필요가 있습니다.

PHP의 미래?

사람들은 필자에게 PHP가 향후 어떤 방향으로 발전되어 갈 것인지 묻곤 합니다.
이것은 답변하기 무척 어려운 문제입니다. 오픈 소스 프로젝트인 PHP는 현시대의 개발자 커뮤니티 요구사항을 반영하는 형태로 진화하고 있습니다. PHP5에서는 OO 기능과 XML 통합 기능이 크게 개선되었습니다. 또 SQL-Lite 툴과의 통합이 이루어졌습니다. (SQL-Lite는 별도의 서버 없이도 파일에 대한 직접적인 SQL 인터페이스를 지원하는 유용한 툴입니다. 이 툴이 관계형 데이타베이스를 대신하기에는 부족한 점이 있지만, 개발자가 직접 인터페이스를 구현하는 것에 비해서는 훨씬 효율적입니다. 또, 제공되는 SQL 인터페이스를 활용하는 경우 향후의 데이타베이스 마이그레이션 작업이 한층 용이해진다는 장점이 있습니다.)

PHP5는 매우 주목할만한 신기능을 포함하고 있지만, 그 변화는 “혁신적”이라기보다는 “진화적”인 형태로 나타나고 있습니다. 우리는 PHP의 세계를 근본적으로 혁신하려 의도하지 않습니다. PHP4로 작성된 코드의 99%는 PHP5 환경에서도 동작합니다. PHP5의 가장 큰 변화로 오브젝트의 처리 방식을 지적할 수 있습니다. PHP5에서 오브젝트를 “new” 처리하는 경우, 별도의 구문 없이도 해당 오브젝트를 전달할 수 있는 레퍼런스(reference)가 기본적으로 제공됩니다 (PHP4에서 해당 오브젝트를 전달하려면 명시적으로 “pass by reference” 방식을 사용해야만 했습니다). 또 PHP5에서 오브젝트의 복제본이 필요한 경우 “clone” 기능을 활용할 수 있습니다.

장기적인 관점에서 볼 때, Parrot 엔진의 활용도가 높아지게 될 것입니다. Parrot은 Perl6를 위한 엔진으로 작성되었지만, 언어중립적인 범용 스크립트 엔진의 성격을 갖고 있습니다. 다양한 스크립팅 언어가 Parrot과 같은 백엔드 엔진을 공유하게 된다면 정말 흥미로울 것입니다. 이 엔진을 기반으로 공통 extension을 개발하고, 언어 간의 통합 수준을 개선할 수 있을 것입니다.

또 일부 개발자들은 JSR 223을 이용한 Java 연결의 가능성을 탐구하고 있습니다. Java 역시 스크립팅 언어를 위한 유니버설 백엔드 엔진으로 활용될 가능성이 있습니다.

PHP의 미래를 예측하기는 어렵지만, 한 가지만큼은 앞으로도 변하지 않을 것입니다. 우리는 많은 개발자들이 중독되어 있는 “복잡성”의 문제와 계속적으로 투쟁해 갈 것입니다. 가장 복잡한 솔루션이 가장 적합한 해결책은 아닙니다. 웹 문제에 대한 우리의 접근법은 PHP가 처음 개발되던 시점과 비교하여 달라지지 않았습니다. 다른 솔루션이 점점 더 그 규모를 키우고 복잡도를 더해 가는 동안에도, 우리는 PHP를 단순화, 효율화하기 위한 노력을 계속해 갈 것입니다.

제공 : DB포탈사이트 DBguide.net

+ Recent posts