You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
네임스페이스, 트레이트, 클로저부터 모범 사례와 최신 도구까지<br />
<strong>Modern</strong><br />
<strong>PHP</strong><br />
조시 록하트 지음<br />
정병열 옮김
www.hanbit.co.kr<br />
이것이<br />
프로그래밍이다!<br />
저자 직강 동영상 제공!<br />
이것이 안드로이드다<br />
이것이 C언어다<br />
이것이 자바다<br />
진정한 안드로이드 개발자로<br />
이끌어줍니다.<br />
SDK 5.0 롤리팝 호환!<br />
책만 보고,<br />
동영상 강좌로도 만족하지 못했다면 Daum<br />
카페 '슈퍼드로이드'에서 만나요<br />
cafe.daum.net/superdroid<br />
박성근 저 | 1,164쪽 | 45,000원<br />
세상에 없던 새로운<br />
C언어 입문서 탄생!<br />
삼성, LG에서 펼쳐졌던<br />
전설의 명강의를 풀타임 동영상 강좌로!<br />
이보다 더 확실한 방법은 없다, 칠판강의<br />
전체 동영상 강좌 유투브 전격 공개!<br />
http://goo.gl/tJK3Tu<br />
서현우 저 | 708쪽 | 25,000원<br />
가장 중요한 프로그래밍 언어를 하나<br />
배워야 한다면, 결론은 자바다!<br />
중급 개발자로 나아가기 위한 람다식,<br />
JavaFX, NIO 수록<br />
자바의 모든 것을 알려주는 인터넷 강의<br />
궁금한 것은 카페에서!<br />
cafe.naver.com/thisisjava<br />
신용권 저 | 1,224쪽 | 30,000원
www.hanbit.co.kr<br />
지금은<br />
모던 웹 시대!<br />
모던 웹 디자인을 위한<br />
HTML5 +<br />
CSS3 입문<br />
모던 웹을 위한<br />
JavaScript +<br />
jQuery 입문<br />
HTML5 분야 부동의 1위 도서<br />
HTML5 표준안 확정에 맞춘 완전 개정판의 귀환!<br />
HTML5 권고안과 최신 웹 브라우저 환경 대응<br />
윤인성 저 | 624쪽 | 30,000원<br />
자바스크립트에서 제이쿼리, 제이쿼리 모바일까지<br />
한 권으로 끝낸다!<br />
시대의 흐름에 맞춰 다시 쓴 자바스크립트 교과서<br />
윤인성 저 | 980쪽 | 32,000원<br />
모던 웹을 위한<br />
Node.js<br />
프로그래밍<br />
HTML5 +<br />
CSS3 정복<br />
페이스북, 월마트, 링크드인은 왜<br />
Node.js를 선택했는가?<br />
이 물음에 대한 답은 Node.js가 보여주는 빠른 처리 능력 때문이다.<br />
윤인성 저 | 484쪽 | 25,000원<br />
필요한 것만 배워<br />
바로 현장에서 쓰는 HTML5<br />
순서대로 읽으며 실습할 수 있는 HTML5 자습서<br />
김상형 저 | 700쪽 | 32,000원
| 표지 설명 |<br />
표지 동물은 호주검은머리따오기(학명: Threskiornis spinicollis)다. 오스트레일리아, 뉴기니,<br />
인도네시아 일부 지역에 서식한다.<br />
호주검은머리따오기는 75cm까지 자라는 대형 조류다. 성체의 목에 나타나는 독특하고 뻣뻣한 깃<br />
털에서 밀짚따오기 straw-necked ibisz 라는 영문명이 유래됐으며, 길고 구부러진 부리로 물속에서 곤충,<br />
연체 동물, 개구리 등을 잡아낼 수 있다. 경작지에서는 농작물에 해를 입힐 수 있는 벌레나 메뚜<br />
기, 귀뚜라미 등을 잡아먹기 때문에 농부들이 반기는 새다.<br />
이 새는 떠돌이 생활을 하며 무리를 지어 서식지를 옮겨 다니는데, 얕은 담수성 습지나 인공적으<br />
로 경작된 목초지, 늪지와 산호 지대의 가장자리를 좋아한다. 번식기에는 나뭇가지나 갈대를 모<br />
아 물가의 나무 위에 큰 컵 모양으로 둥지를 틀며 종종 호주흰따오기와 함께 둥지 군집을 이룬다고 알려져 있다. 이런 습성 탓<br />
에, 앙상한 나무의 높은 가지에 서서 하늘을 배경으로 뚜렷한 실루엣을 남기는 장면을 쉽게 목격할 수 있다.<br />
오라일리 책 표지에 등장하는 동물은 대부분 멸종 위기에 처해있으며 모두 세계적으로 중요한 가치를 지닌다. 이들을 돕는 방<br />
법을 알아보려면 http://animals.oreilly.com에 방문하기 바란다.<br />
표지 그림은 『Woods Illustrated Natural History』 에서 가져왔다.<br />
<strong>Modern</strong> <strong>PHP</strong> :<br />
네임스페이스, 트레이트, 클로저부터 모범 사례와 최신 도구까지<br />
초판발행 2015년 10월 20일<br />
지은이 조시 록하트 / 옮긴이 정병열 / 펴낸이 김태헌<br />
펴낸곳 한빛미디어 (주) / 주소 서울시 마포구 양화로 7길 83 한빛미디어(주) IT출판부<br />
전화 02 – 325 – 5544 / 팩스 02 – 336 – 7124<br />
등록 1999년 6월 24일 제10 – 1779호 / ISBN 978 – 89 – 6848 – 225 – 0 93000<br />
총괄 배용석 / 책임편집 최현우 / 기획 이복연, 강은희 / 편집 홍원규<br />
디자인 강은영<br />
영업 김형진, 김진불, 조유미 / 마케팅 박상용, 송경석, 서은옥 / 제작 박성우<br />
이 책에 대한 의견이나 오탈자 및 잘못된 내용에 대한 수정 정보는 한빛미디어(주)의 홈페이지나 아래 이메일로<br />
알려주십시오. 잘못된 책은 구입하신 서점에서 교환해 드립니다. 책값은 뒤표지에 표시되어 있습니다.<br />
한빛미디어 홈페이지 www.hanbit.co.kr / 이메일 ask@hanbit.co.kr<br />
Published by HANBIT Media, Inc. Printed in Korea<br />
Copyright © 2015 O’Reilly Media & HANBIT Media, Inc. Authorized translation of the English<br />
edition of <strong>Modern</strong> <strong>PHP</strong> ISBN: 9781491905012 © 2015 Josh Lockhart. This translation is to be<br />
published and sold by permission of O’Reilly Media, Inc., the owner of all rights to publish and sell<br />
the same.<br />
이 책의 저작권은 오라일리와 한빛미디어 (주)에 있습니다.<br />
저작권법에 의해 보호를 받는 저작물이므로 무단 복제 및 무단 전재를 금합니다.<br />
지금 하지 않으면 할 수 없는 일이 있습니다.<br />
책으로 펴내고 싶은 아이디어나 원고를 메일 ( writer@hanbit.co.kr ) 로 보내주세요.<br />
한빛미디어(주)는 여러분의 소중한 경험과 지식을 기다리고 있습니다.
로럴을 위해
옮긴이의 글<br />
처음으로 실무에 <strong>PHP</strong>를 사용했던 때는 2002년이었다. 한 중소 규모의 웹 서비스 개발을 맡았<br />
을 때였는데, 처음에는 서블릿으로 개발할 계획이었지만 몇 가지 이유로 최종 기획 단계에서<br />
<strong>PHP</strong>로 결정됐다. 사이트 전체를 <strong>PHP</strong>로 개발하는 일은 처음이었던지라 우려도 있었지만 막상<br />
작업해보니 Perl CGI나 서블릿을 사용하는 것보다 쉽고 빠르게 사이트를 구축할 수 있어 새삼<br />
놀랐던 기억이 난다. <strong>PHP</strong>의 풍부한 내장 라이브러리와 유연한 출력 제어 능력 덕분이었다.<br />
아닌 게 아니라 그즈음 우리나라에서는 이미 <strong>PHP</strong>가 빠른 속도로 자리를 잡아가고 있었다. 개<br />
발 언어로서뿐만 아니라 호스팅 업체들이 주력으로 지원하는 언어로서도 각광받았다. 단기간<br />
동안 호스팅 서비스 거의 대부분에 <strong>PHP</strong>가 탑재됐고 한쪽에서는 다양한 <strong>PHP</strong> 웹 애플리케이션<br />
들이 제작되고 공개됐다. 자생적으로 형성된 국내 커뮤니티 웹 사이트가 대부분 이런 <strong>PHP</strong> 웹<br />
프로그램들을 이용해 구축됐다. 이 시기에 큰 인기를 끌었던 PuryBBS, 제로보드4 등은 이후<br />
에 나온 테터툴즈나 XE 같은 걸출한 프로젝트의 모태이기도 하다. 이런 면에서 보자면 우리나<br />
라에서 <strong>PHP</strong>가 저변을 확대하는 과정은 국내 인터넷 문화의 폭발적 확장 과정과 어느 정도 궤<br />
를 같이 한다고도 볼 수 있다.<br />
<strong>PHP</strong> 같은 고참 스크립트 언어가 아직까지 각종 통계나 인기 순위에서 상위권을 차지하는 데<br />
에는 이유가 있다. 나는 <strong>PHP</strong>가 지닌 매력의 본질이 자유로운 포용력이라고 생각한다. <strong>PHP</strong>는<br />
끊임없이 언어 구조를 개선하고 유수의 라이브러리들을 통합하는 한편 스크립트 언어의 태생<br />
적 한계를 극복하려는 시도도 멈추지 않았다. <strong>PHP</strong> 진영은 늘 다양한 프로젝트로 북적거리는<br />
활기찬 분위기를 이어왔다. 여기에 수많은 개발자들의 활발한 참여가 더해져 <strong>PHP</strong> 개발 생태<br />
계는 나날이 성숙해지고 있다. 특히 최근 몇 년간 <strong>PHP</strong>는 탄생 이후 가장 역동적인 변화의 시<br />
기를 겪고 있다고 해도 과언이 아니다. 페이스북과 Hack으로 대변되는 외적 요인을 촉매로 언<br />
어 자체의 근간부터 재정립되고 있으며, 그 결과 <strong>PHP</strong> 7이라는 또 한번의 큰 도약을 목전에 두<br />
고 있다.<br />
국내에서는 <strong>PHP</strong>가 대형 솔루션을 개발하기에 적합하지 않다거나 보안에 취약한 언어라고 생<br />
각하는 이들도 있다. 역설적이게도 이런 부정적인 인식은 <strong>PHP</strong>가 지닌 강점에 기인한다. 입문<br />
10
하기 쉽고 빠르게 개발할 수 있어 단기간에 많은 프로젝트에 도입됐지만 그에 반해 엔터프라이<br />
즈급 솔루션 개발에 사용되거나 다양한 고도화 작업에 심도있게 활용된 사례가 드물기 때문이<br />
다. 스크립트 언어의 특성상 소스코드가 공개되어 있다는 점도 기피 사유 중 하나였으며 국내<br />
SI 프로젝트에 채택되는 플랫폼 구성이 다소 획일적이라는 실정도 한 몫 거들었다. 그러나 이<br />
런 인식과는 달리 현재 <strong>PHP</strong>는 방대한 솔루션을 많은 개발자가 공동으로 작업할 수 있는 제반<br />
환경을 충분히 갖추고 있다. 의존성과 패키징에 대한 표준이 정립됐으며 이들을 관리할 수 있<br />
는 우수한 도구가 등장했고, 지속적인 통합과 자동화된 테스팅 또한 가능해졌다. 뿐만 아니라<br />
완성도 높은 풀스택 프레임워크와 ORM, 강력한 템플릿 엔진들이 포진하고 있으며 셀 수 없이<br />
많은 오픈소스 컴포넌트를 자유롭게 활용할 수 있다.<br />
<strong>PHP</strong>의 기술적인 최신 동향과 그에 따른 모범 사례들에 대한 정보를 <strong>PHP</strong> 초심자나 다른 언어<br />
개발자가 일목요연하게 열람하거나 편리하게 접할 수 있는 창구는 흔치 않다. 몇몇 선도적인<br />
개발자들의 세미나와 블로그 기고만으로는 역부족이다. 특히나 최근 국내에는 <strong>PHP</strong> 관련 서적<br />
들의 출간도 주춤한 편이어서 아쉬움이 더해가는 상황이었다. 『<strong>Modern</strong> <strong>PHP</strong>』 는 이런 시점에<br />
서 만난 가뭄의 단비 같은 책이다.<br />
이 책은 ‘모던 <strong>PHP</strong>’라는 제목 그대로 <strong>PHP</strong> 언어의 최신 핵심 기능을 요점정리해줄 뿐만 아니<br />
라 유머러스하고 친절한 설명과 이해하기 쉬운 예제를 통해 모범 사례와 발전된 개발 방법까지<br />
제시해주는 실용서다. 저자인 조시 록하트는 유력 프레임워크의 개발자인 동시에 <strong>PHP</strong>에 대한<br />
인식 제고를 위해 발벗고 나선 오피니언 리더로서, <strong>PHP</strong>에 대한 자신의 애정과 열정을 이 책에<br />
고스란히 담아 놓았다. 또한 <strong>PHP</strong> 진영의 전반적인 근황에 대해 넓은 시각으로 잘 설명하고 있<br />
어서 앞으로 공개될 <strong>PHP</strong> 7을 준비하는 데 있어서도 도움이 될만한 책이다.<br />
<strong>PHP</strong>의 미래는 여전히 활짝 열려있고 잠재력 역시 무궁무진하다. 모쪼록 국내의 개발자들도<br />
<strong>PHP</strong>의 짜릿한 변화의 순간에 기꺼이 동참하고 진보된 <strong>PHP</strong>를 온전히 활용할 수 있게 되기를<br />
바라며, 그 과정에 이 책이 조금이나마 보탬이 될 수 있었으면 한다.<br />
이 책이 나오기까지 도움을 주신 분들에게 진심으로 감사의 마음을 전하고 싶다. 먼저, 처음 번<br />
11
역 의사를 전달했을 때 선뜻 기회를 제공해 준 한빛미디어 측에 감사드린다. 강은희 님과 최현<br />
우 팀장님이 원고의 미숙한 부분을 명확히 짚어주고 적절한 가이드 라인을 제시해 준 덕분에<br />
무사히 작업을 마무리할 수 있었다. 막히는 부분이 있을 때는 종종 주변에 도움을 구했다. 그<br />
때마다 매번 새로운 시각과 다양한 아이디어로 생각의 물꼬를 틔워준 김재영 님에게도 감사드<br />
린다. 마지막으로, 언제나 나를 지지하고 응원해주시는 부모님께 감사의 말씀을 드린다.<br />
_2015년 10월 정병열<br />
옮긴이 정병열 cloudshadow@gmail.com<br />
연세대학교 세라믹 공학과를 졸업하고 개발자와 번역자로 활동하고 있다. 어린 시절 BASIC 언어를 통해 프로그래밍을 처음 경험<br />
했으며 PC통신 시절에는 프로그래밍 관련 동호회에서 활동했다. 2000년대 초반부터 프로그래밍 언어와 플랫폼에 관계없이 다양<br />
한 웹 사이트 및 솔루션 개발 프로젝트를 수행했으며 몇 년간은 리눅스 시스템 엔지니어로 근무하기도 했다. 분야를 가리지 않는 폭<br />
넓은 관심사를 가지고 있으며 흥미를 느끼면 어떻게든 파고들어 습득하고 마는 성격의 소유자다. 현재는 취업포털 업체에서 다양한<br />
업무를 수행하고 있다.<br />
12
들어가며<br />
온라인에는 수없이 많은 <strong>PHP</strong> 튜토리얼이 있다. 이들 대부분은 이미 낡고 쓸모 없어진 지 오래<br />
지만 불행히도 구글 검색 결과에 살아남아 여전히 참조자료로 활용된다. 이런 낡은 정보를 무<br />
분별하게 받아들인 <strong>PHP</strong> 프로그래머는 자신도 모르는 사이에 느리고 보안에 취약한 <strong>PHP</strong> 애플<br />
리케이션을 만들게 될 위험에 처한다. 나는 2013년에 이러한 문제를 인식했고, 그때 가졌던 문<br />
제의식은 <strong>PHP</strong> The Right Way(http://www.phptherightway.com )를 시작하는 가장 큰 계기<br />
가 됐다. <strong>PHP</strong> The Right Way는 <strong>PHP</strong> 프로그래머가 <strong>PHP</strong> 커뮤니티 권위자들이 제공하는 품<br />
질 높은 최신 정보에 쉽게 접근할 수 있게 하려고 만든 것이다.<br />
『<strong>Modern</strong> <strong>PHP</strong>』는 이와 같은 목표를 지향하는 나의 다음 시도다. 이 책은 참고서가 절대 아니<br />
며 여러분과 내가 친근하고 재미있게 나눈 대화를 담은 기록과도 같다. 나는 최신 <strong>PHP</strong> 프로<br />
그래밍 언어를 소개하는 한편, 나의 오픈소스 프로젝트와 일상 업무에서 매일 사용하는 최신<br />
<strong>PHP</strong> 기술을 보여줄 것이다. 그리고 여러분이 최신 코딩 표준을 사용하여 자신의 컴포넌트와<br />
라이브러리들을 <strong>PHP</strong> 커뮤니티에서 공유할 수 있도록 도울 것이다.<br />
‘커뮤니티’라는 말이 되풀이되어 나올 것이다. 가끔 극적인 사건이 있긴 해도 <strong>PHP</strong> 커뮤니티는<br />
대체로 프로그래머들에게 친근하고 유용하며 우호적이다. 만약 이 책에서 언급한 특정 내용에<br />
대해 궁금해지면 자신의 지역 <strong>PHP</strong> 사용자 그룹에 가서 질문해보기 바란다. 여러분이 더 나은<br />
<strong>PHP</strong> 프로그래머가 되도록 도와줄 개발자들은 얼마든지 가까이에 있을 것이다. 지역 <strong>PHP</strong> 사<br />
용자 그룹은 당신이 이 책을 다 읽은 후에도 지속적으로 <strong>PHP</strong> 스킬을 향상할 수 있게 도와줄<br />
귀중한 자원이다.<br />
이 책에 대하여<br />
시작하기에 앞서 몇 가지를 염두에 두었으면 한다.<br />
첫째, 다양한 <strong>PHP</strong> 사용 방법을 이 책에서 모두 다루기에는 시간이 부족하다. 대신 나의 <strong>PHP</strong><br />
사용 방법을 보여줄 것이다. 독단적인 접근 방식임에 분명하지만, 나는 많은 <strong>PHP</strong> 개발자가 채<br />
13
택한 사례와 표준을 그대로 사용한다. 이 책에서 얻은 것들을 여러분의 프로젝트에 즉시 적용<br />
할 수 있을 것이다.<br />
둘째, 여러분이 변수와 조건문, 반복문 등에 익숙하다고 간주한다. <strong>PHP</strong>를 알아야 하는 것은<br />
아니지만, 최소한 프로그래밍 기초 개념에 대한 기본 이해는 필요하다. 커피를 곁들여도 된다.<br />
그 외의 모든 것은 내가 제공해줄 것이다.<br />
셋째, 나는 여러분이 특정 운영체제를 사용한다고 간주하지 않는다. 하지만 앞으로 나올 코드<br />
예제는 리눅스에서 작성한다. 배시 Bash 명령어는 우분투용과 CentOS용을 함께 제공하며 일부<br />
는 OS X에서도 실행할 수 있다. 만약 윈도우 사용자가 이 책의 예제 코드를 실행하고자 한다<br />
면 가급적 리눅스 가상머신을 사용하기 바란다.<br />
이 책의 구성<br />
1부에서는 네임스페이스 namespace , 제너레이터 generator , 트레이트 trait 같은 <strong>PHP</strong>의 새로운 기능을<br />
설명한다. 모던 <strong>PHP</strong> 언어를 소개하고 여러분이 지금까지 몰랐을 수도 있는 기능을 선보인다.<br />
2부에서는 <strong>PHP</strong> 애플리케이션에서 구현해야 할 모범 사례들을 알아본다. PSR에 대해 들어보<br />
았을 것이다. 하지만 그것이 무엇인지, 어떻게 사용하는 것인지 온전하게 확신할 수 있는가?<br />
사용자 입력의 위험을 제거하고 데이터베이스 쿼리를 안전하게 사용하는 방법을 알고 싶은가?<br />
그렇다면 2부를 보라.<br />
3부는 1부와 2부보다 더 기술적이다. 배포, 튜닝, 테스트 그리고 <strong>PHP</strong> 애플리케이션을 프로파<br />
일링하는 방법을 알아본다. 카피스트라노 Capistrano 를 이용한 배포 전략을 세우고 <strong>PHP</strong>유닛 <strong>PHP</strong>Unit<br />
과 트래비스 CI Travis CI 같은 테스팅 도구를 이야기한다. 그리고 <strong>PHP</strong> 애플리케이션의 성능을 높<br />
이기 위한 <strong>PHP</strong> 튜닝 방법도 알아본다.<br />
부록 A는 <strong>PHP</strong>-FPM 설치와 구성에 대해 단계별 안내를 제공한다.<br />
14
부록 B는 프로덕션 서버에 유사하게 대응하는 로컬 개발 환경을 구축하는 방법을 설명한다. 또<br />
한 신속한 구축에 도움을 줄 대안 도구로 베이그런트 Vagrant , 퍼핏 Puppet , 셰프 Chef 를 알아본다.<br />
감사의 말<br />
이 책은 나의 첫 책이다. 오라일리에서 『<strong>Modern</strong> <strong>PHP</strong>』 집필을 제안했을 때 나는 정말이지 흥<br />
분과 두려움에 휩싸여버리고 말았다. 어깨춤이 절로 나올 정도였다. 오라일리가 집필을 제안하<br />
다니, 굉장한 일이지 않은가! 기쁨도 잠시, 흥분을 가라앉히고 나는 스스로에게 정말 그렇게 많<br />
은 양을 쓸 수 있을지 물었다. 책을 쓰는 것은 그리 만만한 작업이 아니기 때문이다.<br />
물론, 즉시 “네”라고 말했다. 가족, 친구, 동료, 편집자, 나를 전적으로 지지해줄 독자들이 있었<br />
기 때문에 기꺼이 『<strong>Modern</strong> <strong>PHP</strong>』를 쓰겠다고 할 수 있었다. 그들이 보내준 귀중한 조언에 감<br />
사의 뜻을 밝히고 싶다. 이들이 아니었다면, 이 책은 절대로 나올 수 없었다.<br />
우선, 오라일리 미디어의 담당 편집자 앨리슨 맥도날드(@allyatoreilly)에게 감사하고 싶다.<br />
앨리는 친절하고, 비판적이고, 든든하며, 명석하다. 그녀는 내가 방향을 잃을 때마다 적절히 바<br />
로 잡아주어야 할 정확한 때와 방법을 알고 있었다. 그녀는 내게 있어 최고의 편집자다.<br />
또한 기술 검토를 해준 아담 페어홀름(@adamfairholm)과 에드 핀클러(@funkatron)에게<br />
도 감사한다. 아담은 뉴프랭글드(https://www.newfangled.com )의 뛰어난 웹 개발자며, 뮤직<br />
비디오 데이터베이스 웹 사이트 IMVDb(http://imvdb.com )의 개발자로 유명하다. 에드는 어<br />
마어마한 <strong>PHP</strong> 실력과 개성적인 팟캐스트 /dev/hell(http://devhell.info), 오픈소싱 정신질환<br />
캠페인 Open Sourcing Mental Illness campaign (http://funkatron.com/osmi)으로 잘 알려져 있다. 아담과<br />
에드는 내 초고의 멍청하고 비논리적이며 부정확한 부분들을 지적해주었다. 그들의 노골적이<br />
고 정직한 피드백에 대해서는 어떠한 말로도 감사의 표현을 다 할 수 없다. 그들의 지도와 지혜<br />
에 영원히 감사한다. 최종 원고에 실수나 오류가 있다면 그것은 전적으로 내 책임이다.<br />
15
늘 나를 격려해준 뉴미디어 캠페인 New Media Campaigns (http://www.newmediacampaigns.com )의<br />
동료들 엘, 클레이, 크리스, 알렉스, 패트릭, 애슐리, 레니, 클레어, 토드, 파스칼, 헨리, 네이<br />
선! 그리고 처음부터 끝까지 친절하게 격려해준 모든 이에게 고개 숙여 감사한다.<br />
가장 중요한 나의 가족 로럴, 이선, 테사, 찰리, 리사, 글렌, 리즈에게 감사한다. 그들의 격려가<br />
없었다면 절대로 이 책을 낼 수 없었을 것이다. 사랑스러운 나의 아내 로럴, 당신의 인내에 감<br />
사한다. 밤 늦은 집필 작업 때문에 매번 카리부 커피 Caribou Coffe1 에 동행해주고 주말에도 아내에<br />
게 소홀했던 나를 이해해줘서 감사한다. 일정을 맞추고 지속적으로 동기부여할 수 있게 해준<br />
것에 감사한다. 지금부터 영원토록 당신을 사랑하겠다.<br />
_저자 조시 록하트<br />
지은이 조시 록하트 Josh Lockhart<br />
조시 록하트는 웹 애플리케이션과 API를 빠르게 개발할 수 있는 초소형 <strong>PHP</strong> 프레임워크 슬림 Slim 을 개발했다. 또한 전 세계 <strong>PHP</strong><br />
개발자들에게 모범 사례를 장려하고 양질의 정보를 제공하는 권장안으로 유명한 ‘<strong>PHP</strong> The Right Way’를 창안했으며 지금도 운<br />
영하고 있다.<br />
조시는 노스캐롤라이나주 칼버러에 위치한 풀-서비스 웹 디자인, 개발, 마케팅 에이전시 업체인 뉴미디어 캠페인(http://www.<br />
newmediacampaigns.com/)에서 개발자로 일하고 있다. HTML, CSS, <strong>PHP</strong>, 자바스크립트, Bash와 다양한 콘텐츠 관리 프<br />
레임워크를 이용한 맞춤 애플리케이션 만들기를 좋아한다. 2008년 노스캐롤라이나대학교 채플힐 캠퍼스 정보문헌학 과정을 수료<br />
했으며 아내인 로럴과 함께 두 마리 개를 키우며 노스캐롤라이나주 채플힐에 거주하고 있다.<br />
조시의 트위터(https://twitter.com/codeguy)를 팔로우하거나 깃허브(https://github.com/codeguy)에서 그의 오픈소스 프<br />
로젝트들을 확인할 수 있다.<br />
1 역자주_ 커피숍 체인의 이름이다.<br />
16
CONTENTS<br />
옮긴이의 글 .................................................................................................................... 6<br />
들어가며 ........................................................................................................................ 9<br />
PART 1 언어 기능<br />
CHAPTER 1 새로운 <strong>PHP</strong><br />
1.1 과거 ............................................................................................................................ 27<br />
1.2 현재 ............................................................................................................................ 28<br />
1.3 미래 ............................................................................................................................ 30<br />
CHAPTER 2 기능<br />
2.1 네임스페이스 ................................................................................................................ 31<br />
2.1.1 네임스페이스를 사용하는 이유 ................................................................................ 33<br />
2.1.2 선언 ................................................................................................................... 34<br />
2.1.3 임포트와 별칭 ...................................................................................................... 35<br />
2.1.4 유용한 팁 ............................................................................................................ 38<br />
2.2 인터페이스로 코딩하기 ................................................................................................... 40<br />
2.3 트레이트 ...................................................................................................................... 45<br />
2.3.1 트레이트를 사용하는 이유 ...................................................................................... 46<br />
2.3.2 트레이트 생성 ...................................................................................................... 47<br />
2.3.3 트레이트 사용 ...................................................................................................... 49<br />
2.4 제너레이터 ................................................................................................................... 50<br />
2.4.1 제너레이터 생성 ................................................................................................... 51<br />
2.4.2 제너레이터 사용 ................................................................................................... 52<br />
17
CONTENTS<br />
2.5 클로저 ......................................................................................................................... 54<br />
2.5.1 생성 ................................................................................................................... 55<br />
2.5.2 상태 등록 ............................................................................................................ 56<br />
2.6 젠드 오피캐시 ............................................................................................................... 59<br />
2.6.1 젠드 오피캐시 활성화 ............................................................................................ 59<br />
2.6.2 젠드 오피캐시 설정 ............................................................................................... 61<br />
2.6.3 젠드 오피캐시 사용 ............................................................................................... 62<br />
2.7 내장 HTTP 서버 ........................................................................................................... 62<br />
2.7.1 서버 실행 ............................................................................................................ 63<br />
2.7.2 서버 설정 ............................................................................................................ 63<br />
2.7.3 라우터 스크립트 ................................................................................................... 64<br />
2.7.4 내장 서버 감지 ..................................................................................................... 64<br />
2.7.5 단점 ................................................................................................................... 65<br />
2.8 다음 장에서 다룰 내용 .................................................................................................... 65<br />
PART 2 모범 사례<br />
CHAPTER 3 표준<br />
3.1 <strong>PHP</strong>-FIG 구조대 .......................................................................................................... 70<br />
3.2 프레임워크 상호운용성 ................................................................................................... 70<br />
3.2.1 인터페이스 .......................................................................................................... 71<br />
3.2.2 오토로딩 ............................................................................................................. 71<br />
3.2.3 코드 스타일 ......................................................................................................... 71<br />
3.3 PSR ........................................................................................................................... 72<br />
3.4 PSR-1: 기본 코드 스타일 ............................................................................................... 73<br />
3.5 PSR-2: 엄격한 코드 스타일 ............................................................................................ 74<br />
18
3.6 PSR-3: 로거 인터페이스 ................................................................................................ 77<br />
3.6.1 PSR-3 로거 작성 ................................................................................................ 78<br />
3.6.2 PSR-3 로거 사용 ................................................................................................ 79<br />
3.7 PSR-4: 오토로더 .......................................................................................................... 80<br />
3.7.1 왜 오토로더가 중요한가 ......................................................................................... 80<br />
3.7.2 PSR-4 오토로더 전략 .......................................................................................... 81<br />
3.7.3 PSR-4 오토로더 작성(을 하면 안 되는 이유) ............................................................. 82<br />
CHAPTER 4 컴포넌트<br />
4.1 컴포넌트를 사용하는 이유 ............................................................................................... 85<br />
4.2 컴포넌트란 무엇인가 ...................................................................................................... 86<br />
4.3 컴포넌트 vs. 프레임워크 ................................................................................................. 87<br />
4.3.1 모든 프레임워크가 나쁜 것은 아니다 ........................................................................ 88<br />
4.3.2 알맞은 도구를 사용하라 ......................................................................................... 89<br />
4.4 컴포넌트 선택 ............................................................................................................... 90<br />
4.4.1 쇼핑 ................................................................................................................... 90<br />
4.4.2 선택 ................................................................................................................... 91<br />
4.4.3 피드백 남기기 ...................................................................................................... 92<br />
4.5 컴포넌트 사용 ............................................................................................................... 92<br />
4.5.1 컴포넌트 설치 ...................................................................................................... 93<br />
4.5.2 컴포넌트 사용법 ................................................................................................... 94<br />
4.5.3 예제 프로젝트 ...................................................................................................... 96<br />
4.5.4 컴포저와 사설 저장소 .......................................................................................... 100<br />
4.6 컴포넌트 만들기 .......................................................................................................... 101<br />
4.6.1 벤더와 패키지명 ................................................................................................. 102<br />
4.6.2 네임스페이스 ..................................................................................................... 103<br />
4.6.3 파일시스템 구성 ................................................................................................. 103<br />
19
CONTENTS<br />
4.6.4 composer.json 파일 ......................................................................................... 104<br />
4.6.5 README 파일 ................................................................................................. 106<br />
4.6.6 컴포넌트 구현 .................................................................................................... 107<br />
4.6.7 버전 관리 .......................................................................................................... 109<br />
4.6.8 패키지스트 등록 ................................................................................................. 109<br />
4.6.9 컴포넌트 사용 .................................................................................................... 111<br />
CHAPTER 5 모범 사례<br />
5.1 위험 제거, 유효성 검사, 예외 처리 ................................................................................... 114<br />
5.1.1 입력값 위험 제거 ................................................................................................ 114<br />
5.1.2 유효성 검사 ....................................................................................................... 118<br />
5.1.3 출력 예외 처리 ................................................................................................... 119<br />
5.2 비밀번호 .................................................................................................................... 120<br />
5.2.1 사용자 비밀번호를 절대 알 수 없게 할 것 ................................................................ 120<br />
5.2.2 비밀번호에 절대 제한을 두지 말 것 ........................................................................ 120<br />
5.2.3 사용자 비밀번호를 절대 이메일로 보내지 말 것 ........................................................ 121<br />
5.2.4 사용자 비밀번호를 bcrypt로 해시하라 ................................................................... 121<br />
5.2.5 비밀번호 해싱 API .............................................................................................. 122<br />
5.2.6 <strong>PHP</strong> 5.5.0 이전의 비밀번호 해싱 API ................................................................... 127<br />
5.3 날짜, 시간, 시간대 ........................................................................................................ 128<br />
5.3.1 기본 시간대 지정 ................................................................................................ 128<br />
5.3.2 DateTime 클래스 .............................................................................................. 129<br />
5.3.3 DateInterval 클래스 ........................................................................................... 130<br />
5.3.4 DateTimeZone 클래스 ...................................................................................... 132<br />
5.3.5 DatePeriod 클래스 ............................................................................................ 133<br />
5.3.6 nesbot/carbon 컴포넌트 ................................................................................... 134<br />
5.4 데이터베이스 .............................................................................................................. 134<br />
20
5.4.1 PDO 확장 ........................................................................................................ 135<br />
5.4.2 데이터베이스 연결과 DSN ................................................................................... 135<br />
5.4.3 준비된 구문 ....................................................................................................... 138<br />
5.4.4 쿼리 결과 .......................................................................................................... 140<br />
5.4.5 트랜잭션 ........................................................................................................... 143<br />
5.5 멀티바이트 문자열 ....................................................................................................... 147<br />
5.5.1 문자 인코딩 ....................................................................................................... 147<br />
5.5.2 UTF-8 데이터 .................................................................................................. 148<br />
5.6 스트림 ....................................................................................................................... 149<br />
5.6.1 스트림 래퍼 ....................................................................................................... 150<br />
5.6.2 스트림 콘텍스트 ................................................................................................. 153<br />
5.6.3 스트림 필터 ....................................................................................................... 154<br />
5.6.4 사용자 정의 스트림 필터 ...................................................................................... 156<br />
5.7 오류와 예외 ................................................................................................................ 159<br />
5.7.1 예외 ................................................................................................................. 160<br />
5.7.2 예외 처리기 ....................................................................................................... 164<br />
5.7.3 오류 ................................................................................................................. 165<br />
5.7.4 오류 처리기 ....................................................................................................... 167<br />
5.7.5 개발 과정에서 오류와 예외 다루기 ......................................................................... 169<br />
5.7.6 프로덕션 ........................................................................................................... 171<br />
PART 3 배포, 테스팅, 튜닝<br />
CHAPTER 6 호스팅<br />
6.1 공유 서버 ................................................................................................................... 177<br />
6.2 가상 사설 서버 ............................................................................................................ 178<br />
21
CONTENTS<br />
6.3 전용 서버 ................................................................................................................... 179<br />
6.4 PaaS ........................................................................................................................ 179<br />
6.5 호스팅 선택 ................................................................................................................ 180<br />
CHAPTER 7 프로비저닝<br />
7.1 목표 .......................................................................................................................... 182<br />
7.2 서버 설정 ................................................................................................................... 182<br />
7.2.1 최초 로그인 ....................................................................................................... 183<br />
7.2.2 소프트웨어 업데이트 ........................................................................................... 183<br />
7.2.3 비루트 사용자 .................................................................................................... 184<br />
7.2.4 SSH 키 쌍 인증 ................................................................................................. 185<br />
7.2.5 비밀번호 인증 및 루트 로그인 비활성화 .................................................................. 187<br />
7.3 <strong>PHP</strong>-FPM ................................................................................................................ 188<br />
7.3.1 설치 ................................................................................................................. 188<br />
7.3.2 전역 설정 .......................................................................................................... 189<br />
7.3.3 풀 설정 ............................................................................................................. 190<br />
7.4 엔진엑스 .................................................................................................................... 193<br />
7.4.1 설치 ................................................................................................................. 193<br />
7.4.2 가상 호스트 ....................................................................................................... 193<br />
7.5 서버 프로비저닝 자동화 ................................................................................................ 197<br />
7.6 서버 프로비저닝 위임 ................................................................................................... 197<br />
7.7 추가 자료 ................................................................................................................... 198<br />
7.8 다음 장에서 다룰 내용 .................................................................................................. 198<br />
CHAPTER 8 튜닝<br />
8.1 php.ini 파일 ............................................................................................................... 199<br />
22
8.2 메모리 ....................................................................................................................... 200<br />
8.3 젠드 오피캐시 ............................................................................................................. 201<br />
8.4 파일 업로드 ................................................................................................................ 203<br />
8.5 최대 실행 시간 ............................................................................................................ 204<br />
8.6 세션 처리 ................................................................................................................... 205<br />
8.7 출력 버퍼링 ................................................................................................................ 205<br />
8.8 리얼패스 캐시 ............................................................................................................. 206<br />
8.9 다음 장에서 다룰 내용 .................................................................................................. 206<br />
CHAPTER 9 배포<br />
9.1 버전 관리 ................................................................................................................... 207<br />
9.2 배포 자동화 ................................................................................................................ 208<br />
9.2.1 단순하게 ........................................................................................................... 208<br />
9.2.2 예측 가능하게 .................................................................................................... 208<br />
9.2.3 가역적으로 ........................................................................................................ 208<br />
9.3 카피스트라노 .............................................................................................................. 208<br />
9.3.1 작동 ................................................................................................................. 209<br />
9.3.2 설치 ................................................................................................................. 210<br />
9.3.3 설정 ................................................................................................................. 210<br />
9.3.4 인증 ................................................................................................................. 212<br />
9.3.5 원격 서버 .......................................................................................................... 212<br />
9.3.6 카피스트라노 훅 ................................................................................................. 213<br />
9.3.7 애플리케이션 배포 .............................................................................................. 214<br />
9.3.8 애플리케이션 되돌리기 ........................................................................................ 214<br />
9.4 참고 자료 ................................................................................................................... 214<br />
9.5 다음 장에서 다룰 내용 .................................................................................................. 215<br />
23
CONTENTS<br />
CHAPTER 10 테스팅<br />
10.1 테스트를 하는 이유 ...................................................................................................... 217<br />
10.2 테스트 시점 ............................................................................................................... 218<br />
10.2.1 개발 전 ............................................................................................................. 218<br />
10.2.2 개발 도중 .......................................................................................................... 218<br />
10.2.3 개발 후 ............................................................................................................. 219<br />
10.3 테스트 대상 ................................................................................................................ 219<br />
10.4 테스트 방법 ................................................................................................................ 219<br />
10.4.1 단위 테스트 ....................................................................................................... 220<br />
10.4.2 테스트 주도 개발(TDD) ....................................................................................... 220<br />
10.4.3 행위 주도 개발(BDD) .......................................................................................... 221<br />
10.5 <strong>PHP</strong>유닛 ................................................................................................................... 222<br />
10.5.1 디렉터리 구조 .................................................................................................... 222<br />
10.5.2 <strong>PHP</strong>유닛 설치 ................................................................................................... 223<br />
10.5.3 Xdebug 설치 .................................................................................................... 224<br />
10.5.4 <strong>PHP</strong>유닛 설정 ................................................................................................... 224<br />
10.5.5 Whovian 클래스 ................................................................................................ 226<br />
10.5.6 WhovianTest 테스트 케이스 ............................................................................... 227<br />
10.5.7 테스트 수행 ....................................................................................................... 230<br />
10.5.8 코드 커버리지 .................................................................................................... 231<br />
10.6 트래비스 CI를 통한 지속적인 테스팅 ............................................................................... 232<br />
10.6.1 설정 ................................................................................................................. 232<br />
10.6.2 실행 ................................................................................................................. 233<br />
10.7 참고 자료 ................................................................................................................... 234<br />
10.8 다음 장에서 다룰 내용 .................................................................................................. 234<br />
24
CHAPTER 11 프로파일링<br />
11.1 프로파일러 사용 시점 ................................................................................................... 235<br />
11.2 프로파일러 종류 .......................................................................................................... 236<br />
11.3 Xdebug .................................................................................................................... 236<br />
11.3.1 설정 ................................................................................................................. 237<br />
11.3.2 발동 ................................................................................................................. 237<br />
11.3.3 분석 ................................................................................................................. 238<br />
11.4 XHProf ..................................................................................................................... 238<br />
11.4.1 설치 ................................................................................................................. 238<br />
11.4.2 XHGUI ............................................................................................................ 239<br />
11.4.3 설정 ................................................................................................................. 240<br />
11.4.4 발동 ................................................................................................................. 240<br />
11.5 뉴렐릭 프로파일러 ....................................................................................................... 241<br />
11.6 블랙파이어 프로파일러 ................................................................................................. 241<br />
11.7 참고 자료 ................................................................................................................... 242<br />
11.8 다음 장에서 다룰 내용 .................................................................................................. 242<br />
CHAPTER 12 HHVM과 Hack<br />
12.1 HHVM ...................................................................................................................... 244<br />
12.1.1 페이스북과 <strong>PHP</strong> ................................................................................................ 244<br />
12.1.2 HHVM과 젠드 엔진의 동등성 ............................................................................... 246<br />
12.1.3 HHVM은 내게 적당한가 ...................................................................................... 246<br />
12.1.4 설치 ................................................................................................................. 247<br />
12.1.5 설정 ................................................................................................................. 248<br />
12.1.6 확장 ................................................................................................................. 249<br />
25
CONTENTS<br />
12.1.7 슈퍼바이저를 이용한 HHVM 관제 ......................................................................... 249<br />
12.1.8 HHVM, FastCGI, 엔진엑스 ................................................................................. 251<br />
12.2 Hack 언어 ................................................................................................................. 253<br />
12.2.1 <strong>PHP</strong>를 Hack으로 변환하기 ................................................................................. 253<br />
12.2.2 타입이란 ........................................................................................................... 254<br />
12.2.3 정적 타이핑 ....................................................................................................... 256<br />
12.2.4 동적 타이핑 ....................................................................................................... 256<br />
12.2.5 Hack은 양손잡이다 ............................................................................................ 257<br />
12.2.6 Hack 타입 검사 ................................................................................................. 258<br />
12.2.7 Hack 모드 ........................................................................................................ 258<br />
12.2.8 Hack 문법 ........................................................................................................ 259<br />
12.2.9 Hack 데이터 구조 .............................................................................................. 261<br />
12.2.10 HHVM/Hack vs. <strong>PHP</strong> ...................................................................................... 262<br />
12.3 참고 자료 ................................................................................................................... 264<br />
CHAPTER 13 커뮤니티<br />
13.1 지역 PUG .................................................................................................................. 265<br />
13.2 컨퍼런스 .................................................................................................................... 266<br />
13.3 멘토링 ....................................................................................................................... 266<br />
13.4 최신 정보 ................................................................................................................... 266<br />
13.4.1 웹 사이트 .......................................................................................................... 266<br />
13.4.2 메일링 리스트 .................................................................................................... 267<br />
13.4.3 트위터 .............................................................................................................. 267<br />
13.4.4 팟캐스트 ........................................................................................................... 267<br />
13.4.5 유머 ................................................................................................................. 267<br />
26
APPENDIX A <strong>PHP</strong> 설치<br />
A.1 리눅스 ....................................................................................................................... 269<br />
A.1.1 패키지 관리자 .................................................................................................... 269<br />
A.1.2 우분투 14.04 LTS ............................................................................................. 270<br />
A.1.3 CentOS 7 ....................................................................................................... 272<br />
A.2 OS X ........................................................................................................................ 274<br />
A.2.1 MAMP ............................................................................................................ 274<br />
A.2.2 홈브루 .............................................................................................................. 278<br />
A.3 소스코드로 설치 .......................................................................................................... 282<br />
A.3.1 소스코드 얻기 .................................................................................................... 284<br />
A.4 윈도우 ....................................................................................................................... 290<br />
A.4.1 바이너리 ........................................................................................................... 290<br />
A.4.2 WAMP ............................................................................................................ 290<br />
A.4.3 젠드 서버 .......................................................................................................... 291<br />
APPENDIX B 로컬 개발 환경<br />
B.1 버추얼 박스 ................................................................................................................ 294<br />
B.2 베이그런트 ................................................................................................................. 295<br />
B.2.1 명령어 .............................................................................................................. 295<br />
B.2.2 박스 ................................................................................................................. 296<br />
B.2.3 초기화 .............................................................................................................. 296<br />
B.2.4 프로비전 ........................................................................................................... 297<br />
B.2.5 동기화된 폴더 .................................................................................................... 298<br />
B.2.6 시작하기 ........................................................................................................... 299<br />
찾아보기 .................................................................................................................... 303<br />
27
CHAPTER 1<br />
새로운 <strong>PHP</strong><br />
<strong>PHP</strong> 언어는 르네상스를 맞이했다. <strong>PHP</strong>는 네임스페이스, 트레이트, 클로저, 내장 오피코드<br />
opcode<br />
캐시 같이 유용한 기능을 탑재한 최신 스크립트 언어로 탈바꿈 중이다. <strong>PHP</strong> 생태계 또한<br />
진화하고 있다. <strong>PHP</strong> 개발자들은 이제 단일 프레임워크보다는 작고 특화된 컴포넌트에 더 의<br />
지한다. 의존성 관리도구인 컴포저 Composer 는 <strong>PHP</strong> 애플리케이션 구축 방법에 혁신을 일으켰다.<br />
프레임워크의 울타리 안에서 벗어나 상호운용이 가능한 컴포넌트들을 각각의 <strong>PHP</strong> 애플리케<br />
이션에 알맞게 짜맞출 수 있게 되었다. 컴포넌트 간의 이러한 상호운용은 <strong>PHP</strong> 프레임워크 인<br />
터롭 그룹 <strong>PHP</strong> Framework Interop Group (<strong>PHP</strong>-FIG)이 주도하고 제안한 커뮤니티 표준이 없었다면 불<br />
가능했을 것이다.<br />
『<strong>Modern</strong> <strong>PHP</strong>』는 새로운 <strong>PHP</strong>에 대한 안내서다. 커뮤니티 표준과 모범 사례, 상호운용이 가<br />
능한 컴포넌트들을 사용하여 멋진 <strong>PHP</strong> 애플리케이션을 구축하고 이를 배포하는 방법을 알려<br />
줄 것이다.<br />
1.1 과거<br />
최신 <strong>PHP</strong>를 탐험하기에 앞서 <strong>PHP</strong>의 기원을 아는 게 중요하다. <strong>PHP</strong>는 인터프리터 방식의 서<br />
버 측 스크립트 언어다. <strong>PHP</strong> 코드를 작성해서 웹 서버에 올리면 인터프리터에 의해 실행된다<br />
는 뜻이다. <strong>PHP</strong>는 보통 아파치 혹은 엔진엑스 Nginx 와 함께 동적인 콘텐츠를 제공하는 데 쓰인<br />
1장 새로운 <strong>PHP</strong><br />
29
다. 그러나 <strong>PHP</strong>는 (Bash, 루비, 파이썬 등과 마찬가지로) 강력한 명령행 애플리케이션을 만<br />
드는 데에도 쓰일 수 있다. 많은 <strong>PHP</strong> 개발자가 이 사실을 모른 채 진짜 흥미로운 부분을 놓치<br />
고 있지만 이 책을 읽고 있는 여러분은 그렇지 않다.<br />
공식적인 <strong>PHP</strong> 역사는 래즈머스 러더프 Rasmus Lerdorf (<strong>PHP</strong>의 창시자)가 http://php.net/manual/<br />
history.php.php에 이미 잘 정리해 놓았으니 여기에서 다시 이야기할 필요는 없다. 내가 말하<br />
려는 바는 <strong>PHP</strong>의 역사에 격동기가 있었다는 사실이다. <strong>PHP</strong>는 래즈머스 러더프가 온라인 이<br />
력서 방문 기록을 추적하기 위해 작성한 CGI 스크립트 모음에서 시작됐다. 러더프는 자신의<br />
CGI 스크립트 모음을 ‘Personal Home Page Tools’라고 불렀다. 이때의 초기 형태는 오늘<br />
날 우리가 아는 <strong>PHP</strong>와는 완전히 달랐다. 러더프의 초기 <strong>PHP</strong> Tools는 스크립트 언어가 아니<br />
라 HTML 내장 문법을 이용해 기본적인 변수들과 자동화된 폼 변수들을 제공하는 도구였다.<br />
1994년에서 1998년 사이에 <strong>PHP</strong>는 수많은 개정을 거치며 개선됐고 심지어 몇 번은 완전히 새<br />
로 만들어지기도 했다. 이스라엘 서부 지중해 연안에 있는 도시 텔아비브의 앤디 거트먼스와<br />
지브 수라스키가 래즈머스 러더프와 합류했으며 이들의 손에 의해 <strong>PHP</strong>는 소형 CGI 도구모음<br />
을 넘어 일관된 문법과 기본적인 객체지향 프로그래밍 기능을 갖춘 어엿한 프로그래밍 언어로<br />
탈바꿈했다. 1998년 말 이들은 자신들의 최종 결과물을 <strong>PHP</strong> 3라 명명하고 릴리스`했다. <strong>PHP</strong><br />
라는 단어의 의미는 이전과 완전히 다른 <strong>PHP</strong>: Hypertext Preprocessor의 재귀적인 약자로<br />
변모했다. <strong>PHP</strong> 3는 오늘날 우리가 알고 있는 <strong>PHP</strong>와 가장 닮은 첫 번째 버전이며 다양한 데이<br />
터베이스, 프로토콜, API에 대해 뛰어난 확장성을 제공했다. 이러한 확장성은 많은 신규 개발<br />
자가 <strong>PHP</strong> 3를 프로젝트에 도입하게 되는 기폭제 역할을 했다. <strong>PHP</strong> 3는 경이롭게도 1998년<br />
말에 이미 전 세계 웹 서버의 10%에 설치되기에 이른다.<br />
1.2 현재<br />
오늘날 <strong>PHP</strong> 언어는 빠르게 진화하며 세계 각지에 있는 여러 핵심 개발팀의 지원을 받고 있다.<br />
개발 관행 역시 변했다. 과거에는 <strong>PHP</strong> 파일을 작성하고 프로덕션 서버에 FTP로 업로드한 뒤<br />
작동하길 바라는 것이 관행이었다. 형편없는 개발 전략이지만, 적절한 로컬 개발 환경이 없었<br />
기 때문에 어쩔 수 없었다.<br />
30 1부 언어 기능
요즘은 FTP를 지양하고 버전 관리를 사용한다. 깃 Git 과 같은 버전 관리 프로그램을 이용해 코<br />
드의 이력을 유지하고, 브랜치나 포크를 생성하고, 코드를 병합한다. 베이그런트 같은 가상화<br />
도구와 앤시블, 셰프, 퍼핏 같은 구성 도구들을 사용해 로컬 개발 환경을 프로덕션 서버와 일치<br />
시킨다. 의존성 관리도구인 컴포저로는 특화된 <strong>PHP</strong> 컴포넌트들을 다룬다. 코드를 작성할 때<br />
는 <strong>PHP</strong> 프레임워크 인터롭 그룹이 관리하는 커뮤니티 표준인 PSR을 충실히 따른다. <strong>PHP</strong>유<br />
닛 같은 도구로 코드를 철저하게 테스트한다. 애플리케이션은 엔진엑스 같은 웹 서버 후방에<br />
배포하고 <strong>PHP</strong> FastCGI 프로세스 관리자로 실행한다. 그리고 오피코드 캐시를 통해 애플리케<br />
이션 성능을 향상시킨다.<br />
『<strong>Modern</strong> <strong>PHP</strong>』 는 <strong>PHP</strong>를 처음 접하거나 이전 버전을 경험한 이들에게는 낯설 수도 있는 새<br />
롭고 많은 관행을 포괄한다. 그렇다고 주눅들 필요는 없다. 이 책에서 각각의 개념을 차근차근<br />
알아볼 것이기 때문이다.<br />
이제 <strong>PHP</strong>에는 2014년까지는 없었던 공식 규약 초안이 생겼다.<br />
성숙한 프로그래밍 언어들에는 대부분 규약이 있다. 쉽게 말해 규약이란 <strong>PHP</strong>가 무엇인지를 정의<br />
하는 원본 청사진이다. <strong>PHP</strong> 코드를 분석하고, 해석하고, 실행하는 프로그램을 만드는 개발자들이 사용한다.<br />
<strong>PHP</strong>로 애플리케이션이나 웹 사이트를 만드는 개발자들을 위한 것이 아니다.<br />
새라 골먼과 페이스북은 2014년 오라일리에서 주최한 오스콘 컨퍼런스에서 첫 <strong>PHP</strong> 규약 초<br />
안을 발표했다. 공식 발표문은 <strong>PHP</strong> 내부 메일링 리스트(http://bit.ly/php-internals)나 <strong>PHP</strong><br />
규약 깃허브(http://bit.ly/php-langspec)에서 볼 수 있다.<br />
공식 언어 규약은 경쟁 엔진이 등장하면서 그 중요성이 더욱 부각된다. 기존 <strong>PHP</strong> 엔진은 <strong>PHP</strong><br />
4에서 도입된 젠드 Zend 엔진(http://www.zend.com/en/company/community/php/)이다. 젠드<br />
엔진은 C로 작성된 <strong>PHP</strong> 인터프리터로 래즈머스 러더프, 앤디 거트먼스, 지브 수라스키가 만<br />
들었다. 오늘날 젠드사는 젠드 엔진을 통해 <strong>PHP</strong> 커뮤니티에 크게 기여하고 있지만, 이제 페이<br />
스북의 힙합 가상머신(HHVM)이 <strong>PHP</strong>의 주요한 두 번째 엔진으로 부상하고 있다. 언어 규약<br />
은 이 두 엔진이 기준 호환성을 유지할 수 있도록 보장해준다.<br />
<strong>PHP</strong> 엔진은 <strong>PHP</strong> 코드를 분석, 해석하고 실행하는 프로그램이다(예: 젠드 엔진이나 페이스북의<br />
HHVM). <strong>PHP</strong> 언어 자체와 혼동하지 않도록 한다.<br />
1장 새로운 <strong>PHP</strong><br />
31
1.3 미래<br />
젠드 엔진은 빠른 속도로 새로운 기능을 개선하고 성능을 향상하고 있다. 나는 젠드 엔진의 향<br />
상이 새로운 경쟁자, 특히 페이스북의 HHVM과 Hack 핵 언어 덕분이라고 본다.<br />
Hack은 <strong>PHP</strong>를 기반으로 구축된 새로운 프로그래밍 언어다. 동적 타입이 선언된 기존 <strong>PHP</strong><br />
코드와 하위 호환을 유지하는 동시에 정적 타입 선언, 새로운 데이터 구조, 추가적인 인터페이<br />
스를 제공한다. <strong>PHP</strong>의 빠른 개발 특성을 인정하지만 정적 타입 선언이 주는 예측 가능성과 안<br />
정성이 필요한 개발자들이 Hack의 주타깃층이다.<br />
동적 타입 선언과 정적 타입 선언에 대해서는 나중에 논의할 것이다. 둘 사이의 차이점은 <strong>PHP</strong>가 타<br />
입을 검사하는 시점이다. 동적 타입은 런타임 시에 검사하는 반면, 정적 타입은 컴파일 시에 검사한다. 더 많<br />
은 정보는 12장을 보기 바란다.<br />
HHVM은 저스트 인 타임(JIT) 컴파일러를 사용해 애플리케이션의 성능을 향상시키고 메모<br />
리 사용을 줄이는 <strong>PHP</strong>와 Hack의 인터프리터다.<br />
나는 Hack과 HHVM이 젠드 엔진을 대체하게 될 거라고 예상하진 않는다. 하지만 페이스북의<br />
새로운 기여는 <strong>PHP</strong> 커뮤니티에 큰 파장을 불러 일으켰다. 젠드 엔진 핵심팀이 <strong>PHP</strong> 7 (http://<br />
bit.ly/php7-timeline)을 발표하면서 HHVM과 동등한 수준으로 젠드 엔진을 최적화시켰다고<br />
언급한 배경에는 상대 엔진에 대한 경쟁의식이 잘 나타나 있다. 이러한 상황 변화에 대해서는<br />
12장에서 좀 더 논의해볼 것이다.<br />
<strong>PHP</strong> 프로그래머에게 있어 더할 나위 없이 흥미진진한 시기다. <strong>PHP</strong> 커뮤니티가 이토록 열정<br />
적이고, 재미있고, 혁신적이었던 적은 없었다. 이 책을 통해 최신 <strong>PHP</strong>의 사례들을 확고히 받<br />
아들이길 바란다. 새롭게 배워야 할 것이 엄청나게 많으며 앞으로도 계속해서 생길 것이다. 이<br />
것이 여러분의 로드맵이다. 자, 이제 시작해보자!<br />
32 1부 언어 기능
CHAPTER 2<br />
기능<br />
모던 <strong>PHP</strong> 언어에는 새롭고 흥미진진한 기능이 많다. 새로운 기능은 이전 버전을 사용하던<br />
<strong>PHP</strong> 프로그래머에게는 신선함을 선사하고, 다른 언어를 사용하다 새로이 <strong>PHP</strong>를 접한 프로그<br />
래머에게는 놀라움을 선사할 것이다. 이러한 신기능 덕분에 <strong>PHP</strong>는 더 강력한 플랫폼이 되었<br />
으며, 웹 애플리케이션과 명령행 도구를 개발하는 데 쾌적한 환경을 제공하게 되었다.<br />
필수적이진 않지만 그래도 편리한 기능이 있는 반면, 꼭 필요한 기능도 있다. 예컨대 네임스페<br />
이스는 모던 <strong>PHP</strong> 표준의 초석이며, 모던 <strong>PHP</strong> 개발자라면 당연시하는 개발 관행들(예: 오토<br />
로딩)을 가능하게 해준다. 이제부터 신기능이 어떤 면에서 유용한지와 여러분의 프로젝트에<br />
신기능을 어떻게 구현하는지 보여줄 것이다.<br />
TIP<br />
앞으로 나올 예제들을 자신의 컴퓨터에서 따라해보기 바란다. 모든 예제 코드는 이 책의 깃허브 저장소<br />
(https://github.com/cloud-shadow/hanbit-modern-php)에서 찾을 수 있다.<br />
2.1 네임스페이스<br />
모던 <strong>PHP</strong> 기능 중 꼭 하나만 알아야 한다면 그것은 네임스페이스일 것이다. <strong>PHP</strong> 5.3.0에서<br />
도입된 네임스페이스는 <strong>PHP</strong> 코드를 운영체제의 파일시스템 디렉터리 구조처럼 가상 계층 구<br />
조로 구성하는 중요한 도구다. 모던 <strong>PHP</strong> 컴포넌트와 프레임워크는 전역적으로 고유한 벤더<br />
2장 기능<br />
33
네임스페이스 1 하위에 각각의 코드를 구성한다. 따라서 다른 벤더에서 같은 이름의 클래스를<br />
사용해도 서로 충돌하거나 소유권 문제가 발생하지 않는다.<br />
커피숍에 들어갔는데 기분 나쁜 누군가가 책이며 전선이며 뭔가를 여러 탁자에 잔뜩 어질러 놓고<br />
있다면 질색하지 않겠는가? 게다가 쓰지도 않으면서 유일한 전원 콘센트 바로 옆에 앉아있다면 말이다. 이 사<br />
람은 지금 유용하게 쓸 수 있는 귀중한 공간을 낭비하고 있다. 비유적으로 말하자면, 네임스페이스를 쓰지 않<br />
는 것은 이와 같다. 이런 사람이 되지 말자.<br />
실제로 <strong>PHP</strong> 컴포넌트에서 네임스페이스를 사용하는 방법을 살펴보자. 심포니 Symfony 프레임워<br />
크의 symfony/httpfoundation (https://github.com/symfony/HttpFoundation)은 HTTP 요<br />
청과 응답을 관리하는 <strong>PHP</strong> 컴포넌트로 유명하다. 중요한 점은, symfony/httpfoundation<br />
컴포넌트가 Request, Response, Cookie 같은 흔한 클래스명을 사용한다는 사실이다. 이런 클<br />
래스명을 사용하는 다른 <strong>PHP</strong> 컴포넌트도 많을 것이다. 만약 다른 <strong>PHP</strong> 코드에 동일한 이름<br />
의 클래스가 있다면 어떻게 symfony/httpfoundation 컴포넌트를 쓸 수 있을까? symfony/<br />
httpfoundation 컴포넌트를 안전하게 사용할 수 있는 것은 바로 Symfony라는 고유한 벤<br />
더 네임스페이스 하위에 코드가 고립되어 sandboxed 있기 때문이다. 깃허브에 있는 symfony/<br />
httpfoundation 컴포넌트 저장소(https://github.com/symfony/HttpFoundation )에서<br />
Response.php 파일을 찾아보면 [그림 2-1]처럼 보인다.<br />
[그림 2-1]의 12번째 줄을 살펴보자. 다음과 같은 코드가 있다.<br />
namespace Symfony\Component\HttpFoundation;<br />
이것이 <strong>PHP</strong> 네임스페이스 선언이며 항상
그림 2-1 깃허브 symfony/httpfoundation 스크린샷<br />
구성하고 캡슐화한다.<br />
TIP<br />
서브네임스페이스는 \ 문자로 구분한다.<br />
<strong>PHP</strong> 네임스페이스는 운영체제의 물리적 파일시스템과는 달리 가상 개념이며 파일시스템 디<br />
렉터리와 1:1로 대응할 필요가 없다. 그렇긴 해도 사실상 대부분의 <strong>PHP</strong> 컴포넌트가 서브네임<br />
스페이스를 파일시스템 디렉터리에 맞춘다. 대중화된 PSR-4 오토로더 autoloader 표준과의 호환<br />
성을 위해서다(3장에서 좀 더 이야기해볼 것이다).<br />
엄밀히 말하자면 네임스페이스는 <strong>PHP</strong> 인터프리터가 클래스, 인터페이스, 함수, 상수의 이름에 공통<br />
접두어를 적용하기 위해 참조하는 <strong>PHP</strong> 언어 표기법일 뿐이다.<br />
2.1.1 네임스페이스를 사용하는 이유<br />
네임스페이스가 중요한 이유는 네임스페이스를 통해 다른 개발자들의 코드와 동시에 작동하는<br />
고립된 코드를 만들 수 있기 때문이다. 이것은 모던 <strong>PHP</strong> 컴포넌트 생태계의 기본 개념이다.<br />
2장 기능<br />
35
컴포넌트와 프레임워크 제작자들은 코드를 만들어 수많은 <strong>PHP</strong> 개발자에게 배포한다. 그들에<br />
게는 자신들의 코드와 함께 쓰는 클래스, 인터페이스, 함수, 상수를 알거나 제어할 방법이 없<br />
다. 이 문제는 내부 프로젝트에도 마찬가지로 적용된다. 만약 프로젝트 자체 <strong>PHP</strong> 컴포넌트나<br />
클래스들을 만든다면 그 코드는 프로젝트가 의존하는 서드파티와 동시에 작동해야만 한다.<br />
앞서 언급했던 symfony/httpfoundation 컴포넌트의 경우처럼 다른 개발자들의 코드에 같은<br />
이름의 클래스나 인터페이스, 함수, 상수가 있을 수도 있다. 이 경우 네임스페이스가 없다면 이<br />
름 충돌로 인해 <strong>PHP</strong>에 문제가 생긴다. 네임스페이스를 이용하면 고유한 벤더 네임스페이스<br />
하위에 코드가 존재한다고 간주하기 때문에 다른 개발자들의 코드에 같은 이름의 클래스, 인터<br />
페이스, 함수, 상수가 있더라도 충돌 없이 사용할 수 있다.<br />
약간의 의존성만 있는 작은 개인 프로젝트라면 이름 충돌은 별 문제가 되지 않는다. 하지만 수<br />
많은 서드파티에 의존하는 대규모 팀 프로젝트를 수행한다면 이름 충돌은 매우 실질적인 근심<br />
거리가 될 수 있다. 서드파티가 전역 네임스페이스에 불러들이는 클래스, 인터페이스, 함수, 상<br />
수는 제어할 수 없기 때문이다. 이것이 네임스페이스를 사용하는 중요한 이유다.<br />
2.1.2 선언<br />
모든 <strong>PHP</strong> 클래스, 인터페이스, 함수, 상수는 네임스페이스 (혹은 서브네임스페이스) 하위에<br />
존재한다. 네임스페이스는 <strong>PHP</strong> 파일 제일 위에 있는
서브네임스페이스는 앞의 예시와 같은 방법으로 선언한다. 유일한 차이는 네임스페이스와 서<br />
브네임스페이스 사이를 \ 문자로 구분한 것이다. 이어지는 예시는 최상위 벤더 네임스페이스<br />
Hanbit의 하위에 존재하는 <strong>Modern</strong><strong>PHP</strong> 서브네임스페이스를 선언한다.<br />
임스페이스도 비슷한 문제를 보여준다. 예를 들어 symfony\httpfoundation 컴포넌트에 있<br />
는 Response 클래스의 전체 클래스명은 \Symfony\Component\HttpFoundation\Response<br />
다. 다행히 <strong>PHP</strong>에서는 네임스페이스를 임포트하거나 별칭으로 부를 수 있다.<br />
임포트를 통해 각 <strong>PHP</strong> 파일에서 어떤 네임스페이스, 클래스, 인터페이스, 함수, 상수를 사용<br />
할 것인지 <strong>PHP</strong>에 알려준다. 그러면 네임스페이스 전체를 타이핑하지 않고도 이들을 사용할<br />
수 있다.<br />
그리고 별칭을 통해 임포트한 클래스, 인터페이스, 함수, 상수를 축약한 이름으로 참조할 것임<br />
을 <strong>PHP</strong>에 알려준다.<br />
TIP<br />
<strong>PHP</strong> 5.3부터 클래스와 인터페이스, 네임스페이스를 임포트하거나 별칭을 지정할 수 있다. <strong>PHP</strong> 5.6부터는<br />
함수와 상수도 임포트하거나 별칭을 지정할 수 있다.<br />
[예제 2-1]은 400 Bad Reqeust HTTP 응답을 생성해 전송하는 코드다. 임포트와 별칭을 사<br />
용하지 않는다.<br />
예제 2-1 별칭이 없는 네임스페이스<br />
CHAPTER 3<br />
표준<br />
<strong>PHP</strong> 컴포넌트와 프레임워크는 어마어마하게 많다. 심포니(http://symfony.com )나 라라벨<br />
(http://laravel.com ) 같은 대형 프레임워크가 있는가 하면 사일렉스(http://silex.sensiolabs.<br />
org )나 슬림(http://slimframework.com ) 같은 초소형 프레임워크도 있다. 코드이그나이터<br />
(http://www.codeigniter.com )처럼 <strong>PHP</strong> 컴포넌트가 존재하기 이전에 만들어진 구형 프레임<br />
워크도 있다. 모던 <strong>PHP</strong> 생태계는 개발자로 하여금 놀라운 애플리케이션을 만들 수 있게 해주<br />
는 진정한 코드 용광로다.<br />
불행하게도 오래 전에 개발된 <strong>PHP</strong> 프레임워크들은 고립되어 있으며 다른 <strong>PHP</strong> 프레임워크와<br />
코드를 공유하지 않는다. 이런 구형 <strong>PHP</strong> 프레임워크를 프로젝트에 사용하면 프레임워크의 생<br />
태계 안에 꼼짝 못하고 갇히게 된다. 프레임워크의 기능이 만족스럽다면 이런 중앙집중적인 환<br />
경도 나쁘지 않다. 하지만 코드이그나이터 프레임워크를 프로젝트에 사용하던 중에 심포니 프<br />
레임워크의 헬퍼 라이브러리만 선택적으로 사용하고 싶어지면 어떻게 해야 할까? 프로젝트만<br />
의 전용 어댑터를 만드는 것 말고는 달리 방법이 없을 것이다.<br />
이 친구는 말이 안 통하는 친구라고. – 영화 《폭력 탈옥 Cool Hand Luke 》 중에서<br />
문제점을 알겠는가? 고립된 프레임워크는 다른 프레임워크와 소통하도록 설계되지 않았다. 이<br />
는 (프레임워크로 인해 창조성이 제한된) 개발자와 (어딘가에 이미 있는 코드를 다시 구현해<br />
야 하는) 프레임워크 모두에게 극단적으로 비효율적이다. 하지만 좋은 소식이 있다. <strong>PHP</strong> 커<br />
뮤니티는 이런 중앙집중적인 프레임워크 모델을 효율적이고, 상호운용 가능하며, 특화된 컴포<br />
넌트 생태계로 진화시켜왔다.<br />
3장 표준<br />
39
3.1 <strong>PHP</strong>-FIG 구조대<br />
이러한 문제점을 인식한 몇몇 <strong>PHP</strong> 프레임워크 개발자들이 2009년 php|tek (http://tek.<br />
phparch.com ) (유명한 <strong>PHP</strong> 컨퍼런스)에서 만나 대화하기 시작했다. 이들은 프레임워크의<br />
소통과 효율을 향상할 방법을 논의했다. 프레임워크와 강하게 결합된 로깅 클래스를 새로 만드<br />
는 대신 monolog (https://github.com/Seldaek/monolog) 같은 분리된 로깅 클래스를 서로 공<br />
유할 수 있다면? HTTP 요청과 응답을 처리할 자신만의 클래스를 만드는 대신, 심포니 프레임<br />
워크에 포함된 symfony/httpfoundation (http://bit.ly/symf-docs ) 컴포넌트에서 HTTP 관련<br />
클래스만 가져와 사용할 수 있다면? 이런 일들을 가능하게 하려면 <strong>PHP</strong> 프레임워크들이 소통<br />
과 공유에 사용할 공통의 언어가 있어야 한다. 다시 말해 표준이 필요하다.<br />
php|tek에서 우연히 만난 <strong>PHP</strong> 프레임워크 개발자들은 마침내 <strong>PHP</strong> 프레임워크 인터롭 그<br />
룹(<strong>PHP</strong>-FIG) (http://www.php-fig.org )을 결성했다. <strong>PHP</strong>-FIG 웹 사이트에 따르면 <strong>PHP</strong>-<br />
FIG는 “프로젝트들이 가진 공통성에 관해 이야기하고 함께 만들어나갈 수 있는 방법을 모색하<br />
는 <strong>PHP</strong> 프레임워크 대표자들의 모임”이다. <strong>PHP</strong>-FIG는 <strong>PHP</strong> 프레임워크 사이의 소통과 공<br />
유를 향상하기 위해 프레임워크 스스로 구현할 수 있는 권장안을 창안했다.<br />
<strong>PHP</strong>-FIG는 프레임워크 대표자들이 자발적으로 결성한 단체다. 구성원을 뽑는 특별한 방법<br />
은 없다. <strong>PHP</strong> 커뮤니티 발전에 기꺼이 기여하고자 한다면 누구나 가입을 신청할 수 있고 제안<br />
단계의 권장안에 피드백을 보낼 수도 있다. 통상적으로 <strong>PHP</strong>-FIG는 가장 규모가 크고 인기<br />
있는 <strong>PHP</strong> 프레임워크들에 채택되어 구현된다. 여러분도 <strong>PHP</strong>-FIG에 피드백을 보내 선호하<br />
는 <strong>PHP</strong> 프레임워크의 미래에 일조할 수 있기를 바란다.<br />
<strong>PHP</strong>-FIG가 제공하는 권장안은 규칙도 요구사항도 아니라는 점을 이해해야 한다. 이 권장안은 신<br />
중히 다듬어진 제안이며 이를 통해 <strong>PHP</strong> 개발자(그리고 프레임워크 제작자)들의 삶이 한결 편해진다.<br />
3.2 프레임워크 상호운용성<br />
<strong>PHP</strong>-FIG의 목표는 프레임워크 상호운용성이다. 프레임워크 상호운용성이란 프레임워크들<br />
이 인터페이스, 오토로딩, 스타일을 통해 함께 작동함을 의미한다.<br />
40 2부 모범 사례
3.2.1 인터페이스<br />
<strong>PHP</strong> 프레임워크는 공유 인터페이스를 통해 함께 작동한다. 인터페이스를 사용하면 프레임워<br />
크가 의존하는 서드파티의 메서드가 어떻게 인터페이스를 구현했는지 걱정하지 않아도 된다.<br />
<strong>PHP</strong> 인터페이스에 대한 상세한 설명은 2장을 참고하도록 한다.<br />
예를 들어 프레임워크는 emergency( ), alert( ), critical( ), error( ), warning( ),<br />
notice (), info (), debug () 메서드를 구현한 서드파티 로거 객체를 마음껏 공유할 수 있다.<br />
로거 객체가 이 메서드들을 정확히 어떻게 구현했는지는 상관하지 않는다. 각 프레임워크는 서<br />
드파티가 이 메서드들을 구현했다는 사실 자체에만 관심이 있다.<br />
<strong>PHP</strong> 개발자들은 인터페이스를 통해 단일 프레임워크 대신 특화된 컴포넌트들을 만들어 공유<br />
하고 사용할 수 있다.<br />
3.2.2 오토로딩<br />
<strong>PHP</strong> 프레임워크는 오토로딩을 통해 함께 작동한다. 오토로딩은 <strong>PHP</strong> 인터프리터가 런타임 시<br />
<strong>PHP</strong> 클래스를 그때그때 자동으로 불러오는 과정이다.<br />
<strong>PHP</strong> 표준이 있기 전, <strong>PHP</strong> 컴포넌트와 프레임워크들은 특수 메서드인 \__autoload() 혹은<br />
더 최근에 나온 spl_autoload_register()를 이용해 각자 고유한 오토로더를 구현했다. 이<br />
때문에 사용자들은 각 컴포넌트와 프레임워크의 오토로더 사용법을 모두 익혀야 했다. 요즘에<br />
는 모던 <strong>PHP</strong> 컴포넌트와 프레임워크 대부분이 공통 오토로더 표준을 준수한다. 이는 단 하나<br />
의 오토로더로 다수의 <strong>PHP</strong> 컴포넌트를 필요에 따라 조합할 수 있음을 의미한다.<br />
3.2.3 코드 스타일<br />
<strong>PHP</strong> 프레임워크는 코드 스타일을 통해 함께 작동한다. 코드 스타일은 (여러 가지 중에서도)<br />
공백, 대소문자, 괄호 위치를 결정한다. <strong>PHP</strong> 프레임워크들이 표준 코드 스타일 사용에 합의하<br />
면 <strong>PHP</strong> 개발자들은 새로운 <strong>PHP</strong> 프레임워크를 사용할 때마다 매번 새로운 스타일을 익힐 필<br />
요가 없어지고, 그 대신 <strong>PHP</strong> 프레임워크들의 코드는 단숨에 비슷해진다. 또한 표준 코드 스타<br />
3장 표준<br />
41
일은 신규 프로젝트 기여자들의 진입장벽을 낮춰준다. 이들은 낯선 스타일을 익히는 데 들이는<br />
시간을 줄이는 대신 버그를 없애는 데 더 많은 시간을 쓸 수 있다.<br />
표준 코드 스타일을 사용하면 여러분의 프로젝트도 향상된다. 모든 개발자에게는 자신만의 스<br />
타일이 있으며 그중에는 별스러운 습관도 적지 않다. 이런 습관은 많은 개발자가 같은 코드베<br />
이스를 다룰 때 문제가 된다. 표준 코드 스타일을 사용하면 제작자가 누구든 모든 팀 구성원이<br />
같은 코드베이스를 바로 이해할 수 있다.<br />
3.3 PSR<br />
PSR은 <strong>PHP</strong> Standard Recommendation <strong>PHP</strong> 표준 권장안 의 약자다. 최근 <strong>PHP</strong> 관련 블로그를 읽<br />
었다면 PSR-1, PSR-2, PSR-3 등의 용어를 보았을 것이다. 이 용어들은 <strong>PHP</strong>-FIG 권장안<br />
을 가리킨다. 권장안의 이름은 PSR-로 시작하고 번호로 끝난다. 각 <strong>PHP</strong>-FIG 권장안은 <strong>PHP</strong><br />
프레임워크 대부분이 빈번하게 맞닥뜨리는 특정 문제를 해결해준다. <strong>PHP</strong> 프레임워크들은 같<br />
은 문제를 반복적으로 해결하는 대신 <strong>PHP</strong>-FIG의 권장안을 채택하고 공유된 해결 방법을 사<br />
용할 수 있다.<br />
<strong>PHP</strong>-FIG는 이 책의 출간 시점까지 다섯 가지 권장안을 공표했다.<br />
● PSR-1 : 기본 코드 스타일(http://www.php-fig.org/psr/psr-1/)<br />
● PSR-2 : 엄격한 코드 스타일(http://www.php-fig.org/psr/psr-2/)<br />
● PSR-3 : 로거 인터페이스(http://www.php-fig.org/psr/psr-3/)<br />
● PSR-4 : 오토로딩(http://www.php-fig.org/psr/psr-4/)<br />
네 개밖에 없는 것이 정상이다. <strong>PHP</strong>-FIG는 첫 번째 권장안이었던 PSR-0(http://www.php-fig.<br />
org/psr/psr-0/)를 폐기했다. 이 권장안은 PSR-4(http://www.php-fig.org/psr/psr-4/) 권장안으로 새롭<br />
게 대체됐다.<br />
권장안의 주제들이 앞서 살펴본 세 가지 상호운용 방법(인터페이스, 오토로딩, 코드 스타일)<br />
과 근사하게 맞아떨어진다는 점에 주목하자. 이것은 우연의 일치가 아니다.<br />
42 2부 모범 사례
나는 <strong>PHP</strong>-FIG 권장안에 정말로 흥분했다. 이 권장안들은 모던 <strong>PHP</strong> 생태계를 떠받치는 기반<br />
이며 <strong>PHP</strong> 컴포넌트와 프레임워크들이 상호운용할 수단을 정의한다. <strong>PHP</strong> 표준은 분명 가장<br />
참신한 사안은 아니지만, (내 생각에는) 모던 <strong>PHP</strong>를 이해하기 위한 필수 전제조건이다.<br />
3.4 PSR-1: 기본 코드 스타일<br />
커뮤니티 표준과 호환하는 <strong>PHP</strong> 코드를 작성하고자 한다면 PSR-1으로 시작하자. 가장 사용하<br />
기 쉬운 <strong>PHP</strong> 표준이다. 너무 쉬운 나머지 아마 시도하지도 않았는데 이미 사용하고 있을지도<br />
모른다. PSR-1은 최소한의 노력으로도 쉽게 준수할 수 있는 단순한 지침을 제공한다. PSR-1<br />
의 목표는 PSR에 동참하는 <strong>PHP</strong> 프레임워크에 기준 코드 스타일을 제공하는 것이다. PSR-1<br />
과 호환되게 하려면 다음 요구사항들을 준수해야 한다.<br />
● <strong>PHP</strong> 태그<br />
<strong>PHP</strong> 코드를 감쌀 때는 나 만 사용해야 한다. 다른 어떤 <strong>PHP</strong> 태그도 사용해서는 안 된다.<br />
● 인코딩<br />
모든 <strong>PHP</strong> 파일은 반드시 바이트 순서 표식 Byte Order Mark (BOM)이 없는 UTF-8 문자셋으로 인코딩되어 있<br />
어야 한다. 복잡해 보이지만 문서 편집기나 IDE를 이용하면 자동으로 할 수 있다.<br />
● 목적<br />
하나의 <strong>PHP</strong> 파일은 심볼(클래스, 트레이트, 함수, 상수 등)을 정의하거나 부차적인 효과(예: 결과를 출력하<br />
거나 데이터를 조작하는)가 발생하는 기능을 수행한다. 둘 중 한 가지 역할만 해야 한다. 간단한 요건이며 약간<br />
의 예측과 계획만 있으면 준수할 수 있다.<br />
● 오토로딩<br />
<strong>PHP</strong> 네임스페이스와 클래스들은 PSR-4 오토로더 표준을 지원해야 한다. 여러분이 해야 할 일은 이들의<br />
이름을 적절하게 짓고 이들을 정의한 파일을 올바른 위치에 두는 것뿐이다. PSR-4에 대해서는 곧 이야기할<br />
것이다.<br />
● 클래스명<br />
클래스명에는 일반적인 낙타 표기법 CamelCase, 캐멀케이스 을 사용해야 한다. 이 형식은 첫문자 대문자 표기법 TitleCase,<br />
타이틀케이스<br />
라고도 불린다. 예로는 CoffeeGrinder, CoffeeBean, PourOver 등이 있다.<br />
● 상수명<br />
<strong>PHP</strong> 상수명에는 대문자만 사용해야 한다. 필요하다면 단어를 분리하기 위해 밑줄을 사용할 수 있다. 예로는<br />
WOOT, LET_OUR_POWERS_COMBINE, GREAT_SCOTT 등이 있다.<br />
● 메서드명<br />
메서드명에는 소문자로 시작하는 낙타 표기법을 사용해야 한다. 메서드명의 첫 글자는 소문자이고 이어<br />
3장 표준<br />
43
지는 각 단어의 첫 글자는 대문자라는 의미다. 예로는 phpIsAwesome, iLoveBacon, tennantIs<br />
MyFavoriteDoctor 등이 있다.<br />
3.5 PSR-2: 엄격한 코드 스타일<br />
PSR-1을 구현했다면 다음 단계는 PSR-2를 구현하는 것이다. PSR-2 표준은 PSR-1보다 엄<br />
격한 <strong>PHP</strong> 코드 스타일 지침을 정의한다.<br />
PSR-2 코드 스타일은 <strong>PHP</strong> 프레임워크에 내린 신의 선물과도 같다. <strong>PHP</strong> 프레임워크에 기여<br />
하는 전 세계적으로 많은 개발자가 있고 저마다 선호하는 고유한 스타일이 있지만, 엄격한 공<br />
통 코드 스타일로 작성한 코드는 작성자가 아닌 다른 기여자들도 쉽고 빠르게 이해할 수 있다.<br />
PSR-1과는 달리 PSR-2 권장안에는 더 엄격한 지침들이 있다. PSR-2 지침 중 일부는 마음<br />
에 들지 않을 수도 있다. 하지만 PSR-2는 다수의 대중적인 <strong>PHP</strong> 프레임워크가 선호하는 코드<br />
스타일이다. PSR-2를 꼭 사용할 필요는 없다. 하지만 PSR-2를 사용하면 여러분의 코드를 읽<br />
고 사용하고 개선하는 다른 개발자의 생산성이 극적으로 향상된다.<br />
TIP<br />
여러분은 PSR-2 코드 스타일을 사용해야 한다. 엄격하다고는 해도 어렵지 않게 작성할 수 있으며 사용하다<br />
보면 자연스럽게 익숙해질 것이다. 기존 코드를 PSR-2 스타일에 맞게 자동으로 정리해주는 도구들도 있다.<br />
● PSR-1 구현<br />
PSR-1 코드 스타일 구현은 PSR-2 코드 스타일 구현의 선행 조건이다.<br />
● 들여쓰기<br />
통상적으로 두 진영으로 갈리는 뜨거운 주제다. 첫 번째 진영은 단일 탭 문자로 들여쓰는 것을 선호한다. 두 번<br />
째 (좀 더 쿨한) 진영은 공백문자열을 이용하는 것을 선호한다. PSR-2 권장안에 따르면 <strong>PHP</strong> 코드의 들여<br />
쓰기에는 공백문자열 네 개를 사용해야 한다.<br />
TIP<br />
개인적인 경험으로는 공백문자열이 들여쓰기에 더 적당하다. 왜냐하면 공백은 여러 코드 편집기들이 동일하게<br />
표시할 수 있는 확정적인 단위다. 그러나 탭은 코드 편집기마다 너비와 화면 표시가 제각기 다를 수 있다. 코드<br />
의 시각적인 연속성을 최대한 보장하려면 공백문자열 네 개를 이용해 들여쓰도록 하자.<br />
● 파일과 줄<br />
<strong>PHP</strong> 파일은 유닉스 개행문자 LineFeed (LF)를 사용해야 하고 비어 있는 한 줄로 끝나야 하며 마지막에 ?> 태그<br />
가 없어야 한다. 코드의 각 줄은 80글자를 넘기지 않도록 하며 최대 120글자를 넘기면 안 된다. 각 줄의 끝에<br />
는 공백문자가 오면 안 된다. 손이 많이 갈 것 같지만 전혀 그렇지 않다. 대부분의 코드 편집기는 자동으로 특<br />
44 2부 모범 사례
CHAPTER 4<br />
컴포넌트<br />
모던 <strong>PHP</strong>는 단일 프레임워크와 관련이 적고, 상호운용할 수 있는 전문 컴포넌트로 구성한 솔<br />
루션에 더 관련되어 있다. 나 역시 <strong>PHP</strong> 애플리케이션을 새로 만들 때 무작정 라라벨이나 심포<br />
니로 시작하는 경우는 드물다. 그보다는 기존 <strong>PHP</strong> 컴포넌트 중 어떤 것들을 조합하면 문제를<br />
해결할 수 있을지를 먼저 생각해본다.<br />
4.1 컴포넌트를 사용하는 이유<br />
모던 <strong>PHP</strong> 컴포넌트는 많은 <strong>PHP</strong> 프로그래머에게 새로운 개념이다. 나도 몇 년 전까지는 <strong>PHP</strong><br />
컴포넌트를 알지 못했다. 그전까지는 애플리케이션을 만들 때 다른 방법을 고려하지 않은 채<br />
무의식적으로 심포니나 코드이그나이터 같은 거대 프레임워크를 사용했다. 단일 프레임워크의<br />
폐쇄된 생태계에 갇힌 채 프레임워크가 제공해주는 도구를 사용했다. 만약 필요한 기능이 프레<br />
임워크에 없으면 어쩔 수 없이 직접 만들어 추가해야 했다. 맞춤 기능이나 서드파티 라이브러<br />
리를 프레임워크에 통합하는 것도 쉽지 않았다. 이들이 공통 인터페이스를 공유하지 않았기 때<br />
문이다. 다행스럽게도 이제는 더이상 단일 프레임워크와 그 폐쇄적인 환경에 의지할 필요가 없<br />
는 시대가 되었다.<br />
오늘날에는 지속적으로 증가하는 방대한 전문 컴포넌트 중에서 필요한 것만 골라 애플리케<br />
이션 제작에 사용한다. guzzle/http (https://packagist.org/packages/guzzle/http ) 컴포넌<br />
4장 컴포넌트<br />
45
트가 이미 있는데 HTTP 요청, 응답 라이브러리를 코딩하느라 왜 시간을 낭비하는가? aura/<br />
router (https://packagist.org/packages/aura/router )와 orno/route (https://packagist.<br />
org/packages/orno/route)라는 훌륭한 컴포넌트가 있는데 왜 새로운 라우터를 만드는<br />
가? aws/aws-sdk-php(https://packagist.org/packages/aws/aws-sdk-php)와 league/<br />
flysystem (https://packagist.org/packages/league/flysystem) 컴포넌트를 쓸 수 있는데 뭐<br />
하러 시간을 들여 아마존 S3 온라인 스토리지 서비스 어댑터를 코딩하는가? 요점을 말하자면<br />
이렇다. 다른 개발자들이 무수히 많은 시간을 들여 만들고 다듬고 테스트한 전문 컴포넌트들이<br />
이미 있으며, 이런 컴포넌트는 어떤 한 가지 일을 처리하는 데 매우 능숙하다. 이들을 충분히<br />
활용하면 더 나은 애플리케이션을 신속하게 제작할 수 있고 무의미한 일에 시간을 낭비하는 우<br />
를 범하지 않을 수 있다.<br />
4.2 컴포넌트란 무엇인가<br />
컴포넌트는 <strong>PHP</strong> 애플리케이션의 특정 문제를 해결하도록 도와주는 코드 모음이다. 예를 들어<br />
<strong>PHP</strong> 애플리케이션에 HTTP 요청을 주고받는 기능이 필요하다면 그런 기능의 컴포넌트를 사<br />
용하면 된다. 그리고 쉼표(, )로 구분된 데이터를 파싱하거나 로그 메시지를 기록하는 등의 기<br />
능이 필요하다면 각각을 수행하는 컴포넌트 역시 존재하므로 그 컴포넌트를 사용하면 된다. 그<br />
러므로 이미 해결된 기능을 다시 만드는 대신 <strong>PHP</strong> 컴포넌트를 사용함으로써, 프로젝트 본연<br />
의 목적을 달성하는 일에 더 많은 시간을 할애할 수 있다.<br />
기술적으로 말하자면 <strong>PHP</strong> 컴포넌트는 한 가지 문제를 해결하는 데 관련된 클래스, 인터페이스, 트<br />
레이트 모음이다. 컴포넌트를 이루는 클래스, 인터페이스, 트레이트는 보통 동일한 네임스페이스 하위에 있다.<br />
어느 상점이든 좋은 상품과 나쁜 상품이 있듯이 <strong>PHP</strong> 컴포넌트에도 같은 개념이 적용된다. 식<br />
료품점에서 사과를 살펴볼 때처럼 <strong>PHP</strong> 컴포넌트를 볼 때도 좋은 컴포넌트를 알아보기 위한<br />
비결이 있다. 좋은 <strong>PHP</strong> 컴포넌트의 몇 가지 특징은 다음과 같다.<br />
● 목적이 정확하다<br />
<strong>PHP</strong> 컴포넌트는 오직 한 가지 문제를 정밀하게 겨냥하고 이를 능숙하게 처리하기 위해 존재한다. 넓고 얕은<br />
재주를 가진 사람이 아닌 한 분야의 장인인 셈이다. 한 가지 문제를 해결하는 데 온통 사로잡혀 있고, 간결한<br />
46 2부 모범 사례
사용자 인터페이스를 통해 자신의 유능함을 나타낸다.<br />
● 작다<br />
<strong>PHP</strong> 컴포넌트는 필요 이상으로 크지 않다. 컴포넌트가 담고 있는 코드는 한 가지 문제를 해결하기 위해 필요<br />
한 최소한의 양이다. 코드량은 경우에 따라 다른데 <strong>PHP</strong> 컴포넌트에는 <strong>PHP</strong> 클래스가 하나만 있을 수도 있고<br />
서브네임스페이스로 구성된 <strong>PHP</strong> 클래스가 여러 개 있을 수도 있다. <strong>PHP</strong> 컴포넌트에 사용되는 클래스 개수<br />
는 정해져 있지 않다. 그저 문제를 해결할 수 있을 만큼만 사용될 뿐이다.<br />
● 협력적이다<br />
<strong>PHP</strong> 컴포넌트들은 서로 잘 어울린다. 결국 이것이 <strong>PHP</strong> 컴포넌트 존재의 핵심 이유다(다른 컴포넌트들과<br />
협력해 더 큰 솔루션을 구축하는 것이 핵심이다). <strong>PHP</strong> 컴포넌트는 자신의 코드로 전역 네임스페이스를 오염<br />
시키지 않는다. 대신 자신만의 네임스페이스를 구성해 다른 컴포넌트와 이름 충돌을 피한다.<br />
● 충분한 테스트를 거쳤다<br />
<strong>PHP</strong> 컴포넌트는 충분한 테스트를 거쳤는데, 이는 작은 크기 덕분에 갖추게 된 특성이다. 작고 목적이 정확한<br />
<strong>PHP</strong> 컴포넌트는 테스트하기 아주 쉽다. 고려할 것이 적을 뿐만 아니라 목 mock 객체를 통해 의존성을 대체하<br />
기도 쉽다. 최고의 <strong>PHP</strong> 컴포넌트는 자체적으로 테스트를 제공하며 테스트한 범위도 충분하다.<br />
● 문서화 수준이 높다<br />
<strong>PHP</strong> 컴포넌트에는 유용한 문서가 제공된다. 이 문서 덕분에 개발자가 컴포넌트를 쉽게 설치하고 이해하고<br />
사용할 수 있다. <strong>PHP</strong> 컴포넌트에는 컴포넌트의 용도, 설치 방법, 사용 방법이 설명된 README 파일이 있으<br />
며, 컴포넌트 웹 사이트에서 더욱 상세한 정보를 제공하기도 한다. 소스코드 역시 수준 높은 문서화에 포함된<br />
다. 컴포넌트 클래스, 메서드, 속성에는 코드, 인수, 반환값, 발생 가능한 예외에 대해 설명하는 문서블록 docblocks<br />
이 각각 제 위치에 있어야 한다.<br />
4.3 컴포넌트 vs. 프레임워크<br />
(특히 오래된) 프레임워크의 문제는 투자비용이 많이 든다는 점이다. 프레임워크를 선택하는<br />
것은 그 프레임워크의 도구에 투자하는 것과 같다. 프레임워크는 대개 다양한 도구를 뷔페식으<br />
로 제공해준다. 하지만 가끔 프레임워크가 제공하지 않는 특수한 도구가 필요할 때 그에 알맞<br />
는 <strong>PHP</strong> 라이브러리를 찾아내고 통합하는 일은 우리의 몫이 된다. 서드파티 코드를 프레임워<br />
크에 통합하는 일도 쉽지 않다. 서드파티 코드와 <strong>PHP</strong> 프레임워크가 공통 인터페이스를 공유<br />
하지 않기 때문이다.<br />
프레임워크를 선택하는 것은 그 프레임워크의 미래에 투자하는 것과 같은데 이 투자는 프레임<br />
워크 핵심 개발팀에 대한 신뢰를 담보로 한다. 우리는 프레임워크 개발자가 지속적으로 자신의<br />
시간을 투자해 프레임워크를 개발하고, 코드를 최신 표준에 맞게 유지해줄 것으로 기대하지만<br />
4장 컴포넌트<br />
47
이런 기대는 종종 어긋난다. 프레임워크는 매우 방대하고, 유지보수에 많은 시간과 노력이 필<br />
요하다. 프로젝트 관리자에게도 자신만의 삶과 일과 관심사가 있으며, 프레임워크에 들이는 시<br />
간과 노력은 그에 따라 달라지기 마련이다.<br />
공정한 관점에서 보자면 규모가 큰 <strong>PHP</strong> 컴포넌트 역시 버려지고 방치될 위험이 있다. 특히 핵심 개<br />
발자가 한 명일 경우에는 더욱 그렇다.<br />
또한 어떤 프레임워크가 최고의 프레임워크로 남을지는 그 누구도 알 수 없다. 다년간 지속될<br />
큰 프로젝트는 원활한 성능과 균형잡힌 상태를 지금 뿐만 아니라 미래에도 유지해야만 한다.<br />
프레임워크를 잘못 선택하면 이를 보장할 수 없게 되는데 유행에 뒤쳐진 오래된 프레임워크는<br />
커뮤니티의 지원이 끊겨 속도와 사용성이 떨어질 수 있다. 오래된 프레임워크는 보통 최신 객<br />
체지향 코드가 아닌 절차적 코드로 작성됐고, 새로 들어온 팀원은 이런 오래된 프레임워크의<br />
코드베이스에 익숙하지 않을 수도 있다. <strong>PHP</strong> 프레임워크 사용 여부를 결정할 때에는 고려해<br />
야 할 점이 많다.<br />
4.3.1 모든 프레임워크가 나쁜 것은 아니다<br />
지금까지는 프레임워크의 부정적인 면에 대해서 말했지만 프레임워크가 모두 나쁜 것만은 아<br />
니다. 심포니(http://symfony.com/)는 모던 <strong>PHP</strong> 프레임워크의 훌륭한 본보기다. 파비앵 보탱<br />
시에와 센시오랩이 만든 심포니 프레임워크는 작게 분리된 심포니 컴포넌트(http://symfony.<br />
com/components)의 결합체다. 심포니 컴포넌트는 한데 모아 프레임워크로 사용할 수도 있고<br />
맞춤 애플리케이션에 개별적으로 사용할 수도 있다.<br />
그 밖에도 이와 유사하게 모던 <strong>PHP</strong> 컴포넌트로 전환하고 있는 구형 프레임워크가 있다. 콘<br />
텐츠 관리 프레임워크인 드루팔(https://www.drupal.org )이 바로 그 예다. 드루팔 7은 전역<br />
<strong>PHP</strong> 네임스페이스를 사용하며 절차적 <strong>PHP</strong> 코드로 작성됐다. 기존 코드베이스와 하위호환을<br />
유지하기 위해 모던 <strong>PHP</strong> 관행을 무시한다. 하지만 드루팔 8은 모던 <strong>PHP</strong>를 향한 모범적이고<br />
거대한 도약이라 할 수 있다. 드루팔 8은 여러 <strong>PHP</strong> 컴포넌트가 가진 장점들을 극대화해 최신<br />
콘텐츠 관리 플랫폼을 제작하는 데 이용된다.<br />
테일러 오트웰이 제작한 라라벨(http://laravel.com ) 역시 인기 있는 <strong>PHP</strong> 프레임워크다. 심포<br />
48 2부 모범 사례
니처럼 라라벨도 일루미네이트(https://github.com/illuminate )라는 자체적인 컴포넌트 라이<br />
브러리를 기반으로 제작됐다. 하지만 (발표 당시) 라라벨 컴포넌트는 라라벨 이외의 애플리케<br />
이션에 사용하기에는 분리가 쉽지 않았다. 라라벨은 PSR-2 커뮤니티 표준을 사용하지 않으며<br />
유의적 버전 형식(http://semver.org/)을 준수하지 않는다. 하지만 이런 이유로 라라벨 사용을<br />
단념하긴 이르다. 라라벨은 매우 강력한 애플리케이션을 만들 수 있는 뛰어난 프레임워크다.<br />
TIP<br />
TIP<br />
TIP<br />
TIP<br />
TIP<br />
TIP<br />
가장 인기 있는 축에 속하는 모던 <strong>PHP</strong> 프레임워크 목록은 다음과 같다.<br />
● 아우라 Aura (http://auraphp.com/framework)<br />
● 라라벨 Laravel (http://laravel.com/)<br />
● 심포니 Symfony (http://symfony.com/)<br />
● 이 Yii (http://www.yiiframework.com/)<br />
● 젠드 Zend (http://framework.zend.com/)<br />
4.3.2 알맞은 도구를 사용하라<br />
컴포넌트나 프레임워크를 써야 한다면 용도에 맞는 것을 사용하도록 하자. 모던 <strong>PHP</strong> 프레임<br />
워크 대부분은 그저 <strong>PHP</strong> 컴포넌트를 기반으로 만든 관례들을 모아 놓은 것에 지나지 않는다.<br />
<strong>PHP</strong> 컴포넌트들을 정확하게 조합해 해결할 수 있는 소규모 프로젝트를 수행하고자 한다면 컴<br />
포넌트를 사용하면 된다. 컴포넌트를 쓰면 기존 도구를 아주 쉽게 선택하고 사용할 수 있으며,<br />
이로 인해 보일러플레이트 코드 1 에서 눈을 돌려 현재 당면한 큰 작업에 더욱 집중할 수 있게 된<br />
다. 또한 코드를 가볍고 날렵한 상태로 유지할 수 있다. 꼭 필요한 코드 외에는 컴포넌트로 대<br />
체하고, 프로젝트에 더 잘 맞는 다른 컴포넌트가 있다면 아주 쉽게 교체할 수 있다.<br />
여러 팀원과 함께 큰 프로젝트를 수행하고 있으며 프레임워크가 제공하는 관례, 규율, 구조로<br />
부터 이득을 취할 수 있다면 프레임워크를 사용하면 된다. 프레임워크는 사용자를 대신해 많은<br />
결정을 내리는 한편 프레임워크가 지닌 일련의 관례를 준수할 것을 요구한다. 프레임워크는 유<br />
연성이 떨어지긴 하지만 <strong>PHP</strong> 컴포넌트를 조합해서 할 수 있는 것과는 완전히 다른 수준의 일<br />
을 할 수 있다. 이런 장단점을 받아들일 수 있다면 프로젝트 개발을 이끌고 가속시키기 위해 얼<br />
마든지 프레임워크를 사용해도 좋다.<br />
1 역자주_ 기능은 간단하지만 분량이 많은 코드다.<br />
4장 컴포넌트<br />
49
4.4 컴포넌트 선택<br />
모던 <strong>PHP</strong> 컴포넌트는 패키지스트 Packagist (https://packagist.org ) (그림 4-1 )에서 찾을 수 있<br />
다. 패키지스트는 사실상 <strong>PHP</strong> 컴포넌트 디렉터리며 <strong>PHP</strong> 컴포넌트를 망라하고 키워드 검색<br />
기능을 제공한다. 최고의 <strong>PHP</strong> 컴포넌트들이 패키지스트에 수록되어 있으며 이토록 귀중한 커<br />
뮤니티 자원을 창조해낸 요르디 보기아노(http://seld.be/)와 이고르 비들러(https://igor.io/<br />
archive.html)에게 고개 숙여 감사한다.<br />
TIP<br />
어떤 컴포넌트가 최고의 <strong>PHP</strong> 컴포넌트라고 생각하냐는 질문을 종종 받는다. 사람마다 다르겠지만 나는 어섬<br />
<strong>PHP</strong>(https://github.com/ziadoz/awesome-php)에 수록된 컴포넌트 목록에 대체로 동의한다. 이 목록<br />
에는 제이미 요크(https://github.com/ziadoz)가 추천하는 좋은 컴포넌트들이 수록되어 있다.<br />
그림 4-1 패키지스트 웹 사이트<br />
4.4.1 쇼핑<br />
이미 해결된 문제를 다시 해결하려고 시간을 낭비하지 말자. HTTP 메시지를 주고받아야 하는<br />
가? 패키지스트에서 http로 검색해서 제일 먼저 나오는 거즐 Guzzle 을 사용하라. CSV 파일을 파<br />
50 2부 모범 사례
CHAPTER 5<br />
모범 사례<br />
이번 장에는 <strong>PHP</strong> 애플리케이션을 만들 때 적용해야 할 모범 사례를 모아놓았다. 모범 사례를<br />
따르면 더욱 빠르고 안정적이며 보안에 강한 애플리케이션을 만들 수 있다. <strong>PHP</strong> 언어에는 개<br />
별적으로 도입된 도구들이 오랜 시간에 걸쳐 축적되었고, 이런 도구들은 모범 사례를 적용하는<br />
데 사용된다. 시간이 가면 갈수록 점점 더 새롭고 우수한 도구들이 모던 <strong>PHP</strong> 버전에 도입될<br />
것이다. 불행히도 <strong>PHP</strong> 언어는 여전히 과거에 도입된 구식 도구를 포함하고 있어서, 주의하지<br />
않으면 이런 낡은 도구로 느리고 보안에 취약한 애플리케이션을 만들게 될 수 있다. 그런 애플<br />
리케이션을 만들지 않으려면 사용할 도구와 무시할 도구를 알아두어야 하는데, 이번 장에서는<br />
그에 대해 다뤄보겠다.<br />
나는 현실과 동떨어진 상아탑 꼭대기에 앉아 ‘모범 사례’를 설파하지는 않을 것이다. 이번 장에<br />
는 내가 모든 프로젝트에서 매일같이 활용하는 유용하고 실용적인 조언이 담겨 있다. 여러분은<br />
이 지식을 여러분의 프로젝트에 바로 적용할 수 있다.<br />
이번 장에 나오는 모범 사례들은 현재 <strong>PHP</strong> 버전에서만이 아니라 이전 버전들에서도 언제든 구현<br />
할 수 있었다. 하지만 이런 사례를 구현하는 방법은 <strong>PHP</strong> 언어가 발전함에 따라 함께 변화한다. 모던 <strong>PHP</strong> 버<br />
전에 도입된 도구들을 사용하면 모범 사례를 좀 더 쉽게 적용할 수 있다. 이번 장에서는 <strong>PHP</strong> 5.3+에 도입된<br />
최신 도구들을 이용해 모범 사례를 적용하는 방법을 실습해본다.<br />
5장 모범 사례<br />
51
5.1 위험 제거, 유효성 검사, 예외 처리<br />
TV 드라마 《엑스 파일 The X-Files 》의 남자 주인공 멀더는 “아무도 믿지 말라”는 말을 종종 하곤했<br />
다. 프로그램 세계에서도 자신이 직접 통제하는 출처로부터 나온 데이터가 아니라면 그 어떤<br />
데이터도 절대 믿으면 안 된다. 다음과 같은 몇몇 외부 출처들이 있다.<br />
● $_GET<br />
● $_POST<br />
● $_REQUEST<br />
● $_COOKIE<br />
● $argv<br />
● php://stdin<br />
● php://input<br />
● file_get_contents()<br />
● 원격 데이터베이스<br />
● 원격 API<br />
● 고객의 데이터<br />
이 모든 외부 데이터 출처는 여러분의 스크립트로 악의적인 데이터를 주입할 수 있는(고의든<br />
우연이든) 잠재적 침입 경로다. 사용자 입력을 받고 결과를 출력하는 스크립트는 쉽게 작성할<br />
수 있다. 하지만 그러한 일을 안전하게 수행하는 스크립트를 작성하기 위해서는 고민이 약간<br />
더 필요하다. 가장 단순하게 충고한다! 입력값의 위험을 제거하고 데이터의 유효성을 검사하고<br />
출력을 예외 처리하라.<br />
5.1.1 입력값 위험 제거<br />
입력값(예: 앞선 목록에 있는 출처로부터 나온 데이터)의 위험을 제거하면 안전하지 않은 문<br />
자가 예외 처리되거나 제거된다. 입력 데이터가 애플리케이션 저장소 계층(예: 레디스 Redis 나<br />
MySQL)에 도달하기 전에 위험을 제거하는 것이 중요하다. 이것이 첫 번째 방어선이다. 예를<br />
들어 여러분의 웹 사이트 댓글란에 HTML이 허용된다고 가정해보자. 기본적으로 방문자가 다<br />
음과 같은 악성 태그를 댓글 내용에 포함시키는 것을 막을 방법이 없다.<br />
52 2부 모범 사례
유용한 게시물입니다!<br />
<br />
window.location.href ='http://example.com';<br />
이 댓글의 위험을 제거하지 않으면 악의적인 코드가 데이터베이스에 주입되고 웹 사이트 마크<br />
업으로 출력될 수 있다. 웹 사이트 방문자가 이 댓글이 있는 페이지에 들어가면 유해한 웹 사이<br />
트로 이동하게 된다. 이런 불상사는 자신의 통제 범위 밖에 있는 입력 데이터의 위험을 왜 제거<br />
해야만 하는지 알려주는 단편적인 예시다. 내 경험상 가장 자주 접하는 입력 데이터는 HTML,<br />
SQL 쿼리, 사용자 정보(예: 이메일 주소, 전화번호)다.<br />
HTML<br />
HTML 특수문자(예: &, >, ″)는 htmlentities() 함수(http://php.net/manual/func<br />
tion.htmlentities.php)를 이용해서 각각에 해당하는 HTML 엔티티로 교체한다(예제 5-1 ).<br />
이 함수는 대상 문자열에 있는 모든 HTML 문자를 예외 처리하고 애플리케이션 저장소 계층에<br />
안전한 문자열로 변환한다.<br />
하지만 htmlentities ( ) 함수는 우둔하다. HTML 입력을 검증하지 않으며 기본적으로<br />
홑따옴표를 예외 처리하지 않는다. 입력 문자열의 문자 집합을 검출하지도 못한다. html<br />
entities() 함수를 사용하는 올바른 방법이 [예제 5-1]에 있다. 첫 번째 인수는 입력 문자열<br />
이다. 두 번째 인수는 ENT_QUOTES 상수며 홑따옴표를 인코딩하도록 지시한다. 세 번째 인수로<br />
는 입력 문자열의 문자 집합을 명시한다.<br />
예제 5-1 htmlentities( ) 함수로 입력 위험 제거하기<br />
preg_replace_all(), preg_replace_callback(), preg_replace() 등의 정규<br />
표현식 함수로 HTML의 위험을 제거하지 않도록 하자. 정규표현식은 복잡하며 입력 HTML이 유효하지 않<br />
을 수도 있기 때문에 오류가 발생할 위험이 높다.<br />
SQL 쿼리<br />
입력 데이터에 기반해서 쿼리를 만들어야 할 때가 있다. 어떤 경우는 HTTP 요청 쿼리 문자열<br />
이 입력 데이터로 사용된다(예: ?user=1 ). 또 어떤 경우는 HTTP 요청 URI의 일부분이 입력<br />
데이터로 사용된다(예: /users/1). 주의를 기울이지 않으면 악당들이 고의적으로 SQL 쿼리<br />
를 망가뜨려 데이터베이스에 엄청난 피해를 입힐 수도 있다. 일례로 나는 [예제 5-2]처럼 $_<br />
GET과 $_POST 데이터를 입력받은 그대로 이어붙여 SQL 쿼리를 만드는 초급 <strong>PHP</strong> 개발자들을<br />
많이 보았다.<br />
예제 5-2 나쁜 SQL 쿼리<br />
$sql = sprintf(<br />
'UPDATE users SET password = "%s" WHERE id = %s',<br />
);<br />
$_POST['password'],<br />
$_GET['id']<br />
이런 방식은 나쁘다! 만약 누군가가 다음과 같은 HTTP 요청을 <strong>PHP</strong> 스크립트로 보내면 어떻<br />
게 될까?<br />
POST /user?id=1 HTTP/1.1<br />
Content-Length: 17<br />
Content-Type: application/x-www-form-urlencoded<br />
password=abc";- -<br />
이 HTTP 요청으로 인해 모든 사용자의 비밀번호가 abc로 바뀌게 된다. 많은 SQL 데이터베이<br />
스가 --를 주석의 시작으로 간주하고 그 뒤에 이어지는 문자열을 무시하기 때문이다. 위험이<br />
제거되지 않은 입력 데이터는 절대 SQL 쿼리에서 사용하면 안 된다. 만약 SQL 쿼리에 입력<br />
54 2부 모범 사례
데이터를 합쳐야 한다면 준비된 PDO문을 사용하자. PDO는 <strong>PHP</strong>에 내장된 데이터베이스 추<br />
상화 계층이며 복수 데이터베이스를 단일 인터페이스로 나타낸다. 준비된 PDO문은 SQL 쿼<br />
리에 삽입될 외부 데이터의 위험을 제거하고 안전을 확보해 [예제 5-2]와 같은 문제를 방지하<br />
는 PDO 도구다. 나는 PDO와 PDO문을 극단적으로 중요한 도구라 여기기에 이들에 대해서<br />
는 이번 장에서 나중에 따로 다룰 것이다.<br />
사용자 정보<br />
애플리케이션에 사용자 계정과 관련된 기능이 있다면 이메일 주소, 전화번호, 우편번호 같은<br />
사용자 신상 정보와 맞딱뜨릴게 될 것이다. <strong>PHP</strong>는 filter_var()와 filter_input() 함수<br />
로 이런 시나리오에 대비한다. 이 두 함수는 여러 입력 형식을 나타내는 다양한 플래그를 입력<br />
받아 위험을 제거한다. 이런 형식에는 이메일, 인코딩된 URL 문자열, 정수, 실수, HTML 문자<br />
열, URL, 아스키 ASCII 문자 범위 등이 있다.<br />
[예제 5-3]은 이메일 주소에서 문자열, 숫자, !#$%&'*+-/=?^_`{|}~@.[]를 제외한 모<br />
든 글자를 제거하는 방법을 보여준다.<br />
예제 5-3 사용자 이메일 주소 위험 제거<br />
서 찾아볼 수 있다.<br />
더 많은 filter_var() 플래그와 옵션은 http://php.net/manual/function.filter-var.php에<br />
5.1.2 유효성 검사<br />
데이터의 유효성을 검사하는 일도 중요하다. 위험 제거와 달리 유효성 검사는 입력 데이터에<br />
서 정보를 제거하지 않는다. 유효성 검사는 오직 입력 데이터가 요구 조건에 맞는지만 확인한<br />
다. 이메일 주소를 기대했다면 입력 데이터가 이메일 주소가 맞는지 확인하고, 전화번호를 기<br />
대했다면 데이터가 전화번호인지 확인한다. 딱 거기까지만이다. 유효성 검사는 애플리케이션<br />
저장소 계층이 정확하고 양식화된 정보를 저장할 수 있도록 보장한다. 만일 부적절한 데이터<br />
를 발견하면 데이터 저장 작업을 중단하고 애플리케이션 사용자에게 적절한 오류 메시지를 노<br />
출한다. 또한 유효성 검사는 잠재적인 데이터베이스 오류를 방지한다. 예를 들어 MySQL에<br />
DATETIME을 입력해야 할 상황에서 next year라는 문자열을 입력하면 MySQL은 오류를 내거<br />
나 기본(부정확한)값을 사용할 것이다. 두 경우 모두 부적절한 데이터로 인해 애플리케이션의<br />
데이터 무결성이 위협받는다.<br />
filter_var () 함수에 FILTER_VALIDATE_* 플래그를 써서 사용자 입력의 유효성을 검사할<br />
수 있다. <strong>PHP</strong>는 불리언, 이메일, 실수, 정수, IP 주소, 정규표현식, URL 등을 검사할 수 있는<br />
플래그를 제공한다. [예제 5-5]는 이메일 주소의 유효성을 검사하는 방법을 보여준다.<br />
예제 5-5 이메일 주소 유효성 검사<br />
CHAPTER 6<br />
호스팅<br />
이제 여러분에게는 <strong>PHP</strong> 애플리케이션이 있다. 축하할 일이긴 하지만, 여러분도 알다시피 사<br />
용자가 없는 애플리케이션은 그 누구에게도 어떠한 도움도 주지 못한다. 여러분은 애플리케이<br />
션을 서버에 올리고 애플리케이션을 사용할 사람들에게 열어주어야 한다. 일반적으로 <strong>PHP</strong> 애<br />
플리케이션은 네 가지 방법으로 호스팅할 수 있다. 공유 서버, 가상 사설 서버, 전용 서버, 서비<br />
스로서의 플랫폼(PaaS)이다. 이들은 저마다 나름대로 이점이 있으므로 다양한 애플리케이션<br />
종류와 예산에 맞춰 사용할 수 있다.<br />
웹 호스팅 업체 역시 많아서, 이 방면에 경험이 없는 이들에게는 업체 선택이 난감할 수도 있을<br />
것이다. 호스팅 업체 중에는 공유 서버만 제공하는 업체가 있는가 하면 공유 서버, 가상 사설<br />
서버, 전용 서버를 혼합해서 제공하는 업체도 있다. 이번 장에서는 호스팅 업체보다는 호스팅<br />
방식에 좀 더 초점을 맞춰볼 것이다.<br />
6.1 공유 서버<br />
공유 서버는 가장 저렴한 호스팅 방식으로 비용은 월 1만 원대부터 있다. 공유 호스팅 방식은<br />
피하도록 하자. 공유 호스팅 제공 업체의 고객 지원이나 서비스 품질 때문이 아니다. 좋은 공유<br />
호스팅 업체는 많지만 공유 호스팅 방식 자체가 별로 개발자 친화적이지 않기 때문이다. 이름<br />
에서 알 수 있듯이 공유 서버는 다른 사람들과 자원을 공유하는 서버를 의미한다. 공유 호스팅<br />
방식을 구매하면 여러분은 동일한 물리적 장비를 많은 고객과 함께 쓰게 된다. 만약 이 장비의<br />
6장 호스팅<br />
57
메모리가 2GB로 한정되어 있다면 여러분의 <strong>PHP</strong> 애플리케이션은 같은 장비를 사용하는 고객<br />
수에 따라 전체 메모리 중 일부만 할당받게 된다. 만약 동일한 장비를 쓰는 다른 계정에서 형편<br />
없는 스크립트를 실행하면 그 결과로 인한 나쁜 영향이 여러분의 애플리케이션에 미칠 수도 있<br />
다. 일부 공유 호스팅 업체는 공유 서버를 과도하게 운영하기도 하는데, 이런 호스팅을 이용하<br />
는 <strong>PHP</strong> 애플리케이션은 혼잡한 시스템 속에서 자신의 자원을 확보하기 위해 끊임없이 전쟁을<br />
치러야 한다.<br />
공유 서버는 사용자가 원하는 대로 설정하기에는 매우 어렵다. 어쩌면 여러분의 애플리케이션<br />
에 멤캐시드(http://memcached.org)나 레디스(http://redis.io) 같은 고속 메모리 캐시가 필<br />
요하게 될 수도 있고, 검색 기능을 향상하기 위해 엘라스틱서치(http://www.elasticsearch.<br />
org )를 설치해야 할 상황이 생길 수도 있다. 하지만 불행히도 공유 서버 소프트웨어로는 이런<br />
일들을 마음대로 하기 어렵고, 아예 불가능할 수도 있다. 결과적으로는 애플리케이션이 감당해<br />
야 할 몫만 커지게 된다.<br />
공유 서버는 보통 원격 SSH 접속을 허용하지 않는다. 그 대신 (S)FTP 접속만 제한적으로 허<br />
용하곤 한다. 이런 제약 조건은 <strong>PHP</strong> 애플리케이션 배포 자동화 작업을 심각하게 제한한다.<br />
예산이 아주 적다거나 여러분의 요구 조건이 극히 사소하다면 공유 서버만으로도 충분할 수도<br />
있다. 그러나 상업적인 웹 사이트 혹은 어느 정도 대중적인 <strong>PHP</strong> 애플리케이션을 구축하려 한<br />
다면 가상 사설 서버, 전용 서버, PaaS를 이용하는 편이 더 낫다.<br />
6.2 가상 사설 서버<br />
가상 사설 서버(VPS)는 보기에는 마치 단독 서버 1 처럼 작동하지만 알고 보면 단독 서버가 아<br />
니다. VPS는 단일 혹은 여러 물리적 장비에 걸쳐 분산된 시스템 자원 집합이다. VPS에는 자신<br />
만의 파일시스템, 루트 사용자, 시스템 프로세스, IP 주소가 있다. VPS는 지정된 메모리 용량,<br />
CPU, 대역폭을 할당받으며 여러분은 이런 자원을 온전히 사용할 수 있다.<br />
VPS는 공유 서버보다 더 많은 시스템 자원을 제공한다. SSH를 통해 루트 계정으로 VPS에 접<br />
근할 수 있고 제한 없이 소프트웨어를 설치할 수 있지만, 큰 힘에는 큰 책임이 따르는 법이다.<br />
1 역자주_ 베어메탈 서버 bare-metal server 를 의미하지만 여기서는 분산된 가상 서버의 상대적인 개념이라서 단독 서버로 번역했다.<br />
58 3부 배포, 테스팅, 튜닝
VPS는 순정 운영체제에 대한 루트 접근 권한을 제공하며 여러분은 직접 운영체제를 구성하고<br />
안전하게 관리해야 한다. VPS는 <strong>PHP</strong> 애플리케이션 대부분에 이상적인 환경이다. 충분한 시<br />
스템 자원(예: CPU, 메모리, 디스크 용량)을 제공하며 필요에 따라 규모를 늘리거나 줄일 수<br />
있다. VPS는 <strong>PHP</strong> 애플리케이션에 필요한 시스템 자원에 따라 월 1만 원에서 10만 원 가량의<br />
비용이 든다. <strong>PHP</strong> 애플리케이션의 인기가 엄청나게 올라가(월 방문자 수가 수십만 단위 이<br />
상) VPS에 너무 많은 비용이 들어가게 되면 전용 서버로 업그레이드를 고려해봐야 한다.<br />
TIP<br />
VPS를 쓰면 비용, 기능, 유연성 사이에 균형을 조절할 수 있어서 나는 거의 VPS를 선호한다. 내가 애용하는<br />
호스팅 업체는 VPS와 전용 호스팅 방식을 제공하는 리노드(https://linode.com)다. 리노드가 최저가의 업<br />
체는 아니지만 내 경험에 의하면 빠르고 안정적이며, 값진 보물처럼 유용한 튜토리얼을 함께 제공한다.<br />
6.3 전용 서버<br />
전용 서버는 호스팅 업체가 사용자를 대신해 설치, 운영, 관리하는 랙 장착 장비로, 사용자<br />
가 원하는 정확한 사양에 맞춰 구성된다. 전용 서버는 운반, 설치, 관제가 필요한 실제 장비라<br />
VPS만큼 신속하게 구성할 수는 없다. 하지만 전용 서버를 사용하면 <strong>PHP</strong> 애플리케이션에 필<br />
요한 궁극적인 성능을 낼 수 있다.<br />
전용 서버는 VPS와 비슷하게 움직인다. 여러분은 SSH를 통해 순정 운영체제에 루트 계정으로<br />
접속하며, <strong>PHP</strong> 애플리케이션에 맞게 운영체제를 설정하고 단속해야 한다. 전용 서버는 비용<br />
대비 효율성 면에서 유리하다. VPS는 시스템 자원 소모가 늘어남에 따라 결과적으로 비용이<br />
너무 많이 든다. 이럴 경우에는 전용 인프라를 직접 구축하는 편이 비용을 더 절감할 수 있다.<br />
전용 서버에 소요되는 비용은 매월 수십만 원 정도며 사양에 따라 다르다. 전용 서버에는 비관<br />
리(즉, 여러분이 직접 관리하는) 서버와 관리(즉, 추가 비용을 내고 호스팅 업체에서 관리하<br />
는) 서버가 있다.<br />
6.4 PaaS<br />
서비스로서의 플랫폼(PaaS, 파스)은 <strong>PHP</strong> 애플리케이션을 신속하게 실행할 수 있는 수단이<br />
며, 가상 사설 서버나 전용 서버와는 달리 여러분이 직접 관리할 필요가 없다. 여러분은 그저<br />
6장 호스팅<br />
59
PaaS 공급 업체의 제어판에 로그인하고 버튼을 몇 개 클릭하기만 하면 된다. 일부 PaaS 공급<br />
업체는 <strong>PHP</strong> 애플리케이션을 배포하고 관리할 수 있도록 명령행 혹은 HTTP API를 제공한다.<br />
다음은 많이 알려진 <strong>PHP</strong> PaaS 공급 업체들이다.<br />
● 앱포그 AppFog (https://www.appfog.com/)<br />
● AWS 엘라스틱 빈스토크 AWS Elastic Beanstalk (http://aws.amazon.com/elasticbeanstalk/)<br />
● 엔진 야드 Engine Yard (https://www.engineyard.com/products/cloud)<br />
● 포트래빗 Fortrabbit (http://fortrabbit.com/)<br />
● 구글 앱 엔진 Google App Engine (http://bit.ly/g -app-engine)<br />
● 헤로쿠 Heroku (https://devcenter.heroku.com/categories/php)<br />
● 마이크로소프트 애저 Microsoft Azue (http://www.windowsazure.com/)<br />
● 파고다 박스 Pagoda Box (https://pagodabox.com/)<br />
● 레드햇 오픈시프트 Red Hat OpenShift (http://openshift.com/)<br />
● 젠드 개발자 클라우드 Zend Developer Cloud (http://bit.ly/z-dev-cloud)<br />
PaaS 가격 정책은 공급 업체에 따라 다양하지만 가상 사설 서버와 비슷한 월 1만 원~10만 원<br />
선이다. <strong>PHP</strong> 애플리케이션에 할당된 시스템 자원에 대한 비용을 지불하며 필요에 따라 시스<br />
템 자원 규모를 늘리거나 줄일 수 있다. 서버를 직접 관리하고 싶지 않은 개발자들에게는 PaaS<br />
호스팅 방식을 추천한다.<br />
6.5 호스팅 선택<br />
호스팅은 시기와 용도에 맞게 적절히 선택하면 된다. 여러분은 언제든지 필요에 따라 호스팅<br />
인프라의 규모를 키우거나 줄일 수 있다. 소형 <strong>PHP</strong> 애플리케이션이나 프로토타입에는 엔진<br />
야드 또는 헤로쿠 같은 PaaS 공급 업체를 통한 호스팅이 가장 적당하고 빠르다. 서버 구성을<br />
좀 더 제어하고 싶다면 VPS를 이용하면 된다. 여러분의 애플리케이션이 엄청나게 인기를 끌고<br />
VPS가 수백만 명의 방문자로 휘청거리게 된다면(일단 축하부터 하고), 전용 서버를 이용하도<br />
록 하자. 어떤 호스팅 방식을 선택하든 모던 <strong>PHP</strong> 버전과 더불어 여러분의 <strong>PHP</strong> 애플리케이션<br />
에 필요한 확장을 제공해주는지 꼭 확인하도록 한다.<br />
60 3부 배포, 테스팅, 튜닝
CHAPTER 7<br />
프로비저닝<br />
애플리케이션 호스트를 선택했으니 이제 <strong>PHP</strong> 애플리케이션을 올릴 서버를 설정하고 프로비<br />
전할 차례다. 솔직히 말하면 프로비저닝은 과학적인 이론이라기보다는 예술적인 기교에 가깝<br />
다. 서버를 프로비전하는 방법은 전적으로 애플리케이션이 무엇을 필요로 하는가에 달려 있다.<br />
PaaS를 이용하는 경우에는 PaaS 공급 업체가 서버 인프라를 관리하기 때문에 PaaS 공급 업체의<br />
지시에 따라 <strong>PHP</strong> 애플리케이션을 PaaS 플랫폼으로 옮기기만 하면 모든 준비가 끝난다.<br />
PaaS를 사용하지 않는다면 <strong>PHP</strong> 애플리케이션을 실행할 VPS 혹은 전용 서버를 프로비전해야<br />
만 한다. 서버 프로비저닝은 용어 자체가 주는 느낌만큼 어려운 작업은 아니지만(웃지 말 것),<br />
명령행에 어느 정도 익숙한 사람이어야 수행할 수 있는 작업이다. 도무지 명령행에 적응을 못<br />
하겠다면 엔진 야드나 헤로쿠 같은 PaaS를 이용하는 편이 더 낫다.<br />
나는 시스템 관리자를 자처하지는 않는다. 하지만 기초적인 시스템 관리는 애플리케이션 개발<br />
자에게 대단히 가치 있는 능력이며, 애플리케이션 개발 과정이 더 유연하고 탄탄하게 진행될<br />
수 있도록 뒷받침해준다. 이번 장에서 나는 여러분이 <strong>PHP</strong> 애플리케이션 서버를 프로비전할<br />
때 마음 편하게 터미널을 열 수 있도록 나의 시스템 관리 지식을 공유해줄 것이다. 또한 말미에<br />
는 여러분이 시스템 관리 스킬을 계속해서 향상하는 데 도움이 될 만한 몇 가지 추가적인 참고<br />
자료도 추천해줄 것이다.<br />
7장 프로비저닝<br />
61
이번 장에서 나는 여러분이 (거의 모든 리눅스 배포판에서 사용 가능한) 나노(http://www.nanoeditor.org)나<br />
빔(http://www.vim.org) 같은 명령행 편집기 사용법을 알고 있다고 간주하겠다. 명령행 편<br />
집기가 아니라면 다른 방법을 통해서라도 서버에 있는 텍스트 파일을 수정할 수 있어야 한다.<br />
7.1 목표<br />
우선 가상 사설 서버 혹은 전용 서버를 준비한다. 다음으로는 HTTP 요청을 수신할 웹 서버를<br />
설치해야 한다. 마지막으로 웹 서버와 통신하며 <strong>PHP</strong> 요청을 처리할 <strong>PHP</strong> 프로세스 그룹을 구<br />
성하고 관리해야 한다.<br />
몇 년 전까지만 해도 아파치 웹 서버와 아파치 mod_php 모듈을 설치하는 방식이 일반적이었<br />
다. 아파치 웹 서버는 각 HTTP 요청을 처리할 고유한 자식 프로세스를 생성하고, 아파치 mod_<br />
php 모듈은 각 자식 프로세스(설령 자바스크립트, 이미지, 스타일시트 같은 정적 자산만 제공<br />
하는 프로세스라 해도)에 고유한 <strong>PHP</strong> 인터프리터를 배정한다. 이런 방식은 시스템 자원이 과<br />
하게 낭비되는 결과를 낳는다. 이제는 이보다 더 효율적인 방법이 있기 때문에, 아파치를 쓰는<br />
<strong>PHP</strong> 개발자가 점점 줄고 있다.<br />
요즘에는 엔진엑스(http://nginx.org/) 웹 서버를 사용하며, 이를 <strong>PHP</strong>-FPM 프로세스 집합<br />
전방에 배치하며 <strong>PHP</strong> 요청을 전달하게 한다. 이런 구성 방식을 이번 장에서 실습해볼 것이다.<br />
7.2 서버 설정<br />
먼저 가상 사설 서버(VPS)를 설정해보자. 나는 리노드(http://linode.com/)를 정말로 좋아한<br />
다. 리노드는 최저가 VPS 공급 업체는 아니지만 가장 신뢰할 만한 업체 중 하나다. 리노드 웹<br />
사이트(혹은 선호하는 공급 업체)에 들어가 VPS를 새로 구입하고 신규 서버에 설치될 리눅스<br />
배포판과 서버 루트 비밀번호를 결정하자.<br />
TIP<br />
리노드(http://linode.com/)나 디지털 오션(https://www.digitalocean.com)을 포함한 많은 VPS 공급<br />
62 3부 배포, 테스팅, 튜닝
업체는 시간 단위로 비용을 청구한다. 이 말은 사실상 전혀 비용을 들이지 않고도 VPS를 다뤄볼 수 있다는<br />
의미다.<br />
7.2.1 최초 로그인<br />
우선 신규 서버에 로그인부터 해야 한다. 지금 당장 해보자. 로컬 장비에서 터미널을 열고 다음<br />
ssh 명령을 실행해 서버에 접속한다. IP 주소는 여러분의 서버에 맞게 바꾸도록 한다.<br />
ssh root@123.456.78.90<br />
신규 서버에 처음 접속할 때에는 다음과 같은 호스트 진위를 확인하는 메시지가 표시될 수도<br />
있다. yes를 입력하고 를 누른다.<br />
The authenticity of host '123.456.78.90 (123.456.78.90)' can't be established.<br />
RSA key fingerprint is 21:eb:37:f3:a5:d3:c0:77:47:c4:15:3d:3c:dc:3c:d1.<br />
Are you sure you want to continue connecting (yes/no)?<br />
다음으로 아래 같은 메시지가 나오면 루트 사용자의 비밀번호를 입력하고 를 누른다.<br />
root@123.456.78.90's password:<br />
이제 신규 서버에 최초 로그인을 완료했다!<br />
7.2.2 소프트웨어 업데이트<br />
바로 이어서 운영체제 소프트웨어를 업데이트하기 위해 다음 명령을 실행한다.<br />
# 우분투<br />
apt-get update;<br />
apt-get upgrade;<br />
# CentOS<br />
yum update<br />
7장 프로비저닝<br />
63
이 명령을 실행하면 운영체제 소프트웨어 업데이트를 내려받고 적용하는데, 그에 따라 상당히<br />
많은 정보가 쏟아져 나온다. 이 과정은 운영체제 기본 소프트웨어에 최신 업데이트와 보안 픽<br />
스 security fixes 를 적용하는 중요한 첫 번째 단계다.<br />
7.2.3 비루트 사용자<br />
신규 서버는 안전하지 않다. 신규 서버 보안을 강화하기 위한 몇 가지 좋은 관행이 있는데, 우<br />
선 루트가 아닌 일반 사용자를 생성해야 한다. 여러분은 앞으로 이 일반 사용자로 서버에 로그<br />
인해야 한다. 루트 사용자는 서버를 무제한적으로 다룰 권한이 있는 신과 같은 존재며, 어떤 명<br />
령이라도 이의 없이 실행할 수 있다. 여러분은 루트 사용자의 서버 접근을 가능한 한 어렵게 만<br />
들어야 한다.<br />
우분투<br />
[예제 7-1]을 실행해 deploy라는 이름으로 새로운 사용자를 생성한다. 요청에 따라 사용자 비<br />
밀번호를 입력하고 나머지는 화면에 나오는 지시를 따른다.<br />
예제 7-1 우분투에서 비루트 사용자 생성<br />
adduser deploy<br />
그리고 다음 명령을 실행해 deploy 사용자를 sudo 그룹에 할당한다.<br />
usermod -a -G sudo deploy<br />
위 명령은 deploy 사용자에 sudo 권한을 부여한다(즉, 특수한 권한이 필요한 작업을 비밀번호<br />
인증을 통해 수행할 수 있다).<br />
CentOS<br />
다음 명령을 실행해 deploy라는 이름으로 새로운 사용자를 생성한다.<br />
64 3부 배포, 테스팅, 튜닝
adduser deploy<br />
다음 명령으로 deploy 사용자에 비밀번호를 지정한다. 요청에 따라 사용자 비밀번호를 입력하<br />
고 확인을 위해 다시 한 번 입력한다.<br />
passwd deploy<br />
그리고 다음 명령을 실행해 deploy 사용자를 wheel 그룹에 할당한다.<br />
usermod -a -G wheel deploy<br />
위 명령은 deploy 사용자에 sudo 권한을 부여한다(즉, 특수한 권한이 필요한 작업을 비밀번호<br />
인증을 통해 수행할 수 있다).<br />
7.2.4 SSH 키 쌍 인증<br />
로컬 장비에서 다음 명령을 실행해 deploy 사용자로 신규 서버에 로그인 할 수 있다.<br />
ssh deploy@123.456.78.90<br />
deploy 사용자의 비밀번호를 입력하라는 요청에 응답하면 서버로 로그인하게 된다. 로그인 과<br />
정을 더욱 안전하게 보호하기 위해 비밀번호 인증을 비활성화시킬 수도 있다. 비밀번호 인증<br />
은 무차별 대입 공격에 취약하다. 무차별 대입 공격이란 타인의 비밀번호를 알아내기 위해 비<br />
밀번호를 바꿔가며 연속적으로 인증을 시도하는 행위다. ssh 서버 접속 시 비밀번호 인증 대신<br />
SSH 키 쌍 인증을 사용해 이런 위협을 방지한다.<br />
키 쌍 인증은 복잡한 주제지만 기본적인 정의는 다음과 같다. 여러분은 로컬 장비에 한 쌍의 키<br />
를 만들 수 있는데 이 중 하나는 (로컬 장비에 저장되는) 개인 키며 다른 하나는 (원격 서버에<br />
저장되는) 공개 키다. 공개 키로 암호화된 메시지는 오직 그에 맞는 개인 키로만 복호화할 수<br />
있고 이들을 키 쌍이라 부른다.<br />
SSH 키 쌍 인증을 이용한 접속 과정은 다음과 같다. 원격 장비로 ssh 접속을 시도하면 원격 장<br />
비는 임의의 메시지를 생성하고 공개 키로 암호화한 다음 로컬 장비로 전송한다. 로컬 장비에<br />
7장 프로비저닝<br />
65
서는 개인 키를 사용해 메시지를 해독하고 이 메시지를 원격 서버로 반환한다. 원격 서버는 반<br />
환된 메시지가 유효한지 검사한 다음 서버 접속을 승인하게 된다. 상당히 개략적인 설명이긴<br />
하지만 요점은 파악할 수 있을 것이다.<br />
원격 서버로 로그인하는 컴퓨터가 많을 때는 SSH 키 쌍 인증을 사용하기 어려울지도 모른다.<br />
모든 로컬 컴퓨터에서 공개/개인 SSH 키 쌍을 생성하고 각 컴퓨터의 공개 키를 원격 서버로 복<br />
사해야 하기 때문이다. 이런 경우에는 비밀번호 인증 방식이 더 나을 수도 있다. 하지만 (많은<br />
개발자가 그러하듯이) 로컬 컴퓨터 한 대에서 원격 서버에 접근하는 경우라면 SSH 키 쌍 인증<br />
이 바람직하다. 다음 명령을 실행하면 로컬 컴퓨터에 SSH 키 쌍을 생성할 수 있다.<br />
ssh-keygen<br />
화면에 나오는 지시를 따라 진행하면서 요청받은 정보를 입력한다. 명령을 실행하고 나면<br />
~/.ssh/id_rsa.pub(공개 키) 파일과 ~/.ssh/id_rsa(개인 키) 파일이 생긴다. 개인 키는 로<br />
컬 컴퓨터에 두고 유출되지 않도록 보호해야 하며 공개 키는 여러분의 신규 서버로 복사해야<br />
한다. scp(보안 복사 secure copy ) 명령으로 공개 키를 서버로 복사할 수 있다.<br />
scp ~/.ssh/id_rsa.pub deploy@123.456.78.90:<br />
마지막에는 꼭 콜론 문자(: )를 붙여야 한다! 이 명령을 실행하면 공개 키가 원격 서버 사용자<br />
deploy의 홈 디렉터리에 업로드된다. 이제 deploy 사용자로 원격 서버에 로그인한다. 원격 서<br />
버에 로그인하면 ~/.ssh 디렉터리가 존재하는지 확인하고, 없을 경우에는 다음 명령을 실행해<br />
~/.ssh 디렉터리를 생성한다.<br />
mkdir ~/.ssh<br />
그리고 다음 명령으로 ~/.ssh/authorized_keys 파일을 생성한다.<br />
touch ~/.ssh/authorized_keys<br />
이 파일은 원격 로그인을 허용할 공개 키 목록을 넣어둘 파일이다. 방금 업로드한 공개 키를<br />
~/.ssh/authorized_keys 파일에 추가하기 위해 다음 명령을 실행한다.<br />
66 3부 배포, 테스팅, 튜닝
CHAPTER 8<br />
튜닝<br />
이제 여러분의 <strong>PHP</strong> 애플리케이션은 자신의 <strong>PHP</strong>-FPM 프로세스 풀을 통해 엔진엑스와 나란<br />
히 실행되고 있다. 하지만 아직 다 끝나지 않았다. 여러분의 애플리케이션과 프로덕션 서버에<br />
알맞게 <strong>PHP</strong> 설정을 튜닝해야 한다. 설치된 상태 그대로의 <strong>PHP</strong>는 동네 백화점에서 볼 수 있는<br />
기성 양복과도 같아서, 그럭저럭 맞긴 하지만 아주 잘 맞지는 않는다. 튜닝이 잘 된 <strong>PHP</strong>는 여<br />
러분의 치수에 딱 맞게 제작된 맞춤 양복이라 할 수 있다.<br />
그렇다고 너무 앞서가지는 말자. <strong>PHP</strong> 튜닝이 애플리케이션 성능 문제에 대한 만병통치약은<br />
아니다. 이를테면 부적절한 SQL 쿼리나 응답 없는 API 같이 나쁜 코드로 인해 발생하는 문제<br />
는 <strong>PHP</strong> 튜닝으로 해결할 수 없다. 그렇긴 해도, <strong>PHP</strong> 튜닝은 <strong>PHP</strong> 효율과 애플리케이션 성능<br />
을 향상할 수 있는 가장 쉽고 빠른 방법이다.<br />
8.1 php.ini 파일<br />
<strong>PHP</strong> 인터프리터는 php.ini라는 파일로 설정하며 튜닝한다. 이 파일은 경우에 따라 다른 위치<br />
의 것을 사용한다. 앞서 실습한 방법대로 <strong>PHP</strong>-FPM을 통해 <strong>PHP</strong>를 실행한다면 /etc/php5/<br />
fpm/php.ini에 있다. 묘하게도 이 php.ini 파일은 명령행에서 호출한 <strong>PHP</strong> 인터프리터와는<br />
관계가 없다. 명령행에서 호출하는 <strong>PHP</strong>는 별도의 php.ini 파일로 제어하며 이 파일은 보통 /<br />
etc/php5/cli/php.ini에 있다. 만일 소스를 이용해 <strong>PHP</strong>를 설치했다면 소스 설정 단계에서<br />
8장 튜닝<br />
67
지정했던 $PREFIX 디렉터리에 php.ini 파일이 있을 것이다. 나는 여러분이 <strong>PHP</strong>-FPM을 통<br />
해 <strong>PHP</strong>를 실행한다고 간주하지만, 앞으로 나올 최적화 방법들은 모든 php.ini 파일에 적용할<br />
수 있다.<br />
TIP<br />
TIP<br />
여러분의 php.ini 파일이 모범 보안 사례에 적합한지 알아보려면, 크리스 코넛이 제작한 <strong>PHP</strong> 이니스캔 Iniscan<br />
(https://github.com/psecio/iniscan)으로 php.ini 파일을 검사해보자.<br />
php.ini 파일은 INI 형식으로 작성한다. INI 파일 형식에 대해서는 위키백과(https://ko.wikipedia.org/<br />
wiki/INI_파일)에서 알아볼 수 있다.<br />
8.2 메모리<br />
<strong>PHP</strong>를 실행할 때 제일 먼저 고려해야 할 사항은 각 <strong>PHP</strong> 프로세스가 소비하는 메모리양이다.<br />
php.ini 파일에 있는 memory_limit 설정은 하나의 <strong>PHP</strong> 프로세스가 사용할 수 있는 최대 시<br />
스템 메모리를 결정한다.<br />
이 설정의 기본값은 128M인데, 이 정도면 중소 규모 <strong>PHP</strong> 애플리케이션 대부분에 적당하다.<br />
하지만 초소형 <strong>PHP</strong> 애플리케이션을 실행할 때는 이 값을 64M 정도로 낮춰 시스템 자원을 절<br />
약할 수 있으며, 메모리 집약적인 <strong>PHP</strong> 애플리케이션(예: 드루팔 웹 사이트)을 실행할 때는<br />
512M 정도로 올려 성능을 향상할 수도 있다. 구체적인 설정값은 시스템의 가용 메모리에 의해<br />
좌우된다. <strong>PHP</strong>에 할당된 메모리양을 알아내는 방법은 과학적인 이론이라기보다는 예술적인<br />
기교에 더 가깝다. <strong>PHP</strong>에 허용할 수 있는 한계 메모리와 최대 <strong>PHP</strong>-FPM 프로세스 수를 결<br />
정하려면 다음과 같은 질문에 답할 수 있어야 한다.<br />
● <strong>PHP</strong>에 할당할 수 있는 총 메모리는 얼마인가<br />
우선 시스템 메모리를 얼마만큼 <strong>PHP</strong>에 할당할지 결정한다. 예를 들어 내가 사용하는 리노드 가상 컴퓨터의<br />
전체 메모리는 2GB다. 하지만 다른 프로세스(예: 엔진엑스, MySQL, 멤캐시)가 동일한 시스템에서 실행 중<br />
이며 각자 메모리를 소비하고 있어서, <strong>PHP</strong>용으로 안전하게 확보할 수 있는 메모리는 512MB 정도다.<br />
● 단일 <strong>PHP</strong> 프로세스가 소비하는 평균 메모리는 얼마인가<br />
다음으로 하나의 <strong>PHP</strong> 프로세스가 소비하는 평균 메모리를 결정한다. 이를 위해서는 프로세스의 메모리 사용<br />
량을 지켜봐야 한다. 명령행에서는 top 명령을 실행하면 현재 실행 중인 프로세스에 대한 실시간 통계를 볼<br />
수 있으며, <strong>PHP</strong> 스크립트 맨 마지막에 memory_get_peak_usage() 함수를 호출하면 해당 스크립트가<br />
소비하는 최대 메모리를 출력할 수도 있다. 어느 쪽이든, 같은 <strong>PHP</strong> 스크립트를 (캐시가 준비될 때까지) 여러<br />
68 3부 배포, 테스팅, 튜닝
번 실행한 다음 평균 메모리 소비량을 구하면 된다. <strong>PHP</strong> 프로세스의 메모리 소모량은 보통 5MB~20MB<br />
사이다. 그렇지만 파일 업로드, 이미지 데이터, 메모리 집약적인 애플리케이션 등을 다룬다면 그보다 확연히 높<br />
을 것이다.<br />
● 얼마나 많은 <strong>PHP</strong>-FPM 프로세스를 감당할 수 있는가<br />
<strong>PHP</strong>에 할당된 총 메모리는 512MB이며 각 <strong>PHP</strong> 프로세스가 평균적으로 소비하는 메모리는 15MB로 정<br />
했다. 총 메모리를 개별 <strong>PHP</strong> 프로세스 메모리로 나누면 감당할 수 있는 <strong>PHP</strong>-FPM 프로세스 개수를 알 수<br />
있으며 여기서는 34가 된다. 이 값은 추정치며 실험 과정을 거쳐 개선해야 한다.<br />
● 시스템 자원은 충분한가<br />
마지막으로 <strong>PHP</strong> 애플리케이션을 실행하고 예상 웹 트래픽을 처리할 수 있는 충분한 시스템 자원이 있다고<br />
확신하는지 스스로에게 물어봐야 한다. “예”라고 대답할 수 있다면 좋겠지만 그렇지 않다면 서버 메모리 용량<br />
을 업그레이드하고 첫 번째 질문으로 되돌아가야 한다.<br />
프로덕션과 유사한 환경을 구성해 <strong>PHP</strong> 애플리케이션을 올리고 아파치 벤치(http://bit.ly/apache<br />
-bench)나 시즈(http://www.joedog.org/siege-home/)를 이용해 부하 테스트를 수행하라. 프로덕션에<br />
애플리케이션을 올렸을 때 메모리 부족 문제가 발생하지 않도록 사전에 확인해두는 것이 현명한 처사다.<br />
8.3 젠드 오피캐시<br />
메모리 할당량을 계산하고 나면 <strong>PHP</strong> 젠드 오피캐시 Zend OPcache 확장을 설정하고 오피코드 OPcode<br />
캐시를 활성화한다. 오피코드 캐시란 무엇인가? 먼저 일반적인 <strong>PHP</strong> 스크립트가 HTTP 요청<br />
을 처리하는 과정을 살펴보자. 우선 엔진엑스는 <strong>PHP</strong>-FPM에 HTTP 요청을 전달하고 <strong>PHP</strong>-<br />
FPM은 자식 <strong>PHP</strong> 프로세스에 요청을 할당한다. <strong>PHP</strong> 프로세스는 필요한 <strong>PHP</strong> 스크립트들<br />
을 찾아서 읽어들이고 오피코드(또는 바이트코드) 형식으로 컴파일한다. 컴파일된 오피코드<br />
는 HTTP 응답을 생성하고 엔진엑스는 이 HTTP 응답을 HTTP 클라이언트로 반환한다. 모든<br />
HTTP 요청에 대해 이와 같은 과정을 반복하면 많은 부하가 발생하게 된다.<br />
각 <strong>PHP</strong> 스크립트마다 컴파일된 오피코드 캐시를 생성하면 이 과정의 속도를 높일 수 있다. 이<br />
렇게 하면 HTTP 요청마다 <strong>PHP</strong> 스크립트를 찾고, 읽고, 컴파일하는 대신, 미리 컴파일된 오<br />
피코드를 실행할 수 있다. 젠드 오피캐시 확장은 <strong>PHP</strong> 5.5.0 이상에 내장되어 있다. 다음은 젠<br />
드 오피캐시 확장을 설정하고 최적화한 나의 php.ini 설정이다.<br />
8장 튜닝<br />
69
opcache.memory_consumption = 64<br />
opcache.interned_strings_buffer = 16<br />
opcache.max_accelerated_files = 4000<br />
opcache.validate_timestamps = 1<br />
opcache.revalidate_freq = 0<br />
opcache.fast_shutdown = 1<br />
● opcache.memory_consumption = 64<br />
이 설정은 오피코드 캐시에 할당된 메모리 용량(메가바이트 단위)을 지정한다. 애플리케이션에 있는 모든<br />
<strong>PHP</strong> 스크립트의 컴파일 오피코드를 저장할 수 있을 만큼 충분히 커야 한다. 스크립트 수가 적은 소형 <strong>PHP</strong><br />
애플리케이션이라면 16MB 정도로 낮은 값을 사용하며 스크립트 수가 많은 대형 <strong>PHP</strong> 애플리케이션이라면<br />
64MB 정도로 큰 값을 사용한다.<br />
● opcache.interned_strings_buffer = 16<br />
이 설정은 인턴화된 interned 문자열을 저장하는 데 사용되는 메모리 용량(메가바이트 단위)이다. 대체 인턴화된<br />
문자열이 무엇인지 나 역시 궁금했다. 막후에서 <strong>PHP</strong> 인터프리터는 반복적으로 사용되는 문자열 인스턴스를<br />
감지하고 메모리에 저장하며, 일단 저장한 후에는 같은 문자열이 다시 사용될 때마다 포인터를 활용해 메모<br />
리를 절약한다. 이런 과정을 문자열 인턴화라고 한다. <strong>PHP</strong>의 문자열 인턴화는 기본적으로 각 <strong>PHP</strong> 프로세<br />
스에 의해 고립되는데, 이 설정을 이용하면 모든 <strong>PHP</strong>-FPM 풀 프로세스가 인턴화된 문자열을 공유 버퍼에<br />
저장하게 된다. 저장된 인턴화 문자열은 여러 <strong>PHP</strong>-FPM 풀 프로세스가 동시에 참조할 수 있으며 이런 과정<br />
을 통해 더욱 많은 메모리를 절약할 수 있다. 이 설정의 기본값은 4MB지만 나는 한층 큰 값인 16MB를 선호<br />
한다.<br />
● opcache.max_accelerated_files = 4000<br />
이 설정은 오피코드 캐시에 저장될 수 있는 <strong>PHP</strong> 스크립트의 최대 개수다. 200과 100000 사이에서 지정할<br />
수 있으며, 나는 4000을 사용한다. 이 값은 <strong>PHP</strong> 애플리케이션에 있는 전체 스크립트 파일 수보다 커야 한다.<br />
● opcache.validate_timestamps = 1<br />
이 설정을 사용하면 <strong>PHP</strong>는 opcache.revalidate_freq 설정에 지정된 시간 간격마다 변경된 <strong>PHP</strong> 스<br />
크립트가 있는지 확인한다. 이 설정이 비활성화되어 있으면 <strong>PHP</strong>가 스크립트 변경 여부를 확인하지 않기 때문<br />
에, 변경된 스크립트의 캐시를 새로 생성하려면 수동으로 오피코드 캐시를 삭제해야 한다. 이 설정은 개발 기<br />
간에만 사용하고 프로덕션 환경에서는 비활성화해두자.<br />
● opcache.revalidate_freq = 0<br />
이 설정은 컴파일된 <strong>PHP</strong> 파일의 변경 여부를 얼마나 자주 검사할지 지정한다. 캐시를 사용하면 매 요청마다<br />
<strong>PHP</strong> 스크립트를 재컴파일하지 않는다는 이점이 있으며, 이 설정값은 캐시의 신선함을 판단할 기준 시간 간<br />
격을 결정한다. 이 시간 간격이 지날 때마다 <strong>PHP</strong>는 <strong>PHP</strong> 스크립트 변경 여부를 확인하며, 변경을 감지하면<br />
스크립트를 다시 컴파일하고 캐시를 새로 생성한다. 나는 이 값을 0으로 설정하는데, 이렇게 하면 opcache.<br />
validate_timestamps 설정이 활성화됐을 때에 한해서 매 요청마다 <strong>PHP</strong> 파일을 재검증한다. 다시 말<br />
해 개발하는 동안 매 요청마다 <strong>PHP</strong>가 파일들을 재검증한다는 의미다(좋은 방법이다). 프로덕션 환경에서는<br />
opcache.validate_timestamps 설정을 비활성화하기 때문에 이 설정은 신경 쓸 필요가 없다.<br />
70 3부 배포, 테스팅, 튜닝
● opcache.fast_shutdown = 1<br />
이 설정을 사용하면 오피캐시가 객체의 소멸과 메모리 해제를 젠드 엔진 메모리 관리자에 위임해서 빠른 종료<br />
단계를 거치게 된다. 이 설정에 대한 문서는 많지 않으며, 여러분은 그저 이 설정을 켜둬야 한다는 점만 알아두<br />
면 된다.<br />
8.4 파일 업로드<br />
파일 업로드 기능이 없는 <strong>PHP</strong> 애플리케이션이라면 애플리케이션 보안을 향상하기 위해 파일<br />
업로드 설정을 꺼두자. 그렇지 않다면 애플리케이션이 허용하는 최대 업로드 파일 크기와 애플<br />
리케이션에 한 번에 업로드할 수 있는 최대 파일 개수를 설정해야 한다. 다음은 내가 사용하는<br />
php.ini 설정이다.<br />
file_uploads = 1<br />
upload_max_filesize = 10M<br />
max_file_uploads = 3<br />
기본적으로 <strong>PHP</strong>는 단일 요청에 포함된 업로드를 20개까지 허용하며 각 업로드 파일의 최대<br />
크기는 2MB다. 아마 한 번에 20개까지 업로드를 허용할 필요는 없을 것이다. 나는 단일 요청<br />
에 업로드 세 개를 허용하지만 여러분은 각자 애플리케이션에 맞는 값으로 설정을 변경하자.<br />
파일 업로드 기능이 있는 <strong>PHP</strong> 애플리케이션이라면 2MB보다 큰 파일 업로드를 허용해야 할<br />
경우도 종종 있다. 그럴 때는 <strong>PHP</strong> 애플리케이션의 요구 사항에 맞게 upload_max_filesize<br />
값을 10M 혹은 그보다 큰 값으로 설정한다. 너무 큰 값으로 설정하면 여러분의 웹 서버(예: 엔<br />
진엑스)가 HTTP 요청 본문이 너무 크다고 불평하거나 응답 시간을 초과해버릴 수도 있으니<br />
주의하자.<br />
아주 큰 파일 업로드를 허용해야 한다면 웹 서버가 적절하게 구성되어 있는지 확인해야 한다. php.<br />
ini 파일뿐만 아니라 엔진엑스 가상 호스트 설정에서 client_max_body_size(http://bit.ly/max-bodysize)를<br />
조정해야 할 수도 있다.<br />
8장 튜닝<br />
71
8.5 최대 실행 시간<br />
php.ini 파일에 있는 max_execution_time 설정은 단일 <strong>PHP</strong> 프로세스의 최대 실행 시간을<br />
결정하며, 이 시간이 지나면 <strong>PHP</strong> 프로세스가 종료된다. 기본값은 30초지만 아무도 <strong>PHP</strong> 프로<br />
세스를 30초 동안 실행하고 싶어 하지는 않는다. 우리는 애플리케이션 실행 속도가 (밀리초 단<br />
위로 측정되는) 초고속이기를 바란다. 이 설정값은 5초로 지정하자.<br />
max_execution_time = 5<br />
이 설정은 set_time_limit()(http://php.net/manual/function.set-time-limit.php) 함수<br />
를 이용해 개별 스크립트 단위로 재정의할 수 있다.<br />
<strong>PHP</strong> 스크립트를 장시간 실행해야 할 때는 어떻게 하냐고 묻는다면, 그래서는 안 된다고 대답<br />
하겠다. <strong>PHP</strong> 실행 시간이 길어질수록 웹 애플리케이션 방문자의 대기 시간도 길어질 수밖에<br />
없다. 실행 시간이 많이 걸리는 작업(예를 들어 이미지 크기를 조정하거나 보고서를 생성하는)<br />
이라면 별도의 작업자 프로세스로 해당 작업을 넘겨주자.<br />
TIP<br />
나는 exec() <strong>PHP</strong> 함수를 사용해서 bash 명령어를 호출한다. 이 함수를 이용하면 <strong>PHP</strong> 프로세스를 지연<br />
시키지 않는 논블로킹 프로세스를 생성해 현재 <strong>PHP</strong> 스크립트로부터 분리할 수 있다. exec() 함수를 사용하<br />
려면 escapeshellarg(http://php.net/manual/function.escapeshellarg.php) 함수로 셸 인수를 직<br />
접 예외 처리해야 한다.<br />
결과 보고서를 <strong>PDF</strong> 파일로 생성해야 한다고 가정해보자. 이 작업은 완료까지 10분 정도 걸<br />
린다. <strong>PHP</strong> 요청이 완료될 때까지 10분 동안 기다리고 있을 사람은 아무도 없다. 대신 우리는<br />
create-report.php라는 파일을 따로 만들고 이 파일을 10분 동안 계속 실행시켜 보고서를<br />
생성한다. 반면 웹 애플리케이션은 백그라운드 프로세스를 분리하고 다음과 같은 HTTP 응답<br />
을 반환하는 데 몇천 분의 1초밖에 걸리지 않는다.<br />
CHAPTER 9<br />
배포<br />
서버를 프로비전하고 엔진엑스와 <strong>PHP</strong>-FPM을 실행할 준비를 마쳤다면 이제 <strong>PHP</strong> 애플리케<br />
이션을 프로덕션 서버로 배포해야 한다. 프로덕션으로 코드를 올리는 방법은 다양하다. 초창기<br />
<strong>PHP</strong> 개발자들은 주로 FTP를 사용해서 <strong>PHP</strong> 코드를 배포했지만 오늘날에는 FTP보다 더 안전<br />
하고 예측 가능한 배포 전략들이 있다. 이번 장에서는 단순하고 예측 가능하며 가역적 Reversible 인<br />
방법으로 배포를 자동화해주는 최신 도구들을 알아본다.<br />
9.1 버전 관리<br />
여러분은 버전 관리를 잘 활용하고 있을 것이다. 만일 그렇지 않다면 하던 일을 멈추고 코드<br />
버전 관리부터 시작해야 한다. 나는 주로 깃(http://git-scm.com )을 이용해 코드를 버전 관리<br />
하지만 깃 외에 머큐리얼 Mercurial (http://mercurial.selenic.com ) 같은 버전 관리 소프트웨어<br />
를 사용할 수도 있다. 깃은 내게 익숙한 도구며 비트버킷(https://bitbucket.org )이나 깃허브<br />
(https://github.com ) 같은 온라인 저장소와도 매끄럽게 연동되기 때문에 나는 깃을 사용한다.<br />
버전 관리는 <strong>PHP</strong> 애플리케이션 개발자에게 매우 귀중한 도구다. 버전 관리를 통해 코드베이<br />
스의 변경 이력을 추적할 수 있기 때문이다. 버전 관리를 이용하면 코드베이스에 특정 배포 시<br />
점을 지칭하는 태그를 붙이거나 코드베이스를 과거 버전으로 되돌릴 수 있으며, 프로덕션 코드<br />
에 영향을 주지 않고도 새로운 기능을 시험해볼 수 있도록 브랜치를 분리할 수도 있다. 무엇보<br />
다 버전 관리는 <strong>PHP</strong> 애플리케이션 배포를 자동화하는 데 있어 중요한 역할을 담당한다.<br />
9장 배포<br />
73
9.2 배포 자동화<br />
애플리케이션 배포를 자동화하면 배포 과정이 단순해질 뿐만 아니라 배포 과정을 예측하거나<br />
배포 상태를 이전으로 되돌릴 수도 있게 된다. 이 점이 배포 자동화가 중요한 이유다. 여러분에<br />
게 가장 피하고 싶은 작업이 있다면 바로 복잡한 과정이 수반된 배포 작업일 것이다. 복잡한 배<br />
포 과정은 부담스럽고, 부담스러운 작업은 누구나 기피하기 마련이다.<br />
9.2.1 단순하게<br />
배포 과정은 명령어 한 줄로 처리할 수 있을 정도로 단순해야 한다. 배포 과정이 단순해지면 배<br />
포 작업에 대한 부담이 줄고 프로덕션으로 코드를 올리는 일이 좀 더 수월해진다.<br />
9.2.2 예측 가능하게<br />
배포 과정은 예측할 수 있어야 한다. 무슨 일이 벌어질지 정확히 알고 있으면 배포 과정에 대한<br />
부담이 한층 더 줄어든다. 배포 과정에는 예기치 못한 부작용이 없어야 하며, 만약 오류가 발생<br />
하더라도 즉시 작업을 중단하고 기존 코드베이스를 유지해야 한다.<br />
9.2.3 가역적으로<br />
배포 과정은 가역적이어야 한다. 좋지 않은 코드가 뜻하지 않게 프로덕션으로 배포됐다 하더라<br />
도 간단한 명령어 한 줄만으로 이전 안정화 버전으로 되돌릴 수 있어야 하며, 가역적인 배포 과<br />
정이 이러한 안전망의 역할을 한다. 배포 과정을 되돌릴 수 있다면 프로덕션에 코드를 올리는<br />
일을 즐기게 즉, 두려워하지 않게 된다. 뭔가 망치더라도 이전 버전으로 되돌려버리면 그만이<br />
기 때문이다.<br />
9.3 카피스트라노<br />
카피스트라노(http://capistranorb.com/)는 애플리케이션 배포를 단순하고 예측 가능하며 가<br />
역적인 방법으로 자동화해주는 소프트웨어다. 카피스트라노는 로컬 컴퓨터에서 실행하며 SSH<br />
74 3부 배포, 테스팅, 튜닝
를 통해 원격 서버와 소통한다. 카피스트라노는 원래 루비 애플리케이션을 배포하기 위해 제작<br />
됐지만 <strong>PHP</strong>를 포함한 다른 모든 프로그래밍 언어에도 마찬가지로 유용하다.<br />
9.3.1 작동<br />
카피스트라노는 로컬 워크스테이션에 설치하는 도구다. 카피스트라노는 로컬 워크스테이션으<br />
로부터 원격 서버로 SSH 명령을 내릴 수 있으며 이를 이용해 <strong>PHP</strong> 애플리케이션을 원격 서버<br />
에 배포한다. 원격 서버에는 애플리케이션 배포 버전들로 구성된 카피스트라노 관리 디렉터리<br />
가 생성되는데, 이전 버전으로 되돌려야 할 경우를 대비해 5개 이상의 애플리케이션 배포 디렉<br />
터리가 유지된다. 또한 카피스트라노는 애플리케이션의 현재 배포 버전 디렉터리를 가리키는<br />
심볼릭 링크인 current/ 디렉터리를 생성한다. [예제 9-1]은 프로덕션 서버에 구성된 카피스<br />
트라노 관리 디렉터리의 예시 구조다.<br />
예제 9-1 예제 디렉터리 구조<br />
/<br />
home/<br />
deploy/<br />
apps/<br />
my_app/<br />
current/<br />
releases/<br />
release1/<br />
release2/<br />
release3/<br />
release4/<br />
release5/<br />
프로덕션에 새 애플리케이션 버전을 배포할 때 카피스트라노는 먼저 깃 저장소에서 애플리케<br />
이션 코드의 최신 버전을 검색한다. 다음으로 신규 버전 디렉터리에 애플리케이션 코드를 배치<br />
하고, 마지막으로 심볼릭 링크 디렉터리 current/를 신규 버전 디렉터리와 연결한다. 애플리케<br />
이션을 이전 버전으로 되돌릴 때는 current/ 링크가 가리키는 대상을 이전 버전 디렉터리로 변<br />
경만 하면 된다. 이처럼 카피스트라노는 우아하면서도 간결한 배포 솔루션이며, 카피스트라노<br />
를 통해 단순하고, 예측 가능하며, 가역적인 방법으로 <strong>PHP</strong> 애플리케이션을 배포할 수 있다.<br />
9장 배포<br />
75
9.3.2 설치<br />
카피스트라노는 로컬 장비에 설치하며 원격 서버에는 설치하지 않는다. 카피스트라노를 설치<br />
하려면 ruby와 gem이 필요한데, OS X에는 기본적으로 설치되어 있으며 리눅스에는 패키지 관<br />
리자로 설치할 수 있다. ruby와 gem을 설치하고 나면 다음 명령을 실행해 카피스트라노를 설<br />
치한다.<br />
gem install capistrano<br />
9.3.3 설정<br />
카피스트라노를 설치한 다음에는 카피스트라노로 배포할 프로젝트를 초기화해야 한다. 터미널<br />
을 열고 프로젝트 최상위 디렉터리로 이동해 다음 명령을 실행한다.<br />
cap install<br />
이 명령을 실행하면 Capfile 파일을 비롯해 config/ 및 lib/ 디렉터리가 생성된다. 프로젝트<br />
최상위 디렉터리에는 이제 다음과 같은 파일과 디렉터리들이 있을 것이다.<br />
Capfile<br />
config/<br />
deploy/<br />
production.rb<br />
staging.rb<br />
deploy.rb<br />
lib/<br />
capistrano/<br />
tasks/<br />
Capfile 파일은 카피스트라노의 중앙 설정 파일이며 config/ 디렉터리에 있는 설정 파일들을<br />
취합한다. config/ 디렉터리에는 각 원격 서버 환경(예: 테스트, 스테이징, 프로덕션)에 대한<br />
설정 파일이 있다.<br />
카피스트라노 설정 파일은 루비 언어로 작성되어 있지만 편집하거나 이해하는 데는 불편함이 없다.<br />
76 3부 배포, 테스팅, 튜닝
기본적으로 카피스트라노는 한 애플리케이션이 다양한 환경에서 실행된다고 간주한다. 예를<br />
들어 스테이징 환경과 프로덕션 환경이 분리되어 있다면 애플리케이션도 두 환경에 모두 배포<br />
되어야 한다. 카피스트라노는 각 환경별로 설정 파일을 제공하며 이 설정 파일들은 config/<br />
deploy/ 디렉터리에 있다. 또한 config/deploy.rb 파일에는 모든 환경에 공통적으로 적용되<br />
는 설정이 있다.<br />
카피스트라노는 각 환경을 구성하는 서버들을 서버 역할이라는 개념으로 분류한다. 예를 들면<br />
프로덕션 환경은 최전방 웹 서버(web 역할), 애플리케이션 서버(app 역할), 데이터베이스 서<br />
버(db 역할)로 구성된다. 이런 구조는 대규모 애플리케이션에만 사용되며 소형 <strong>PHP</strong> 애플리<br />
케이션 환경에서는 일반적으로 웹 서버(엔진엑스), 애플리케이션 서버(<strong>PHP</strong>-FPM), 데이터<br />
베이스 서버(마리아DB MariaDB )가 모두 하나의 장비에서 실행된다.<br />
앞으로 실습할 예제에서는 web 역할만 사용하고 app과 db 역할은 무시한다. 서버 역할을 활용<br />
하면 배포 작업을 구분하고 특정 역할에 속한 서버에서만 실행되도록 구성할 수 있다. 여기서<br />
는 서버 역할에 대해서는 다루지 않지만 서버 환경에 대한 개념은 준수할 것이다. 앞으로 나올<br />
과정들은 프로덕션 환경을 대상으로 하며, 다른 환경(예: 스테이징 staging 또는 테스팅 testing )에도<br />
동일하게 적용할 수 있다.<br />
config/deploy.rb 파일<br />
config/deploy.rb 파일을 살펴보자. 이 파일에 지정된 설정들은 모든 환경(예: 스테이징과<br />
프로덕션)에 공통적으로 적용된다. 카피스트라노 설정 대부분이 이 파일에 있다. 즐겨 쓰는 편<br />
집기로 config/deploy.rb 파일을 열고 다음 설정들을 수정해보자.<br />
● :application<br />
<strong>PHP</strong> 애플리케이션명을 지정한다. 애플리케이션명에는 문자, 숫자, 밑줄만 사용할 수 있다.<br />
● :repo_url<br />
깃 저장소 URL을 지정한다. 올바른 깃 저장소 URL이어야만 하며 원격 서버에서 접근할 수 있어야 한다.<br />
● :deploy_to<br />
<strong>PHP</strong> 애플리케이션이 배포될 원격 서버의 디렉터리 절대 경로를 지정한다. [예제 9 -1]에서는 /home/<br />
deploy/apps/my_app을 사용한다.<br />
● :keep_releases<br />
이전 배포 버전을 몇 개까지 보관할 것인지 지정한다. 보관된 버전들은 애플리케이션을 이전 버전으로 되돌릴<br />
때 사용된다.<br />
9장 배포<br />
77
config/deploy/production.rb 파일<br />
이 파일에는 프로덕션 환경에 대한 설정이 있다. 이 파일은 프로덕션 환경의 역할을 정의하고<br />
각 역할에 속한 서버를 나열한다. 우리는 web 역할만 사용하며 이 역할에 속한 서버는 한 대다.<br />
7장에서 프로비전한 서버를 사용하자. config/deploy/production.rb 파일 내용 전체를 다<br />
음 내용으로 교체하고, IP 주소는 여러분에게 맞게 수정한다.<br />
role :web, %w{deploy@123.456.78.90}<br />
9.3.4 인증<br />
카피스트라노로 애플리케이션을 배포하기에 앞서 로컬 컴퓨터와 원격 서버, 원격 서버와 깃 저<br />
장소 사이에 인증을 수립해야 한다. 우리는 앞서 로컬 컴퓨터와 원격 서버 사이에 SSH 키 쌍<br />
인증을 설정하는 방법을 알아보았다. 이제 원격 서버와 자식 저장소 사이에 SSH 키 쌍 인증을<br />
수립해보자.<br />
앞서 설명한 지침을 따라 각 원격 서버에 SSH 공개 키와 개인 키 쌍을 생성한다. 깃 저장소는<br />
각 원격 서버의 공개 키에 접근할 수 있어야 하는데, 깃허브와 비트버킷 모두 공개 SSH 키를<br />
사용자 계정에 여러 개 등록할 수 있다. 이런 과정을 거쳐 궁극적으로는 암호를 입력하지 않고<br />
도 원격 서버에 깃 저장소를 복제 clone 할 수 있어야 한다.<br />
9.3.5 원격 서버<br />
애플리케이션을 배포할 준비가 거의 끝났다. 이제 원격 서버를 준비해야 한다. SSH로 원격 서<br />
버에 로그인해서 <strong>PHP</strong> 애플리케이션을 배포할 디렉터리를 생성한다. 이 디렉터리는 deploy<br />
사용자가 읽고 쓸 수 있어야 한다. 나는 다음과 같이 deploy 사용자의 홈 디렉터리에 애플리케<br />
이션 디렉터리를 만든다.<br />
/<br />
home/<br />
deploy/<br />
apps/<br />
my_app/<br />
78 3부 배포, 테스팅, 튜닝
CHAPTER 10<br />
테스팅<br />
테스팅은 <strong>PHP</strong> 애플리케이션 개발 과정의 중요한 일부분이지만 종종 도외시되곤 한다. 많은<br />
<strong>PHP</strong> 개발자가 테스트를 하지 않는데, 테스트를 해봤자 소요 시간에 비해 얻을 수 있는 이익이<br />
많지 않으며 오히려 불필요한 부담만 가중된다고 여기기 때문이다. 한편으로는 다양한 테스팅<br />
도구와 가파른 학습곡선 때문에 테스트 방법을 습득하지 못하는 개발자들도 있다.<br />
이번 장에서 나는 이러한 오해를 불식시키고자 한다. 나는 여러분이 편안하고 즐거운 마음으로<br />
<strong>PHP</strong> 코드를 테스트하기 바란다. 또한 테스팅이 애플리케이션 개발 과정의 엄연한 일부분이며<br />
개발 과정의 시작과 중간과 마지막을 함께하는 작업이라고 여기기 바란다.<br />
10.1 테스트를 하는 이유<br />
테스트를 작성하는 이유는 <strong>PHP</strong> 애플리케이션이 우리의 기대에 따라 지속적으로 작동하도록<br />
보장하기 위해서다. 단지 그뿐이다. 여러분은 프로덕션으로 애플리케이션을 배포하고 나서 불<br />
안에 떨어야 했던 경험이 얼마나 있는가? 예전에는 나도 코드를 테스트하지 않았으며 새로운<br />
코드를 프로덕션으로 올리는 일에 두려움을 느꼈다. 코드가 제대로 작동할지 문제가 생기지는<br />
않을지 걱정하면서도 그저 아무 일 없이 무사하기만을 두 손 모아 기도할 수밖에 없었다. 이런<br />
방식은 코드에 전혀 도움이 되지 못하며 두려움과 스트레스를 유발할 뿐만 아니라 대개의 경우<br />
실망스러운 결과를 야기한다. 하지만 테스트를 이용하면 불확실성을 줄이고 코드 작성과 배포<br />
에 확신이 생긴다.<br />
10장 테스팅<br />
79
여러분의 상사는 테스트를 작성할 시간적인 여유가 없다고 항변할지 모르지만, 결국 시간은 돈<br />
이라는 관점에서 보자면 이는 근시안적인 주장이다. 테스팅 인프라를 갖추고 테스트 코드를 작<br />
성하는 일에는 시간이 걸리지만 이 과정은 장래에 수령할 배당금이 보장된 현명한 투자와도 같<br />
다. 테스트를 이용하면 처음부터 잘 작동하는 코드를 작성할 수 있을 뿐만 아니라 이를 지속적<br />
으로 반복하면서도 기존 코드에 문제를 일으키지 않게 된다. 테스트를 수행하면 개발 속도가<br />
지연될 수도 있지만, 미처 발견하지 못했던 버그를 수정하고 리팩토링하느라 낭비될지도 모를<br />
무수한 개발 시간을 미리 아낄 수 있다. 장기적으로는 테스트를 통해 비용을 절감하고 서비스<br />
중단 사태를 방지하며 자신감을 고취할 수 있다.<br />
10.2 테스트 시점<br />
많은 개발자가 뒤늦은 시점에 테스트 코드를 작성한다. 이런 개발자들은 테스트가 중요하다는<br />
사실을 알고는 있지만, 원치 않게 의무적으로 테스트를 해야 한다고 여긴다. 이들은 테스트를<br />
개발 과정 맨 나중으로 미뤄 두었다가, 관리팀의 평가 요건을 맞추기 위해 한두 개 뚝딱 만들어<br />
통과시키고는 이내 손을 떼버린다. 이런 방식은 옳지 않다. 테스트는 개발 전, 개발 도중, 개발<br />
후를 통틀어 전면적인 관심사로 취급되어야 한다.<br />
10.2.1 개발 전<br />
애플리케이션을 개발하기에 앞서 테스팅 도구를 설치하고 구성해야 한다. 어떤 테스팅 도구를<br />
선택하든지 애플리케이션에 필수적인 의존성이 있는 것처럼 설치해야 하며, 이런 방식은 개발<br />
하는 동안 애플리케이션을 테스트하는 데 있어 물리적, 심리적 측면으로 도움이 된다. 또한 이<br />
시기는 프로젝트 관리자와 함께 애플리케이션의 행동을 높은 수준에서 정의하기에 적절하다.<br />
10.2.2 개발 도중<br />
애플리케이션의 각 부분을 만들 때마다 테스트를 작성하고 실행한다. 새로운 <strong>PHP</strong> 클래스를<br />
추가했다면 그 즉시 테스트를 만들어 실행해야 한다. 나중으로 미뤘다간 테스트를 하지 않을<br />
수도 있기 때문이다. 개발 과정에서 테스트를 병행하면 견고하고 안정적인 코드를 구축할 수<br />
80 3부 배포, 테스팅, 튜닝
있으며 새로운 코드로 인해 기존 기능성이 침해되는 부분을 신속하게 찾아내고 리팩토링을 할<br />
수 있다.<br />
10.2.3 개발 후<br />
개발 과정에서 애플리케이션의 모든 행동을 예상하고 테스트하지 못할 수도 있다. 애플리케이<br />
션 출시 후 버그를 발견하면 버그 픽스를 만들어야 하며, 버그 픽스의 올바른 동작을 보장하기<br />
위한 새로운 테스트도 함께 작성해야 한다. 테스트는 일회성 작업이 아니며 애플리케이션과 마<br />
찬가지로 지속적인 수정과 개선이 필요하다. 애플리케이션 코드를 수정하면 그에 따른 영향을<br />
받는 테스트 역시 수정되어야 한다.<br />
10.3 테스트 대상<br />
테스트를 수행할 대상은 애플리케이션을 구성하는 가장 작은 조각들이다. 미시적인 관점에서<br />
볼 때 <strong>PHP</strong> 애플리케이션에는 <strong>PHP</strong> 클래스, 메서드, 함수가 있다. 우리는 공개된 클래스, 메서<br />
드, 함수를 테스트해야 하며 이들이 고립된 상태에서 우리가 원하는 대로 행동하는지 확인해야<br />
한다. 각 조각들이 저마다 잘 작동하면 전체 애플리케이션으로 통합된 후에도 잘 작동한다고<br />
확신할 수 있다. 이러한 테스트를 단위 테스트라 부른다.<br />
불행히도 애플리케이션의 개별적인 조각들이 각각 테스트를 거친다 해도 전체 애플리케이션이<br />
제대로 작동한다고 보장할 수는 없다. 이 점이 자동화된 도구로 애플리케이션을 테스트하는 이<br />
유다. 자동화된 도구를 이용하면 애플리케이션의 상위 수준 행동을 거시적인 관점에서 검증할<br />
수 있다. 이러한 테스트를 기능 테스트라 부른다.<br />
10.4 테스트 방법<br />
지금까지 왜, 언제, 무엇을 테스트할지 알아보았다. 이제 더욱 중요한 요소인 코드 테스트 방법<br />
을 이야기해보자. <strong>PHP</strong> 개발자들은 몇 가지 대표적인 방법을 통해 테스팅에 대한 개념에 접근<br />
10장 테스팅<br />
81
한다. 단위 테스트를 선호하는 개발자가 있는가 하면, 테스트 주도 개발(TDD)을 선호하는 개<br />
발자가 있으며, 행위 주도 개발(BDD)을 선호하는 개발자도 있다. 이런 테스트 방법론들은 상<br />
호 배타적인 관계에 있지 않다.<br />
10.4.1 단위 테스트<br />
<strong>PHP</strong> 애플리케이션 테스트에 대한 가장 대중적인 접근 방식은 단위 테스트 unit test 다. 앞서 설명<br />
한 바와 같이 단위 테스트는 큰 애플리케이션에 포함된 클래스, 메서드, 함수를 고립시킨 상태<br />
로 검증하는 테스트 방식이다. 세바스찬 버그만(https://sebastianbergmann.de/)이 제작한<br />
<strong>PHP</strong>유닛(https://phpunit.de/)은 사실상 표준 <strong>PHP</strong> 단위 테스트 프레임워크다. <strong>PHP</strong>유닛 프<br />
레임워크는 xUnit 1 테스트 아키텍처를 준수한다.<br />
<strong>PHP</strong>스펙 <strong>PHP</strong>Spec 같은 대체 프레임워크를 사용해서 단위 테스트를 수행해도 되지만, 가장 널리<br />
쓰이는 <strong>PHP</strong> 프레임워크들은 대부분 <strong>PHP</strong>유닛 테스트를 제공한다. <strong>PHP</strong> 컴포넌트를 개선하<br />
거나 배포하려면 <strong>PHP</strong>유닛 테스트를 읽고 작성하고 실행하는 방법을 필수적으로 알아야 한다.<br />
<strong>PHP</strong> 단위 테스트를 설치하고, 작성하고, 실행하는 방법은 이번 장 끝 부분에 나와 있다.<br />
10.4.2 테스트 주도 개발(TDD)<br />
테스트 주도 개발 Test-Driven Development (TDD)은 테스트 작성이 애플리케이션 코드 작성보다 선<br />
행되는 테스트 방법론이다. 이 테스트는 의도적인 실패를 통해 애플리케이션의 행동 방식을 묘<br />
사하고, 애플리케이션의 기능이 갖춰지고 나서야 성공적으로 수행된다. TDD는 목표 지향적<br />
인 개발 방법론이며, 무엇을 만들어야 할지, 결과물은 어떻게 작동해야 할지를 사전에 인지할<br />
수 있게 도와준다.<br />
테스트를 전부 작성하기 전까지 애플리케이션 코드를 작성하면 안 된다는 의미는 아니다. 테스<br />
트를 일부 작성하고 그에 관련된 기능을 구현하면 된다. TDD는 테스트 작성과 기능 구현이 계<br />
속 반복되는 과정이며 이 과정은 애플리케이션이 완성될 때까지 점진적으로 진행된다.<br />
1 역자주_ JUnit, NUnit 등 Smaltalk의 SUnit을 계승한 테스트 프레임워크를 통칭하는 용어다.<br />
82 3부 배포, 테스팅, 튜닝
10.4.3 행위 주도 개발(BDD)<br />
행위 주도 개발 Behavior-Driven Development (BDD)은 애플리케이션이 행동하는 방식을 이야기처럼<br />
묘사하는 개발 방법론이다. BDD에는 스펙BDD SpecBDD 와 스토리BDD StoryBDD 유형이 있다.<br />
스펙BDD는 인간 친화적인 우아한 언어로 애플리케이션 구현을 묘사하는 단위 테스트 유형이<br />
다. 스펙BDD를 적용한 단위 테스트 도구는 <strong>PHP</strong>유닛과 동일한 역할을 수행하며, <strong>PHP</strong>유닛<br />
이 사용하는 xUnit 아키텍처와는 달리 사람이 이야기하는 것처럼 애플리케이션의 행동을 묘<br />
사한다. 예를 들어 <strong>PHP</strong>유닛으로 작성한 테스트 메서드명이 testRenderTemplate()이라면<br />
이에 상응하는 스펙BDD 테스트 메서드명은 itRendersTheTemplate()이 된다. 스펙BDD<br />
테스트는 헬퍼 메서드도 이와 유사하게 $this->shouldReturn ( ), $this->shouldBe ( ),<br />
$this->shouldThrow()처럼 이름을 짓는다. 스펙BDD 테스트는 이처럼 xUnit 계열 도구보<br />
다 훨씬 읽고 이해하기 쉬운 언어를 사용한다. 대표적인 스펙BDD 테스트 도구로는 <strong>PHP</strong>스펙<br />
<strong>PHP</strong>Spec<br />
(http://www.phpspec.net/)이 있다.<br />
스토리BDD 도구는 스펙BDD 테스트처럼 인간 친화적인 이야기를 사용하지만 하위 수준 구<br />
현보다는 상위 수준 행동에 관심이 있다. 예를 들자면 스토리BDD 테스트는 여러분의 코드가<br />
<strong>PDF</strong> 보고서를 작성하고 이메일로 발송하는지 검증한다. 스펙BDD 테스트라면 이 경우 <strong>PDF</strong><br />
생성 클래스 메서드가 매개변수를 입력받아 올바르게 <strong>PDF</strong> 파일을 생성하는지 검증할 것이다.<br />
둘 사이의 차이는 바로 테스트 영역이다. 스토리BDD는 프로젝트 관리자의 관점에서 작성한<br />
이야기(예: “보고서를 생성하고 나에게 이메일로 보내야 함”)와 비슷하고 스펙BDD 테스트는<br />
개발자의 관점에서 작성한 이야기(예: “이 클래스 메서드는 데이터 배열을 전달받아 <strong>PDF</strong> 파<br />
일에 기록해야 함”)와 비슷하다. 스토리BDD와 스펙BDD 도구는 상호 배타적이지 않으며 좀<br />
더 포괄적인 테스트셋을 구축하기 위해 종종 함께 쓰인다. 스토리BDD 테스트는 보통 포괄적<br />
인 애플리케이션 동작을 정의하기 위해 프로젝트 관리자와 함께 작성하며, 스펙BDD 테스트<br />
는 애플리케이션 구현을 설계하고 구축할 때 작성한다. 대표적인 스토리BDD 테스트 도구로<br />
는 비햇 Behat (http://behat.org/)이 있다.<br />
TIP<br />
스토리BDD 테스트는 구체적인 구현이 아닌 비즈니스 로직을 묘사하는 테스트다. 좋은 스토리BDD 테스<br />
트는 “장바구니에 상품을 추가할 때 증가하는 결제 금액”을 검증하고, 나쁜 스토리BDD 테스트는 “본문이<br />
product_id=1&quantity=2인 HTTP PUT 요청을 /cart URL에 보낼 때 증가하는 결제 금액”을 검증한<br />
다. 전자는 상위 수준에서 비즈니스 로직만을 포괄적으로 설명하는 반면 후자는 특정 구현에 대해 너무 구체<br />
적으로 묘사하고 있다.<br />
10장 테스팅<br />
83
www.hanbit.co.kr<br />
Hanbit eBook<br />
Realtime<br />
www.hanbit.co.kr/ebook<br />
DRM free!<br />
어떤 디바이스에서도 자유롭게<br />
eBook Oriented!<br />
전자책에 꼭 맞는 최적의 내용과 디자인<br />
Hanbit eBook<br />
Realtime 70<br />
Hanbit eBook<br />
Realtime 49 89<br />
Hanbit eBook<br />
Realtime 90<br />
Hanbit eBook<br />
Realtime 49 92<br />
MFC<br />
프로그래밍<br />
주식분석 프로그램 만들기<br />
김세훈 지음<br />
JavaScript<br />
Promise<br />
azu지음 /주우영옮김<br />
STOMP와 MQTT로 개발하는 IoT 이연복 지음<br />
모바일/웹 애플리케이션<br />
Mobile and Web Messaging<br />
제프 메스닐 지음 / 조건희 옮김<br />
자바 개발자를 위한<br />
Vert.x<br />
모바일/웹 메시징 애플리케이션 개발
www.hanbit.co.kr<br />
즐거운 상상이 가득! 2015년 화제의 신간<br />
즐거운 상상이 가득! 2015년 화제의 신간<br />
전자부품 백과사전 vol.2<br />
전자부품 백과사전 vol.1<br />
찰스 플랫 지음 / 배지은 옮김 / 30,000원<br />
취미공학에 필요한 핵심 전자부품을<br />
사전식으로 정리한 안내서.<br />
시리즈의 두 번째 도서다.<br />
Zero to Maker<br />
: 누구나 메이커가 될 수 있다<br />
데이비드 랭 지음 / 장재웅 옮김 / 14,000원<br />
전자부품 백과사전 vol.2 찰스 플랫 지음 / 가격미정<br />
일반인에서 메이커로. 날백수에서 무인 잠<br />
수정 된 사나이, 시리즈의 데이비드 두 번째 도서다.<br />
랭의 메이커 도전기.<br />
Zero to Maker<br />
: 누구나 메이커가 될 수 있다<br />
전자부품 백과사전 vol.1<br />
데이비드 랭 지음 / 장재웅 Maker 옮김 / 14,000원 Pro<br />
존 베이첼 지음 / 가격미정<br />
일반인에서 메이커로. 날백수에서 무인 잠<br />
메이커라면 반드시 읽어야 할 필수 계발<br />
수정 회사 CEO가 된 사나이, 데이비드<br />
서. 프로 메이커들과의 인터뷰 및 에세이<br />
랭의 메이커 도전기.<br />
수록.<br />
프로젝트로 배우는 라즈베리 파이 도날드 노리스 지음 / 임지순 옮김<br />
다양한 실전 프로젝트를 통해 라즈베리 파이를 쉽고 재미있게 배워본다.<br />
찰스 플랫 지음 / 배지은 옮김 / 30,000원<br />
처음 시작하는 센서<br />
취미공학에 필요한 핵심 전자부품을<br />
사전식으로 정리한 안내서.<br />
찰스 플랫 지음 / 가격미정<br />
Maker Pro<br />
존 베이첼 지음 / 가격미정<br />
메이커라면 반드시 읽어야 할 필수 계발<br />
키모 카르비넨,<br />
테로 카르비넨 지음<br />
임지순 옮김 / 13,000원<br />
세상을 수치로 읽어내는<br />
부품인 센서를 알려주<br />
는 책. 이 책을 통해 자신<br />
만의 프로젝트에 다양한<br />
처음 시작하는 센서<br />
센서를 사용해보자.<br />
키모 카르비넨,<br />
테로 카르비넨 지음<br />
임지순 옮김 / 13,000원<br />
세상을 수치로 읽어내는<br />
Make: 센서<br />
부품인 센서를 알려주<br />
키모 카르비넨, 테로 카르비<br />
넨, 빌 발토카리 지음 는 책. 이 책을 통해 자신<br />
/ 가격미정<br />
만의 프로젝트에 다양한<br />
필수 전자부품인 센서를<br />
마이크로 컨트롤러 보드 센서를 사용해보자.<br />
에 응용하는 방법을 담<br />
았다.<br />
Make: 센서<br />
키모 카르비넨, 테로 카르비<br />
넨, 빌 발토카리 지음<br />
/ 가격미정<br />
필수 전자부품인 센서를<br />
마이크로 컨트롤러 보드<br />
에 응용하는 방법을 담<br />
았다.
새로운 패러다임의 최신 <strong>PHP</strong>를 만나다<br />
<strong>PHP</strong>는 르네상스를 맞이했다. 객체지향, 네임스페이스, 트레이트, 클로저 등의 현대적 기능과 풍부한 컴포넌트 라이<br />
브러리로 원숙하고 완전한 모던 언어로 다시 태어났다. 하지만 인터넷에는 아직도 낡은 <strong>PHP</strong> 튜토리얼이 넘쳐난다.<br />
이 책은 ‘<strong>PHP</strong> The Right Way’의 창안자로 유명한 조시 록하트가 현대화된 <strong>PHP</strong>의 세련된 기능을 설명하고 올<br />
바른 개발 습관을 길러주는 모범 사례들을 담은 실용서다. <strong>PHP</strong>에 대한 기본적인 이해가 있으며 자신의 기량을 강<br />
화하고 싶은 모든 개발자를 위한 책이다.<br />
•네임스페이스, 트레이트, 제너레이터, 클로저 등의 모던 <strong>PHP</strong> 기능<br />
•<strong>PHP</strong> 컴포넌트를 검색, 사용, 작성하는 방법<br />
•애플리케이션 보안, 데이터베이스 작업, 에러와 예외 등에 대한 모범 사례<br />
•배포, 튜닝, 테스팅, 프로파일링에 필요한 도구와 기술<br />
•페이스북이 선보인 HHVM과 Hack이 최신 <strong>PHP</strong>에 미친 영향<br />
•프로덕션 서버에 대응하는 로컬 개발 환경 구축<br />
“나는 <strong>PHP</strong> 언어와 커뮤니티의 현 상황을 제대로 반영한 서적을 찾느라 수년을 보냈다. 이제 주저하지 않고 『<strong>Modern</strong><br />
<strong>PHP</strong>』 를 추천한다.”<br />
- 에드 핀클러, 개발자 겸 블로거(funkatron.com)<br />
“프로그래밍에서 절대 변하지 않는 진리는 ‘프로그래밍은 변한다’는 사실뿐이다. <strong>PHP</strong>는 변하고 있고 여러분의 개발 방법<br />
역시 변해야만 한다. 조시는 최신 <strong>PHP</strong>로 작성하기 위해 알아야 할 도구와 개념을 제시한다.”<br />
- 캘 에번스, E.I.C.C. CEO<br />
예제 소스 http://git.io/vchsm<br />
한빛미디어와 오라일리의 웹사이트로 오세요.<br />
www.hanbit.co.kr<br />
www.oreilly.com<br />
웹 / <strong>PHP</strong><br />
정가 22,000원