Modern PHP-미리보기

Page 1

네임스페이스, 트레이트, 클로저부터 모범 사례와 최신 도구까지

Modern

PHP

조시 록하트 지음 정병열 옮김


w w w. h a n b i t . c o . k r

이것이 프로그래밍이다! 저자 직강 동영상 제공!

이것이 안드로이드다

이것이 C언어다

이것이 자바다

진정한 안드로이드 개발자로 이끌어줍니다.

세상에 없던 새로운 C언어 입문서 탄생!

가장 중요한 프로그래밍 언어를 하나 배워야 한다면, 결론은 자바다!

SDK 5.0 롤리팝 호환!

삼성, LG에서 펼쳐졌던 전설의 명강의를 풀타임 동영상 강좌로!

중급 개발자로 나아가기 위한 람다식, JavaFX, NIO 수록

이보다 더 확실한 방법은 없다, 칠판강의

책만 보고, 동영상 강좌로도 만족하지 못했다면 Daum 카페 '슈퍼드로이드'에서 만나요

전체 동영상 강좌 유투브 전격 공개!

자바의 모든 것을 알려주는 인터넷 강의 궁금한 것은 카페에서!

cafe.daum.net/superdroid

http://goo.gl/tJK3Tu

cafe.naver.com/thisisjava

박성근 저 | 1,164쪽 | 45,000원

서현우 저 | 708쪽 | 25,000원

신용권 저 | 1,224쪽 | 30,000원


w w w. h a n b i t . c o . k r

지금은 모던 웹 시대! 모던 웹 디자인을 위한

모던 웹을 위한

HTML5 + CSS3 입문 HTML5 분야 부동의 1위 도서

JavaScript + jQuery 입문

HTML5 표준안 확정에 맞춘 완전 개정판의 귀환!

자바스크립트에서 제이쿼리, 제이쿼리 모바일까지 한 권으로 끝낸다!

HTML5 권고안과 최신 웹 브라우저 환경 대응

시대의 흐름에 맞춰 다시 쓴 자바스크립트 교과서

윤인성 저 | 624쪽 | 30,000원

윤인성 저 | 980쪽 | 32,000원

모던 웹을 위한

HTML5 + CSS3 정복

Node.js

프로그래밍 페이스북, 월마트, 링크드인은 왜 Node.js를 선택했는가?

필요한 것만 배워 바로 현장에서 쓰는 HTML5

이 물음에 대한 답은 Node.js가 보여주는 빠른 처리 능력 때문이다.

순서대로 읽으며 실습할 수 있는 HTML5 자습서

윤인성 저 | 484쪽 | 25,000원

김상형 저 | 700쪽 | 32,000원




| 표지 설명 | 표지 동물은 호주검은머리따오기(학명: Threskiornis spinicollis )다. 오스트레일리아, 뉴기니, 인도네시아 일부 지역에 서식한다. 호주검은머리따오기는 75cm까지 자라는 대형 조류다. 성체의 목에 나타나는 독특하고 뻣뻣한 깃 털에서 밀짚따오기straw-necked ibisz라는 영문명이 유래됐으며, 길고 구부러진 부리로 물속에서 곤충, 연체 동물, 개구리 등을 잡아낼 수 있다. 경작지에서는 농작물에 해를 입힐 수 있는 벌레나 메뚜 기, 귀뚜라미 등을 잡아먹기 때문에 농부들이 반기는 새다. 이 새는 떠돌이 생활을 하며 무리를 지어 서식지를 옮겨 다니는데, 얕은 담수성 습지나 인공적으 로 경작된 목초지, 늪지와 산호 지대의 가장자리를 좋아한다. 번식기에는 나뭇가지나 갈대를 모 아 물가의 나무 위에 큰 컵 모양으로 둥지를 틀며 종종 호주흰따오기와 함께 둥지 군집을 이룬다고 알려져 있다. 이런 습성 탓 에, 앙상한 나무의 높은 가지에 서서 하늘을 배경으로 뚜렷한 실루엣을 남기는 장면을 쉽게 목격할 수 있다. 오라일리 책 표지에 등장하는 동물은 대부분 멸종 위기에 처해있으며 모두 세계적으로 중요한 가치를 지닌다. 이들을 돕는 방 법을 알아보려면 http://animals.oreilly.com에 방문하기 바란다. 표지 그림은 『Woods Illustrated Natural History』에서 가져왔다.

Modern PHP : 네임스페이스, 트레이트, 클로저부터 모범 사례와 최신 도구까지 초판발행 2015년 10월 20일 지은이 조시 록하트 / 옮긴이 정병열 / 펴낸이 김태헌 펴낸곳 한빛미디어 (주) / 주소 서울시 마포구 양화로 7길 83 한빛미디어(주) IT출판부 전화 02 – 325 – 5544 / 팩스 02 – 336 – 7124 등록 1999년 6월 24일 제10 – 1779호 / ISBN 978 – 89 – 6848 – 225 – 0 93000 총괄 배용석 / 책임편집 최현우 / 기획 이복연, 강은희 / 편집 홍원규 디자인 강은영 영업 김형진, 김진불, 조유미 / 마케팅 박상용, 송경석, 서은옥 / 제작 박성우 이 책에 대한 의견이나 오탈자 및 잘못된 내용에 대한 수정 정보는 한빛미디어(주)의 홈페이지나 아래 이메일로 알려주십시오. 잘못된 책은 구입하신 서점에서 교환해 드립니다. 책값은 뒤표지에 표시되어 있습니다. 한빛미디어 홈페이지 www.hanbit.co.kr / 이메일 ask@hanbit.co.kr

Published by HANBIT Media, Inc. Printed in Korea Copyright © 2015 O’Reilly Media & HANBIT Media, Inc. Authorized translation of the English edition of Modern PHP ISBN: 9781491905012 © 2015 Josh Lockhart. This translation is to be published and sold by permission of O’Reilly Media, Inc., the owner of all rights to publish and sell the same. 이 책의 저작권은 오라일리와 한빛미디어 (주)에 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 복제 및 무단 전재를 금합니다.

지금 하지 않으면 할 수 없는 일이 있습니다. 책으로 펴내고 싶은 아이디어나 원고를 메일 ( writer@hanbit.co.kr ) 로 보내주세요. 한빛미디어(주)는 여러분의 소중한 경험과 지식을 기다리고 있습니다.




로럴을 위해


옮긴이의 글

처음으로 실무에 PHP를 사용했던 때는 2002년이었다. 한 중소 규모의 웹 서비스 개발을 맡았 을 때였는데, 처음에는 서블릿으로 개발할 계획이었지만 몇 가지 이유로 최종 기획 단계에서

PHP로 결정됐다. 사이트 전체를 PHP로 개발하는 일은 처음이었던지라 우려도 있었지만 막상 작업해보니 Perl CGI나 서블릿을 사용하는 것보다 쉽고 빠르게 사이트를 구축할 수 있어 새삼 놀랐던 기억이 난다. PHP의 풍부한 내장 라이브러리와 유연한 출력 제어 능력 덕분이었다. 아닌 게 아니라 그즈음 우리나라에서는 이미 PHP가 빠른 속도로 자리를 잡아가고 있었다. 개 발 언어로서뿐만 아니라 호스팅 업체들이 주력으로 지원하는 언어로서도 각광받았다. 단기간 동안 호스팅 서비스 거의 대부분에 PHP가 탑재됐고 한쪽에서는 다양한 PHP 웹 애플리케이션 들이 제작되고 공개됐다. 자생적으로 형성된 국내 커뮤니티 웹 사이트가 대부분 이런 PHP 웹 프로그램들을 이용해 구축됐다. 이 시기에 큰 인기를 끌었던 PuryBBS, 제로보드4 등은 이후 에 나온 테터툴즈나 XE 같은 걸출한 프로젝트의 모태이기도 하다. 이런 면에서 보자면 우리나 라에서 PHP가 저변을 확대하는 과정은 국내 인터넷 문화의 폭발적 확장 과정과 어느 정도 궤 를 같이 한다고도 볼 수 있다.

PHP 같은 고참 스크립트 언어가 아직까지 각종 통계나 인기 순위에서 상위권을 차지하는 데 에는 이유가 있다. 나는 PHP가 지닌 매력의 본질이 자유로운 포용력이라고 생각한다. PHP는 끊임없이 언어 구조를 개선하고 유수의 라이브러리들을 통합하는 한편 스크립트 언어의 태생 적 한계를 극복하려는 시도도 멈추지 않았다. PHP 진영은 늘 다양한 프로젝트로 북적거리는 활기찬 분위기를 이어왔다. 여기에 수많은 개발자들의 활발한 참여가 더해져 PHP 개발 생태 계는 나날이 성숙해지고 있다. 특히 최근 몇 년간 PHP는 탄생 이후 가장 역동적인 변화의 시 기를 겪고 있다고 해도 과언이 아니다. 페이스북과 Hack으로 대변되는 외적 요인을 촉매로 언 어 자체의 근간부터 재정립되고 있으며, 그 결과 PHP 7이라는 또 한번의 큰 도약을 목전에 두 고 있다. 국내에서는 PHP가 대형 솔루션을 개발하기에 적합하지 않다거나 보안에 취약한 언어라고 생 각하는 이들도 있다. 역설적이게도 이런 부정적인 인식은 PHP가 지닌 강점에 기인한다. 입문

10


하기 쉽고 빠르게 개발할 수 있어 단기간에 많은 프로젝트에 도입됐지만 그에 반해 엔터프라이 즈급 솔루션 개발에 사용되거나 다양한 고도화 작업에 심도있게 활용된 사례가 드물기 때문이 다. 스크립트 언어의 특성상 소스코드가 공개되어 있다는 점도 기피 사유 중 하나였으며 국내

SI 프로젝트에 채택되는 플랫폼 구성이 다소 획일적이라는 실정도 한 몫 거들었다. 그러나 이 런 인식과는 달리 현재 PHP는 방대한 솔루션을 많은 개발자가 공동으로 작업할 수 있는 제반 환경을 충분히 갖추고 있다. 의존성과 패키징에 대한 표준이 정립됐으며 이들을 관리할 수 있 는 우수한 도구가 등장했고, 지속적인 통합과 자동화된 테스팅 또한 가능해졌다. 뿐만 아니라 완성도 높은 풀스택 프레임워크와 ORM, 강력한 템플릿 엔진들이 포진하고 있으며 셀 수 없이 많은 오픈소스 컴포넌트를 자유롭게 활용할 수 있다.

PHP의 기술적인 최신 동향과 그에 따른 모범 사례들에 대한 정보를 PHP 초심자나 다른 언어 개발자가 일목요연하게 열람하거나 편리하게 접할 수 있는 창구는 흔치 않다. 몇몇 선도적인 개발자들의 세미나와 블로그 기고만으로는 역부족이다. 특히나 최근 국내에는 PHP 관련 서적 들의 출간도 주춤한 편이어서 아쉬움이 더해가는 상황이었다. 『Modern PHP』는 이런 시점에 서 만난 가뭄의 단비 같은 책이다. 이 책은 ‘모던 PHP’라는 제목 그대로 PHP 언어의 최신 핵심 기능을 요점정리해줄 뿐만 아니 라 유머러스하고 친절한 설명과 이해하기 쉬운 예제를 통해 모범 사례와 발전된 개발 방법까지 제시해주는 실용서다. 저자인 조시 록하트는 유력 프레임워크의 개발자인 동시에 PHP에 대한 인식 제고를 위해 발벗고 나선 오피니언 리더로서, PHP에 대한 자신의 애정과 열정을 이 책에 고스란히 담아 놓았다. 또한 PHP 진영의 전반적인 근황에 대해 넓은 시각으로 잘 설명하고 있 어서 앞으로 공개될 PHP 7을 준비하는 데 있어서도 도움이 될만한 책이다.

PHP의 미래는 여전히 활짝 열려있고 잠재력 역시 무궁무진하다. 모쪼록 국내의 개발자들도 PHP의 짜릿한 변화의 순간에 기꺼이 동참하고 진보된 PHP를 온전히 활용할 수 있게 되기를 바라며, 그 과정에 이 책이 조금이나마 보탬이 될 수 있었으면 한다. 이 책이 나오기까지 도움을 주신 분들에게 진심으로 감사의 마음을 전하고 싶다. 먼저, 처음 번

11


역 의사를 전달했을 때 선뜻 기회를 제공해 준 한빛미디어 측에 감사드린다. 강은희 님과 최현 우 팀장님이 원고의 미숙한 부분을 명확히 짚어주고 적절한 가이드 라인을 제시해 준 덕분에 무사히 작업을 마무리할 수 있었다. 막히는 부분이 있을 때는 종종 주변에 도움을 구했다. 그 때마다 매번 새로운 시각과 다양한 아이디어로 생각의 물꼬를 틔워준 김재영 님에게도 감사드 린다. 마지막으로, 언제나 나를 지지하고 응원해주시는 부모님께 감사의 말씀을 드린다. _2015년 10월 정병열

옮긴이

정병열 cloudshadow@gmail.com

연세대학교 세라믹 공학과를 졸업하고 개발자와 번역자로 활동하고 있다. 어린 시절 BASIC 언어를 통해 프로그래밍을 처음 경험 했으며 PC통신 시절에는 프로그래밍 관련 동호회에서 활동했다. 2000년대 초반부터 프로그래밍 언어와 플랫폼에 관계없이 다양 한 웹 사이트 및 솔루션 개발 프로젝트를 수행했으며 몇 년간은 리눅스 시스템 엔지니어로 근무하기도 했다. 분야를 가리지 않는 폭 넓은 관심사를 가지고 있으며 흥미를 느끼면 어떻게든 파고들어 습득하고 마는 성격의 소유자다. 현재는 취업포털 업체에서 다양한 업무를 수행하고 있다.

12


들어가며

온라인에는 수없이 많은 PHP 튜토리얼이 있다. 이들 대부분은 이미 낡고 쓸모 없어진 지 오래 지만 불행히도 구글 검색 결과에 살아남아 여전히 참조자료로 활용된다. 이런 낡은 정보를 무 분별하게 받아들인 PHP 프로그래머는 자신도 모르는 사이에 느리고 보안에 취약한 PHP 애플 리케이션을 만들게 될 위험에 처한다. 나는 2013년에 이러한 문제를 인식했고, 그때 가졌던 문 제의식은 PHP The Right Way (http://www.phptherightway.com )를 시작하는 가장 큰 계기 가 됐다. PHP The Right Way는 PHP 프로그래머가 PHP 커뮤니티 권위자들이 제공하는 품 질 높은 최신 정보에 쉽게 접근할 수 있게 하려고 만든 것이다. 『Modern PHP』는 이와 같은 목표를 지향하는 나의 다음 시도다. 이 책은 참고서가 절대 아니 며 여러분과 내가 친근하고 재미있게 나눈 대화를 담은 기록과도 같다. 나는 최신 PHP 프로 그래밍 언어를 소개하는 한편, 나의 오픈소스 프로젝트와 일상 업무에서 매일 사용하는 최신

PHP 기술을 보여줄 것이다. 그리고 여러분이 최신 코딩 표준을 사용하여 자신의 컴포넌트와 라이브러리들을 PHP 커뮤니티에서 공유할 수 있도록 도울 것이다. ‘커뮤니티’라는 말이 되풀이되어 나올 것이다. 가끔 극적인 사건이 있긴 해도 PHP 커뮤니티는 대체로 프로그래머들에게 친근하고 유용하며 우호적이다. 만약 이 책에서 언급한 특정 내용에 대해 궁금해지면 자신의 지역 PHP 사용자 그룹에 가서 질문해보기 바란다. 여러분이 더 나은

PHP 프로그래머가 되도록 도와줄 개발자들은 얼마든지 가까이에 있을 것이다. 지역 PHP 사 용자 그룹은 당신이 이 책을 다 읽은 후에도 지속적으로 PHP 스킬을 향상할 수 있게 도와줄 귀중한 자원이다.

이 책에 대하여 시작하기에 앞서 몇 가지를 염두에 두었으면 한다. 첫째, 다양한 PHP 사용 방법을 이 책에서 모두 다루기에는 시간이 부족하다. 대신 나의 PHP 사용 방법을 보여줄 것이다. 독단적인 접근 방식임에 분명하지만, 나는 많은 PHP 개발자가 채

13


택한 사례와 표준을 그대로 사용한다. 이 책에서 얻은 것들을 여러분의 프로젝트에 즉시 적용 할 수 있을 것이다. 둘째, 여러분이 변수와 조건문, 반복문 등에 익숙하다고 간주한다. PHP를 알아야 하는 것은 아니지만, 최소한 프로그래밍 기초 개념에 대한 기본 이해는 필요하다. 커피를 곁들여도 된다. 그 외의 모든 것은 내가 제공해줄 것이다. 셋째, 나는 여러분이 특정 운영체제를 사용한다고 간주하지 않는다. 하지만 앞으로 나올 코드 예제는 리눅스에서 작성한다. 배시Bash 명령어는 우분투용과 CentOS용을 함께 제공하며 일부 는 OS X에서도 실행할 수 있다. 만약 윈도우 사용자가 이 책의 예제 코드를 실행하고자 한다 면 가급적 리눅스 가상머신을 사용하기 바란다.

이 책의 구성 1부에서는 네임스페이스namespace, 제너레이터generator, 트레이트trait 같은 PHP의 새로운 기능을 설명한다. 모던 PHP 언어를 소개하고 여러분이 지금까지 몰랐을 수도 있는 기능을 선보인다.

2부에서는 PHP 애플리케이션에서 구현해야 할 모범 사례들을 알아본다. PSR에 대해 들어보 았을 것이다. 하지만 그것이 무엇인지, 어떻게 사용하는 것인지 온전하게 확신할 수 있는가? 사용자 입력의 위험을 제거하고 데이터베이스 쿼리를 안전하게 사용하는 방법을 알고 싶은가? 그렇다면 2부를 보라.

3부는 1부와 2부보다 더 기술적이다. 배포, 튜닝, 테스트 그리고 PHP 애플리케이션을 프로파 일링하는 방법을 알아본다. 카피스트라노Capistrano를 이용한 배포 전략을 세우고 PHP유닛PHPUnit 과 트래비스 CITravis CI 같은 테스팅 도구를 이야기한다. 그리고 PHP 애플리케이션의 성능을 높 이기 위한 PHP 튜닝 방법도 알아본다. 부록 A는 PHP-FPM 설치와 구성에 대해 단계별 안내를 제공한다.

14


부록 B는 프로덕션 서버에 유사하게 대응하는 로컬 개발 환경을 구축하는 방법을 설명한다. 또 한 신속한 구축에 도움을 줄 대안 도구로 베이그런트Vagrant, 퍼핏Puppet, 셰프Chef를 알아본다.

감사의 말 이 책은 나의 첫 책이다. 오라일리에서 『Modern PHP』 집필을 제안했을 때 나는 정말이지 흥 분과 두려움에 휩싸여버리고 말았다. 어깨춤이 절로 나올 정도였다. 오라일리가 집필을 제안하 다니, 굉장한 일이지 않은가! 기쁨도 잠시, 흥분을 가라앉히고 나는 스스로에게 정말 그렇게 많 은 양을 쓸 수 있을지 물었다. 책을 쓰는 것은 그리 만만한 작업이 아니기 때문이다. 물론, 즉시 “네”라고 말했다. 가족, 친구, 동료, 편집자, 나를 전적으로 지지해줄 독자들이 있었 기 때문에 기꺼이 『Modern PHP』를 쓰겠다고 할 수 있었다. 그들이 보내준 귀중한 조언에 감 사의 뜻을 밝히고 싶다. 이들이 아니었다면, 이 책은 절대로 나올 수 없었다. 우선, 오라일리 미디어의 담당 편집자 앨리슨 맥도날드(@allyatoreilly )에게 감사하고 싶다. 앨리는 친절하고, 비판적이고, 든든하며, 명석하다. 그녀는 내가 방향을 잃을 때마다 적절히 바 로 잡아주어야 할 정확한 때와 방법을 알고 있었다. 그녀는 내게 있어 최고의 편집자다. 또한 기술 검토를 해준 아담 페어홀름(@adamfairholm )과 에드 핀클러(@funkatron )에게 도 감사한다. 아담은 뉴프랭글드(https://www.newfangled.com )의 뛰어난 웹 개발자며, 뮤직 비디오 데이터베이스 웹 사이트 IMVDb (http://imvdb.com )의 개발자로 유명하다. 에드는 어 마어마한 PHP 실력과 개성적인 팟캐스트 /dev/hell (http://devhell.info ), 오픈소싱 정신질환 캠페인Open Sourcing Mental Illness campaign ( http://funkatron.com/osmi )으로 잘 알려져 있다. 아담과 에드는 내 초고의 멍청하고 비논리적이며 부정확한 부분들을 지적해주었다. 그들의 노골적이 고 정직한 피드백에 대해서는 어떠한 말로도 감사의 표현을 다 할 수 없다. 그들의 지도와 지혜 에 영원히 감사한다. 최종 원고에 실수나 오류가 있다면 그것은 전적으로 내 책임이다.

15


늘 나를 격려해준 뉴미디어 캠페인New Media Campaigns (http://www.newmediacampaigns.com )의 동료들 엘, 클레이, 크리스, 알렉스, 패트릭, 애슐리, 레니, 클레어, 토드, 파스칼, 헨리, 네이 선! 그리고 처음부터 끝까지 친절하게 격려해준 모든 이에게 고개 숙여 감사한다. 가장 중요한 나의 가족 로럴, 이선, 테사, 찰리, 리사, 글렌, 리즈에게 감사한다. 그들의 격려가 없었다면 절대로 이 책을 낼 수 없었을 것이다. 사랑스러운 나의 아내 로럴, 당신의 인내에 감 사한다. 밤 늦은 집필 작업 때문에 매번 카리부 커피Caribou Coffe1에 동행해주고 주말에도 아내에 게 소홀했던 나를 이해해줘서 감사한다. 일정을 맞추고 지속적으로 동기부여할 수 있게 해준 것에 감사한다. 지금부터 영원토록 당신을 사랑하겠다. _저자 조시 록하트

지은이

조시 록하트 Josh Lockhart

조시 록하트는 웹 애플리케이션과 API를 빠르게 개발할 수 있는 초소형 PHP 프레임워크 슬림Slim을 개발했다. 또한 전 세계 PHP 개발자들에게 모범 사례를 장려하고 양질의 정보를 제공하는 권장안으로 유명한 ‘PHP The Right Way’를 창안했으며 지금도 운 영하고 있다. 조시는 노스캐롤라이나주 칼버러에 위치한 풀-서비스 웹 디자인, 개발, 마케팅 에이전시 업체인 뉴미디어 캠페인(http://www.

newmediacampaigns.com/)에서 개발자로 일하고 있다. HTML, CSS, PHP, 자바스크립트, Bash와 다양한 콘텐츠 관리 프 레임워크를 이용한 맞춤 애플리케이션 만들기를 좋아한다. 2008년 노스캐롤라이나대학교 채플힐 캠퍼스 정보문헌학 과정을 수료 했으며 아내인 로럴과 함께 두 마리 개를 키우며 노스캐롤라이나주 채플힐에 거주하고 있다. 조시의 트위터(https://twitter.com/codeguy)를 팔로우하거나 깃허브(https://github.com/codeguy)에서 그의 오픈소스 프 로젝트들을 확인할 수 있다.

1 역자주_ 커피숍 체인의 이름이다.

16


CONTENTS

옮긴이의 글 �������������������������������������������������������������������������������������������������������������������� 6

들어가며 ������������������������������������������������������������������������������������������������������������������������ 9

PART

1 언어 기능

CHAPTER

1 새로운 PHP

1.1 과거 ���������������������������������������������������������������������������������������������������������������������������� 27

1.2 현재 ���������������������������������������������������������������������������������������������������������������������������� 28

1.3 미래 ���������������������������������������������������������������������������������������������������������������������������� 30

CHAPTER

2 기능

2.1 네임스페이스 ���������������������������������������������������������������������������������������������������������������� 31

2.1.1 네임스페이스를 사용하는 이유 �������������������������������������������������������������������������������� 33

2.1.2 선언 ������������������������������������������������������������������������������������������������������������������� 34

2.1.3 임포트와 별칭 ������������������������������������������������������������������������������������������������������ 35

2.1.4 유용한 팁 ������������������������������������������������������������������������������������������������������������ 38

2.2 인터페이스로 코딩하기 ��������������������������������������������������������������������������������������������������� 40 2.3 트레이트 ���������������������������������������������������������������������������������������������������������������������� 45

2.3.1 트레이트를 사용하는 이유 �������������������������������������������������������������������������������������� 46

2.3.2 트레이트 생성 ������������������������������������������������������������������������������������������������������ 47

2.3.3 트레이트 사용 ������������������������������������������������������������������������������������������������������ 49

2.4 제너레이터 ������������������������������������������������������������������������������������������������������������������� 50

2.4.1 제너레이터 생성 ��������������������������������������������������������������������������������������������������� 51

2.4.2 제너레이터 사용 ��������������������������������������������������������������������������������������������������� 52

17


CONTENTS

2.5 클로저 ������������������������������������������������������������������������������������������������������������������������� 54

2.5.1 생성 ������������������������������������������������������������������������������������������������������������������� 55

2.5.2 상태 등록 ������������������������������������������������������������������������������������������������������������ 56

2.6 젠드 오피캐시 ��������������������������������������������������������������������������������������������������������������� 59

2.6.1 젠드 오피캐시 활성화 �������������������������������������������������������������������������������������������� 59

2.6.2 젠드 오피캐시 설정 ����������������������������������������������������������������������������������������������� 61

2.6.3 젠드 오피캐시 사용 ����������������������������������������������������������������������������������������������� 62

2.7 내장 HTTP 서버 ����������������������������������������������������������������������������������������������������������� 62

2.7.1 서버 실행 ������������������������������������������������������������������������������������������������������������ 63

2.7.2 서버 설정 ������������������������������������������������������������������������������������������������������������ 63

2.7.3 라우터 스크립트 ��������������������������������������������������������������������������������������������������� 64

2.7.4 내장 서버 감지 ����������������������������������������������������������������������������������������������������� 64

2.7.5 단점 ������������������������������������������������������������������������������������������������������������������� 65

2.8 다음 장에서 다룰 내용 ���������������������������������������������������������������������������������������������������� 65

PART

2 모범 사례

CHAPTER

3 표준 3.1 PHP-FIG 구조대 ���������������������������������������������������������������������������������������������������������� 70

3.2 프레임워크 상호운용성 ��������������������������������������������������������������������������������������������������� 70

3.2.1 인터페이스 ���������������������������������������������������������������������������������������������������������� 71

3.2.2 오토로딩 ������������������������������������������������������������������������������������������������������������� 71

3.2.3 코드 스타일 ��������������������������������������������������������������������������������������������������������� 71

3.3 PSR ��������������������������������������������������������������������������������������������������������������������������� 72 3.4 PSR-1: 기본 코드 스타일 ����������������������������������������������������������������������������������������������� 73 3.5 PSR-2: 엄격한 코드 스타일 �������������������������������������������������������������������������������������������� 74

18


3.6 PSR-3: 로거 인터페이스 ������������������������������������������������������������������������������������������������ 77

3.6.1 PSR-3 로거 작성 ������������������������������������������������������������������������������������������������ 78

3.6.2 PSR-3 로거 사용 ������������������������������������������������������������������������������������������������ 79

3.7 PSR-4: 오토로더 ���������������������������������������������������������������������������������������������������������� 80

3.7.1 왜 오토로더가 중요한가 ����������������������������������������������������������������������������������������� 80

3.7.2 PSR-4 오토로더 전략 ������������������������������������������������������������������������������������������ 81

3.7.3 PSR-4 오토로더 작성(을 하면 안 되는 이유) ������������������������������������������������������������� 82

CHAPTER

4 컴포넌트 4.1 컴포넌트를 사용하는 이유 ����������������������������������������������������������������������������������������������� 85

4.2 컴포넌트란 무엇인가 ������������������������������������������������������������������������������������������������������ 86 4.3 컴포넌트 vs. 프레임워크 ������������������������������������������������������������������������������������������������� 87

4.3.1 모든 프레임워크가 나쁜 것은 아니다 ������������������������������������������������������������������������ 88

4.3.2 알맞은 도구를 사용하라 ����������������������������������������������������������������������������������������� 89

4.4 컴포넌트 선택 ��������������������������������������������������������������������������������������������������������������� 90

4.4.1 쇼핑 ������������������������������������������������������������������������������������������������������������������� 90

4.4.2 선택 ������������������������������������������������������������������������������������������������������������������� 91

4.4.3 피드백 남기기 ������������������������������������������������������������������������������������������������������ 92

4.5 컴포넌트 사용 ��������������������������������������������������������������������������������������������������������������� 92

4.5.1 컴포넌트 설치 ������������������������������������������������������������������������������������������������������ 93

4.5.2 컴포넌트 사용법 ��������������������������������������������������������������������������������������������������� 94

4.5.3 예제 프로젝트 ������������������������������������������������������������������������������������������������������ 96

4.5.4 컴포저와 사설 저장소 ������������������������������������������������������������������������������������������ 100

4.6 컴포넌트 만들기 ���������������������������������������������������������������������������������������������������������� 101

4.6.1 벤더와 패키지명 ������������������������������������������������������������������������������������������������� 102

4.6.2 네임스페이스 ����������������������������������������������������������������������������������������������������� 103

4.6.3 파일시스템 구성 ������������������������������������������������������������������������������������������������� 103

19


CONTENTS

4.6.4 composer.json 파일 ����������������������������������������������������������������������������������������� 104

4.6.5 README 파일 ������������������������������������������������������������������������������������������������� 106

4.6.6 컴포넌트 구현 ���������������������������������������������������������������������������������������������������� 107

4.6.7 버전 관리 ���������������������������������������������������������������������������������������������������������� 109

4.6.8 패키지스트 등록 ������������������������������������������������������������������������������������������������� 109

4.6.9 컴포넌트 사용 ���������������������������������������������������������������������������������������������������� 111

CHAPTER

5 모범 사례 5.1 위험 제거, 유효성 검사, 예외 처리 ����������������������������������������������������������������������������������� 114

5.1.1 입력값 위험 제거 ������������������������������������������������������������������������������������������������ 114

5.1.2 유효성 검사 ������������������������������������������������������������������������������������������������������� 118

5.1.3 출력 예외 처리 ��������������������������������������������������������������������������������������������������� 119

5.2 비밀번호 �������������������������������������������������������������������������������������������������������������������� 120

5.2.1 사용자 비밀번호를 절대 알 수 없게 할 것 ���������������������������������������������������������������� 120

5.2.2 비밀번호에 절대 제한을 두지 말 것 ������������������������������������������������������������������������ 120

5.2.3 사용자 비밀번호를 절대 이메일로 보내지 말 것 �������������������������������������������������������� 121

5.2.4 사용자 비밀번호를 bcrypt로 해시하라 ������������������������������������������������������������������� 121

5.2.5 비밀번호 해싱 API ���������������������������������������������������������������������������������������������� 122

5.2.6 PHP 5.5.0 이전의 비밀번호 해싱 API ������������������������������������������������������������������� 127

5.3 날짜, 시간, 시간대 �������������������������������������������������������������������������������������������������������� 128

5.3.1 기본 시간대 지정 ������������������������������������������������������������������������������������������������ 128

5.3.2 DateTime 클래스 ���������������������������������������������������������������������������������������������� 129

5.3.3 DateInterval 클래스 ������������������������������������������������������������������������������������������� 130

5.3.4 DateTimeZone 클래스 �������������������������������������������������������������������������������������� 132

5.3.5 DatePeriod 클래스 �������������������������������������������������������������������������������������������� 133

5.3.6 nesbot/carbon 컴포넌트 ����������������������������������������������������������������������������������� 134

5.4 데이터베이스 �������������������������������������������������������������������������������������������������������������� 134

20


5.4.1 PDO 확장 �������������������������������������������������������������������������������������������������������� 135

5.4.2 데이터베이스 연결과 DSN ����������������������������������������������������������������������������������� 135

5.4.3 준비된 구문 ������������������������������������������������������������������������������������������������������� 138

5.4.4 쿼리 결과 ���������������������������������������������������������������������������������������������������������� 140

5.4.5 트랜잭션 ����������������������������������������������������������������������������������������������������������� 143

5.5 멀티바이트 문자열 ������������������������������������������������������������������������������������������������������� 147

5.5.1 문자 인코딩 ������������������������������������������������������������������������������������������������������� 147

5.5.2 UTF-8 데이터 �������������������������������������������������������������������������������������������������� 148

5.6 스트림 ����������������������������������������������������������������������������������������������������������������������� 149

5.6.1 스트림 래퍼 ������������������������������������������������������������������������������������������������������� 150

5.6.2 스트림 콘텍스트 ������������������������������������������������������������������������������������������������� 153

5.6.3 스트림 필터 ������������������������������������������������������������������������������������������������������� 154

5.6.4 사용자 정의 스트림 필터 �������������������������������������������������������������������������������������� 156

5.7 오류와 예외 ���������������������������������������������������������������������������������������������������������������� 159

5.7.1 예외 ����������������������������������������������������������������������������������������������������������������� 160

5.7.2 예외 처리기 ������������������������������������������������������������������������������������������������������� 164

5.7.3 오류 ����������������������������������������������������������������������������������������������������������������� 165

5.7.4 오류 처리기 ������������������������������������������������������������������������������������������������������� 167

5.7.5 개발 과정에서 오류와 예외 다루기 ������������������������������������������������������������������������� 169

5.7.6 프로덕션 ����������������������������������������������������������������������������������������������������������� 171

PART

3 배포, 테스팅, 튜닝

CHAPTER

6 호스팅 6.1 공유 서버 ������������������������������������������������������������������������������������������������������������������� 177

6.2 가상 사설 서버 ������������������������������������������������������������������������������������������������������������ 178

21


CONTENTS

6.3 전용 서버 ������������������������������������������������������������������������������������������������������������������� 179 6.4 PaaS ������������������������������������������������������������������������������������������������������������������������ 179 6.5 호스팅 선택 ���������������������������������������������������������������������������������������������������������������� 180

CHAPTER

7 프로비저닝 7.1 목표 �������������������������������������������������������������������������������������������������������������������������� 182

7.2 서버 설정 ������������������������������������������������������������������������������������������������������������������� 182

7.2.1 최초 로그인 ������������������������������������������������������������������������������������������������������� 183

7.2.2 소프트웨어 업데이트 ������������������������������������������������������������������������������������������� 183

7.2.3 비루트 사용자 ���������������������������������������������������������������������������������������������������� 184

7.2.4 SSH 키 쌍 인증 ������������������������������������������������������������������������������������������������� 185

7.2.5 비밀번호 인증 및 루트 로그인 비활성화 ������������������������������������������������������������������ 187

7.3 PHP-FPM ���������������������������������������������������������������������������������������������������������������� 188

7.3.1 설치 ����������������������������������������������������������������������������������������������������������������� 188

7.3.2 전역 설정 ���������������������������������������������������������������������������������������������������������� 189

7.3.3 풀 설정 ������������������������������������������������������������������������������������������������������������� 190

7.4 엔진엑스 �������������������������������������������������������������������������������������������������������������������� 193

7.4.1 설치 ����������������������������������������������������������������������������������������������������������������� 193

7.4.2 가상 호스트 ������������������������������������������������������������������������������������������������������� 193

7.5 서버 프로비저닝 자동화 ������������������������������������������������������������������������������������������������ 197 7.6 서버 프로비저닝 위임 ��������������������������������������������������������������������������������������������������� 197 7.7 추가 자료 ������������������������������������������������������������������������������������������������������������������� 198 7.8 다음 장에서 다룰 내용 �������������������������������������������������������������������������������������������������� 198

CHAPTER

22

8 튜닝 8.1 php.ini 파일 ��������������������������������������������������������������������������������������������������������������� 199


8.2 메모리 ����������������������������������������������������������������������������������������������������������������������� 200 8.3 젠드 오피캐시 ������������������������������������������������������������������������������������������������������������� 201 8.4 파일 업로드 ���������������������������������������������������������������������������������������������������������������� 203 8.5 최대 실행 시간 ������������������������������������������������������������������������������������������������������������ 204 8.6 세션 처리 ������������������������������������������������������������������������������������������������������������������� 205 8.7 출력 버퍼링 ���������������������������������������������������������������������������������������������������������������� 205 8.8 리얼패스 캐시 ������������������������������������������������������������������������������������������������������������� 206 8.9 다음 장에서 다룰 내용 �������������������������������������������������������������������������������������������������� 206

CHAPTER

9 배포 9.1 버전 관리 ������������������������������������������������������������������������������������������������������������������� 207

9.2 배포 자동화 ���������������������������������������������������������������������������������������������������������������� 208

9.2.1 단순하게 ����������������������������������������������������������������������������������������������������������� 208

9.2.2 예측 가능하게 ���������������������������������������������������������������������������������������������������� 208

9.2.3 가역적으로 �������������������������������������������������������������������������������������������������������� 208

9.3 카피스트라노 �������������������������������������������������������������������������������������������������������������� 208

9.3.1 작동 ����������������������������������������������������������������������������������������������������������������� 209

9.3.2 설치 ����������������������������������������������������������������������������������������������������������������� 210

9.3.3 설정 ����������������������������������������������������������������������������������������������������������������� 210

9.3.4 인증 ����������������������������������������������������������������������������������������������������������������� 212

9.3.5 원격 서버 ���������������������������������������������������������������������������������������������������������� 212

9.3.6 카피스트라노 훅 ������������������������������������������������������������������������������������������������� 213

9.3.7 애플리케이션 배포 ���������������������������������������������������������������������������������������������� 214

9.3.8 애플리케이션 되돌리기 ���������������������������������������������������������������������������������������� 214

9.4 참고 자료 ������������������������������������������������������������������������������������������������������������������� 214 9.5 다음 장에서 다룰 내용 �������������������������������������������������������������������������������������������������� 215

23


CONTENTS

CHAPTER

10 테스팅

10.1 테스트를 하는 이유 ������������������������������������������������������������������������������������������������������ 217

10.2 테스트 시점 ��������������������������������������������������������������������������������������������������������������� 218

10.2.1 개발 전 �������������������������������������������������������������������������������������������������������������

218

10.2.2 개발 도중 ����������������������������������������������������������������������������������������������������������

218

10.2.3 개발 후 �������������������������������������������������������������������������������������������������������������

219

10.3 테스트 대상 ����������������������������������������������������������������������������������������������������������������

219

10.4 테스트 방법 ����������������������������������������������������������������������������������������������������������������

219

10.4.1 단위 테스트 �������������������������������������������������������������������������������������������������������

220

10.4.2 테스트 주도 개발(TDD) ���������������������������������������������������������������������������������������

220

10.4.3 행위 주도 개발(BDD) ������������������������������������������������������������������������������������������

221

10.5 PHP유닛 �������������������������������������������������������������������������������������������������������������������

222

10.5.1 디렉터리 구조 ����������������������������������������������������������������������������������������������������

222

10.5.2 PHP유닛 설치 ���������������������������������������������������������������������������������������������������

223

10.5.3 Xdebug 설치 ����������������������������������������������������������������������������������������������������

224

10.5.4 PHP유닛 설정 ���������������������������������������������������������������������������������������������������

224

10.5.5 Whovian 클래스 �����������������������������������������������������������������������������������������������

226

10.5.6 WhovianTest 테스트 케이스 �������������������������������������������������������������������������������

227

10.5.7 테스트 수행 �������������������������������������������������������������������������������������������������������

230

10.5.8 코드 커버리지 ����������������������������������������������������������������������������������������������������

231

10.6 트래비스 CI를 통한 지속적인 테스팅 �������������������������������������������������������������������������������

232

10.6.1 설정 �����������������������������������������������������������������������������������������������������������������

232

10.6.2 실행 �����������������������������������������������������������������������������������������������������������������

233

10.7 참고 자료 �������������������������������������������������������������������������������������������������������������������

234

10.8 다음 장에서 다룰 내용 ��������������������������������������������������������������������������������������������������

234

24


CHAPTER

11 프로파일링

11.1 프로파일러 사용 시점 ��������������������������������������������������������������������������������������������������� 235

11.2 프로파일러 종류 ���������������������������������������������������������������������������������������������������������� 236

11.3 Xdebug �������������������������������������������������������������������������������������������������������������������� 236

11.3.1 설정 �����������������������������������������������������������������������������������������������������������������

237

11.3.2 발동 �����������������������������������������������������������������������������������������������������������������

237

11.3.3 분석 �����������������������������������������������������������������������������������������������������������������

238

11.4 XHProf ���������������������������������������������������������������������������������������������������������������������

238

11.4.1 설치 �����������������������������������������������������������������������������������������������������������������

238

11.4.2 XHGUI ������������������������������������������������������������������������������������������������������������

239

11.4.3 설정 �����������������������������������������������������������������������������������������������������������������

240

11.4.4 발동 �����������������������������������������������������������������������������������������������������������������

240

11.5 뉴렐릭 프로파일러 �������������������������������������������������������������������������������������������������������

241

11.6 블랙파이어 프로파일러 �������������������������������������������������������������������������������������������������

241

11.7 참고 자료 �������������������������������������������������������������������������������������������������������������������

242

11.8 다음 장에서 다룰 내용 ��������������������������������������������������������������������������������������������������

242

CHAPTER

12 HHVM과 Hack 12.1 HHVM ���������������������������������������������������������������������������������������������������������������������� 244

12.1.1 페이스북과 PHP ������������������������������������������������������������������������������������������������

244

12.1.2 HHVM과 젠드 엔진의 동등성 �������������������������������������������������������������������������������

246

12.1.3 HHVM은 내게 적당한가 ��������������������������������������������������������������������������������������

246

12.1.4 설치 �����������������������������������������������������������������������������������������������������������������

247

12.1.5 설정 �����������������������������������������������������������������������������������������������������������������

248

12.1.6 확장 �����������������������������������������������������������������������������������������������������������������

249

25


CONTENTS

12.1.7 슈퍼바이저를 이용한 HHVM 관제 �������������������������������������������������������������������������

249

12.1.8 HHVM, FastCGI, 엔진엑스 ���������������������������������������������������������������������������������

251

12.2 Hack 언어 �����������������������������������������������������������������������������������������������������������������

253

12.2.1 PHP를 Hack으로 변환하기 ���������������������������������������������������������������������������������

253

12.2.2 타입이란 �����������������������������������������������������������������������������������������������������������

254

12.2.3 정적 타이핑 �������������������������������������������������������������������������������������������������������

256

12.2.4 동적 타이핑 �������������������������������������������������������������������������������������������������������

256

12.2.5 Hack은 양손잡이다 ��������������������������������������������������������������������������������������������

257

12.2.6 Hack 타입 검사 �������������������������������������������������������������������������������������������������

258

12.2.7 Hack 모드 ��������������������������������������������������������������������������������������������������������

258

12.2.8 Hack 문법 ��������������������������������������������������������������������������������������������������������

259

12.2.9 Hack 데이터 구조 ����������������������������������������������������������������������������������������������

261

12.2.10 HHVM/Hack vs. PHP ��������������������������������������������������������������������������������������

262

12.3 참고 자료 �������������������������������������������������������������������������������������������������������������������

264

CHAPTER

13 커뮤니티

13.1 지역 PUG ������������������������������������������������������������������������������������������������������������������ 265

13.2 컨퍼런스 �������������������������������������������������������������������������������������������������������������������� 266

13.3 멘토링 ����������������������������������������������������������������������������������������������������������������������� 266

13.4 최신 정보 ������������������������������������������������������������������������������������������������������������������� 266

13.4.1 웹 사이트 ����������������������������������������������������������������������������������������������������������

266

13.4.2 메일링 리스트 ����������������������������������������������������������������������������������������������������

267

13.4.3 트위터 ��������������������������������������������������������������������������������������������������������������

267

13.4.4 팟캐스트 �����������������������������������������������������������������������������������������������������������

267

13.4.5 유머 �����������������������������������������������������������������������������������������������������������������

267

26


APPENDIX

A PHP 설치

A.1 리눅스 ����������������������������������������������������������������������������������������������������������������������� 269

A.1.1 패키지 관리자 ���������������������������������������������������������������������������������������������������� 269

A.1.2 우분투 14.04 LTS ��������������������������������������������������������������������������������������������� 270

A.1.3 CentOS 7 ������������������������������������������������������������������������������������������������������� 272

A.2 OS X ������������������������������������������������������������������������������������������������������������������������ 274

A.2.1 MAMP ������������������������������������������������������������������������������������������������������������ 274

A.2.2 홈브루 �������������������������������������������������������������������������������������������������������������� 278

A.3 소스코드로 설치 ���������������������������������������������������������������������������������������������������������� 282

A.3.1 소스코드 얻기 ���������������������������������������������������������������������������������������������������� 284

A.4 윈도우 ����������������������������������������������������������������������������������������������������������������������� 290

A.4.1 바이너리 ����������������������������������������������������������������������������������������������������������� 290

A.4.2 WAMP ������������������������������������������������������������������������������������������������������������ 290

A.4.3 젠드 서버 ���������������������������������������������������������������������������������������������������������� 291

APPENDIX

B 로컬 개발 환경

B.1 버추얼 박스 ���������������������������������������������������������������������������������������������������������������� 294 B.2 베이그런트 ����������������������������������������������������������������������������������������������������������������� 295

B.2.1 명령어 �������������������������������������������������������������������������������������������������������������� 295

B.2.2 박스 ����������������������������������������������������������������������������������������������������������������� 296

B.2.3 초기화 �������������������������������������������������������������������������������������������������������������� 296

B.2.4 프로비전 ����������������������������������������������������������������������������������������������������������� 297

B.2.5 동기화된 폴더 ���������������������������������������������������������������������������������������������������� 298

B.2.6 시작하기 ����������������������������������������������������������������������������������������������������������� 299

찾아보기 �������������������������������������������������������������������������������������������������������������������� 303

27



CHAPTER

1

새로운 PHP

PHP 언어는 르네상스를 맞이했다. PHP는 네임스페이스, 트레이트, 클로저, 내장 오피코드 opcode

캐시 같이 유용한 기능을 탑재한 최신 스크립트 언어로 탈바꿈 중이다. PHP 생태계 또한

진화하고 있다. PHP 개발자들은 이제 단일 프레임워크보다는 작고 특화된 컴포넌트에 더 의 지한다. 의존성 관리도구인 컴포저Composer는 PHP 애플리케이션 구축 방법에 혁신을 일으켰다. 프레임워크의 울타리 안에서 벗어나 상호운용이 가능한 컴포넌트들을 각각의 PHP 애플리케 이션에 알맞게 짜맞출 수 있게 되었다. 컴포넌트 간의 이러한 상호운용은 PHP 프레임워크 인 터롭 그룹PHP Framework Interop Group (PHP-FIG )이 주도하고 제안한 커뮤니티 표준이 없었다면 불 가능했을 것이다. 『Modern PHP』는 새로운 PHP에 대한 안내서다. 커뮤니티 표준과 모범 사례, 상호운용이 가 능한 컴포넌트들을 사용하여 멋진 PHP 애플리케이션을 구축하고 이를 배포하는 방법을 알려 줄 것이다.

1.1 과거 최신 PHP를 탐험하기에 앞서 PHP의 기원을 아는 게 중요하다. PHP는 인터프리터 방식의 서 버 측 스크립트 언어다. PHP 코드를 작성해서 웹 서버에 올리면 인터프리터에 의해 실행된다 는 뜻이다. PHP는 보통 아파치 혹은 엔진엑스Nginx와 함께 동적인 콘텐츠를 제공하는 데 쓰인

1장 새로운 PHP

29


다. 그러나 PHP는 (Bash, 루비, 파이썬 등과 마찬가지로) 강력한 명령행 애플리케이션을 만 드는 데에도 쓰일 수 있다. 많은 PHP 개발자가 이 사실을 모른 채 진짜 흥미로운 부분을 놓치 고 있지만 이 책을 읽고 있는 여러분은 그렇지 않다. 공식적인 PHP 역사는 래즈머스 러더프Rasmus Lerdorf (PHP의 창시자)가 http://php.net/manual/

history.php.php에 이미 잘 정리해 놓았으니 여기에서 다시 이야기할 필요는 없다. 내가 말하 려는 바는 PHP의 역사에 격동기가 있었다는 사실이다. PHP는 래즈머스 러더프가 온라인 이 력서 방문 기록을 추적하기 위해 작성한 CGI 스크립트 모음에서 시작됐다. 러더프는 자신의

CGI 스크립트 모음을 ‘Personal Home Page Tools’라고 불렀다. 이때의 초기 형태는 오늘 날 우리가 아는 PHP와는 완전히 달랐다. 러더프의 초기 PHP Tools는 스크립트 언어가 아니 라 HTML 내장 문법을 이용해 기본적인 변수들과 자동화된 폼 변수들을 제공하는 도구였다.

1994년에서 1998년 사이에 PHP는 수많은 개정을 거치며 개선됐고 심지어 몇 번은 완전히 새 로 만들어지기도 했다. 이스라엘 서부 지중해 연안에 있는 도시 텔아비브의 앤디 거트먼스와 지브 수라스키가 래즈머스 러더프와 합류했으며 이들의 손에 의해 PHP는 소형 CGI 도구모음 을 넘어 일관된 문법과 기본적인 객체지향 프로그래밍 기능을 갖춘 어엿한 프로그래밍 언어로 탈바꿈했다. 1998년 말 이들은 자신들의 최종 결과물을 PHP 3라 명명하고 릴리스`했다. PHP 라는 단어의 의미는 이전과 완전히 다른 PHP: Hypertext Preprocessor의 재귀적인 약자로 변모했다. PHP 3는 오늘날 우리가 알고 있는 PHP와 가장 닮은 첫 번째 버전이며 다양한 데이 터베이스, 프로토콜, API에 대해 뛰어난 확장성을 제공했다. 이러한 확장성은 많은 신규 개발 자가 PHP 3를 프로젝트에 도입하게 되는 기폭제 역할을 했다. PHP 3는 경이롭게도 1998년 말에 이미 전 세계 웹 서버의 10%에 설치되기에 이른다.

1.2 현재 오늘날 PHP 언어는 빠르게 진화하며 세계 각지에 있는 여러 핵심 개발팀의 지원을 받고 있다. 개발 관행 역시 변했다. 과거에는 PHP 파일을 작성하고 프로덕션 서버에 FTP로 업로드한 뒤 작동하길 바라는 것이 관행이었다. 형편없는 개발 전략이지만, 적절한 로컬 개발 환경이 없었 기 때문에 어쩔 수 없었다.

30

1부 언어 기능


요즘은 FTP를 지양하고 버전 관리를 사용한다. 깃Git과 같은 버전 관리 프로그램을 이용해 코 드의 이력을 유지하고, 브랜치나 포크를 생성하고, 코드를 병합한다. 베이그런트 같은 가상화 도구와 앤시블, 셰프, 퍼핏 같은 구성 도구들을 사용해 로컬 개발 환경을 프로덕션 서버와 일치 시킨다. 의존성 관리도구인 컴포저로는 특화된 PHP 컴포넌트들을 다룬다. 코드를 작성할 때 는 PHP 프레임워크 인터롭 그룹이 관리하는 커뮤니티 표준인 PSR을 충실히 따른다. PHP유 닛 같은 도구로 코드를 철저하게 테스트한다. 애플리케이션은 엔진엑스 같은 웹 서버 후방에 배포하고 PHP FastCGI 프로세스 관리자로 실행한다. 그리고 오피코드 캐시를 통해 애플리케 이션 성능을 향상시킨다. 『Modern PHP』는 PHP를 처음 접하거나 이전 버전을 경험한 이들에게는 낯설 수도 있는 새 롭고 많은 관행을 포괄한다. 그렇다고 주눅들 필요는 없다. 이 책에서 각각의 개념을 차근차근 알아볼 것이기 때문이다. 이제 PHP에는 2014년까지는 없었던 공식 규약 초안이 생겼다. 성숙한 프로그래밍 언어들에는 대부분 규약이 있다. 쉽게 말해 규약이란 PHP가 무엇인지를 정의 하는 원본 청사진이다. PHP 코드를 분석하고, 해석하고, 실행하는 프로그램을 만드는 개발자들이 사용한다.

PHP로 애플리케이션이나 웹 사이트를 만드는 개발자들을 위한 것이 아니다.

새라 골먼과 페이스북은 2014년 오라일리에서 주최한 오스콘 컨퍼런스에서 첫 PHP 규약 초 안을 발표했다. 공식 발표문은 PHP 내부 메일링 리스트(http://bit.ly/php-internals )나 PHP 규약 깃허브(http://bit.ly/php-langspec )에서 볼 수 있다. 공식 언어 규약은 경쟁 엔진이 등장하면서 그 중요성이 더욱 부각된다. 기존 PHP 엔진은 PHP

4에서 도입된 젠드Zend 엔진(http://www.zend.com/en/company/community/php/)이다. 젠드 엔진은 C로 작성된 PHP 인터프리터로 래즈머스 러더프, 앤디 거트먼스, 지브 수라스키가 만 들었다. 오늘날 젠드사는 젠드 엔진을 통해 PHP 커뮤니티에 크게 기여하고 있지만, 이제 페이 스북의 힙합 가상머신(HHVM )이 PHP의 주요한 두 번째 엔진으로 부상하고 있다. 언어 규약 은 이 두 엔진이 기준 호환성을 유지할 수 있도록 보장해준다. PHP 엔진은 PHP 코드를 분석, 해석하고 실행하는 프로그램이다(예: 젠드 엔진이나 페이스북의 HHVM). PHP 언어 자체와 혼동하지 않도록 한다.

1장 새로운 PHP

31


1.3 미래 젠드 엔진은 빠른 속도로 새로운 기능을 개선하고 성능을 향상하고 있다. 나는 젠드 엔진의 향 상이 새로운 경쟁자, 특히 페이스북의 HHVM과 Hack핵 언어 덕분이라고 본다.

Hack은 PHP를 기반으로 구축된 새로운 프로그래밍 언어다. 동적 타입이 선언된 기존 PHP 코드와 하위 호환을 유지하는 동시에 정적 타입 선언, 새로운 데이터 구조, 추가적인 인터페이 스를 제공한다. PHP의 빠른 개발 특성을 인정하지만 정적 타입 선언이 주는 예측 가능성과 안 정성이 필요한 개발자들이 Hack의 주타깃층이다. 동적 타입 선언과 정적 타입 선언에 대해서는 나중에 논의할 것이다. 둘 사이의 차이점은 PHP가 타 입을 검사하는 시점이다. 동적 타입은 런타임 시에 검사하는 반면, 정적 타입은 컴파일 시에 검사한다. 더 많 은 정보는 12장을 보기 바란다.

HHVM은 저스트 인 타임( JIT ) 컴파일러를 사용해 애플리케이션의 성능을 향상시키고 메모 리 사용을 줄이는 PHP와 Hack의 인터프리터다. 나는 Hack과 HHVM이 젠드 엔진을 대체하게 될 거라고 예상하진 않는다. 하지만 페이스북의 새로운 기여는 PHP 커뮤니티에 큰 파장을 불러 일으켰다. 젠드 엔진 핵심팀이 PHP 7 (http://

bit.ly/php7-timeline )을 발표하면서 HHVM과 동등한 수준으로 젠드 엔진을 최적화시켰다고 언급한 배경에는 상대 엔진에 대한 경쟁의식이 잘 나타나 있다. 이러한 상황 변화에 대해서는

12장에서 좀 더 논의해볼 것이다. PHP 프로그래머에게 있어 더할 나위 없이 흥미진진한 시기다. PHP 커뮤니티가 이토록 열정 적이고, 재미있고, 혁신적이었던 적은 없었다. 이 책을 통해 최신 PHP의 사례들을 확고히 받 아들이길 바란다. 새롭게 배워야 할 것이 엄청나게 많으며 앞으로도 계속해서 생길 것이다. 이 것이 여러분의 로드맵이다. 자, 이제 시작해보자!

32

1부 언어 기능


CHAPTER

2

기능

모던 PHP 언어에는 새롭고 흥미진진한 기능이 많다. 새로운 기능은 이전 버전을 사용하던

PHP 프로그래머에게는 신선함을 선사하고, 다른 언어를 사용하다 새로이 PHP를 접한 프로그 래머에게는 놀라움을 선사할 것이다. 이러한 신기능 덕분에 PHP는 더 강력한 플랫폼이 되었 으며, 웹 애플리케이션과 명령행 도구를 개발하는 데 쾌적한 환경을 제공하게 되었다. 필수적이진 않지만 그래도 편리한 기능이 있는 반면, 꼭 필요한 기능도 있다. 예컨대 네임스페 이스는 모던 PHP 표준의 초석이며, 모던 PHP 개발자라면 당연시하는 개발 관행들(예: 오토 로딩)을 가능하게 해준다. 이제부터 신기능이 어떤 면에서 유용한지와 여러분의 프로젝트에 신기능을 어떻게 구현하는지 보여줄 것이다. TIP

앞으로 나올 예제들을 자신의 컴퓨터에서 따라해보기 바란다. 모든 예제 코드는 이 책의 깃허브 저장소 (https://github.com/cloud-shadow/hanbit-modern-php)에서 찾을 수 있다.

2.1 네임스페이스 모던 PHP 기능 중 꼭 하나만 알아야 한다면 그것은 네임스페이스일 것이다. PHP 5.3.0에서 도입된 네임스페이스는 PHP 코드를 운영체제의 파일시스템 디렉터리 구조처럼 가상 계층 구 조로 구성하는 중요한 도구다. 모던 PHP 컴포넌트와 프레임워크는 전역적으로 고유한 벤더

2장 기능

33


네임스페이스1 하위에 각각의 코드를 구성한다. 따라서 다른 벤더에서 같은 이름의 클래스를 사용해도 서로 충돌하거나 소유권 문제가 발생하지 않는다. 커피숍에 들어갔는데 기분 나쁜 누군가가 책이며 전선이며 뭔가를 여러 탁자에 잔뜩 어질러 놓고 있다면 질색하지 않겠는가? 게다가 쓰지도 않으면서 유일한 전원 콘센트 바로 옆에 앉아있다면 말이다. 이 사 람은 지금 유용하게 쓸 수 있는 귀중한 공간을 낭비하고 있다. 비유적으로 말하자면, 네임스페이스를 쓰지 않 는 것은 이와 같다. 이런 사람이 되지 말자.

실제로 PHP 컴포넌트에서 네임스페이스를 사용하는 방법을 살펴보자. 심포니Symfony 프레임워 크의 symfony/httpfoundation (https://github.com/symfony/HttpFoundation )은 HTTP 요 청과 응답을 관리하는 PHP 컴포넌트로 유명하다. 중요한 점은, symfony/httpfoundation 컴포넌트가 Request, Response, Cookie 같은 흔한 클래스명을 사용한다는 사실이다. 이런 클 래스명을 사용하는 다른 PHP 컴포넌트도 많을 것이다. 만약 다른 PHP 코드에 동일한 이름 의 클래스가 있다면 어떻게 symfony/httpfoundation 컴포넌트를 쓸 수 있을까? symfony/ httpfoundation 컴포넌트를 안전하게 사용할 수 있는 것은 바로 Symfony라는 고유한 벤

더 네임스페이스 하위에 코드가 고립되어sandboxed 있기 때문이다. 깃허브에 있는 symfony/ httpfoundation 컴포넌트 저장소( https ://github .com /symfony /HttpFoundation )에서

Response.php 파일을 찾아보면 [그림 2-1]처럼 보인다. [그림 2-1]의 12번째 줄을 살펴보자. 다음과 같은 코드가 있다. namespace Symfony\Component\HttpFoundation;

이것이 PHP 네임스페이스 선언이며 항상 <?php 시작 태그 바로 다음 줄에 나온다. 이 특정한 네임스페이스 선언은 몇 가지를 알려준다. 첫째, Response 클래스는 Symfony 벤더 네임스페 이스 하위에 있다(벤더 네임스페이스는 최상위 네임스페이스다). Response 클래스는 서브네 임페이스인 Component 하위에 있다. 또한 Response 클래스는 뒤이어 나온 HttpFoundation 이라는 이름의 서브네임스페이스 하위에 있다. Response.php 주변의 다른 파일들 역시 같은 네임스페이스를 선언하고 있음을 볼 수 있을 것이다. 네임스페이스(혹은 서브네임스페이스) 는 연관된 PHP 클래스들을 마치 파일시스템 디렉터리가 연관된 파일들을 담고 있는 것처럼 1 역자주_ 최상위 네임스페이스다. 프로젝트를 대표하는 정체성을 나타낸다(예: 기업명, 개인 아이디 등).

34

1부 언어 기능


그림 2-1 깃허브 symfony/httpfoundation 스크린샷

구성하고 캡슐화한다. TIP

서브네임스페이스는 \ 문자로 구분한다.

PHP 네임스페이스는 운영체제의 물리적 파일시스템과는 달리 가상 개념이며 파일시스템 디 렉터리와 1:1로 대응할 필요가 없다. 그렇긴 해도 사실상 대부분의 PHP 컴포넌트가 서브네임 스페이스를 파일시스템 디렉터리에 맞춘다. 대중화된 PSR-4 오토로더autoloader 표준과의 호환 성을 위해서다(3장에서 좀 더 이야기해볼 것이다). 엄밀히 말하자면 네임스페이스는 PHP 인터프리터가 클래스, 인터페이스, 함수, 상수의 이름에 공통 접두어를 적용하기 위해 참조하는 PHP 언어 표기법일 뿐이다.

2.1.1 네임스페이스를 사용하는 이유 네임스페이스가 중요한 이유는 네임스페이스를 통해 다른 개발자들의 코드와 동시에 작동하는 고립된 코드를 만들 수 있기 때문이다. 이것은 모던 PHP 컴포넌트 생태계의 기본 개념이다.

2장 기능

35


컴포넌트와 프레임워크 제작자들은 코드를 만들어 수많은 PHP 개발자에게 배포한다. 그들에 게는 자신들의 코드와 함께 쓰는 클래스, 인터페이스, 함수, 상수를 알거나 제어할 방법이 없 다. 이 문제는 내부 프로젝트에도 마찬가지로 적용된다. 만약 프로젝트 자체 PHP 컴포넌트나 클래스들을 만든다면 그 코드는 프로젝트가 의존하는 서드파티와 동시에 작동해야만 한다. 앞서 언급했던 symfony/httpfoundation 컴포넌트의 경우처럼 다른 개발자들의 코드에 같은 이름의 클래스나 인터페이스, 함수, 상수가 있을 수도 있다. 이 경우 네임스페이스가 없다면 이 름 충돌로 인해 PHP에 문제가 생긴다. 네임스페이스를 이용하면 고유한 벤더 네임스페이스 하위에 코드가 존재한다고 간주하기 때문에 다른 개발자들의 코드에 같은 이름의 클래스, 인터 페이스, 함수, 상수가 있더라도 충돌 없이 사용할 수 있다. 약간의 의존성만 있는 작은 개인 프로젝트라면 이름 충돌은 별 문제가 되지 않는다. 하지만 수 많은 서드파티에 의존하는 대규모 팀 프로젝트를 수행한다면 이름 충돌은 매우 실질적인 근심 거리가 될 수 있다. 서드파티가 전역 네임스페이스에 불러들이는 클래스, 인터페이스, 함수, 상 수는 제어할 수 없기 때문이다. 이것이 네임스페이스를 사용하는 중요한 이유다.

2.1.2 선언 모든 PHP 클래스, 인터페이스, 함수, 상수는 네임스페이스 (혹은 서브네임스페이스) 하위에 존재한다. 네임스페이스는 PHP 파일 제일 위에 있는 <?php 시작 태그 바로 다음 줄에 선언한 다. 네임스페이스 선언은 namespace로 시작하고 공백문자에 이어 네임스페이스명을 쓰고 세 미콜론 문자(; )로 끝낸다. 네임스페이스는 보통 최상위 벤더명으로 시작한다는 것을 기억해두자. 다음 예시의 네임스페 이스 선언은 Hanbit이라는 벤더명을 나타낸다. <?php

namespace Hanbit;

이 네임스페이스 아래에 선언된 모든 PHP 클래스, 인터페이스, 함수, 상수는 Hanbit 네임스 페이스 안에 존재하며, 어떤 식으로든 한빛미디어와 관련되어 있다. 그럼 이 책과 관련된 코드 를 구성하려면 어떻게 해야 할까? 서브네임스페이스를 사용하면 된다.

36

1부 언어 기능


서브네임스페이스는 앞의 예시와 같은 방법으로 선언한다. 유일한 차이는 네임스페이스와 서 브네임스페이스 사이를 \ 문자로 구분한 것이다. 이어지는 예시는 최상위 벤더 네임스페이스 Hanbit의 하위에 존재하는 ModernPHP 서브네임스페이스를 선언한다. <?php

namespace Hanbit\ModernPHP;

이 네임스페이스 선언 아래에 있는 모든 클래스, 인터페이스, 함수, 상수는 Hanbit\Modern PHP 네임스페이스 안에 존재하며, 어떤 식으로든 이 책과 관련되어 있다.

동일한 네임스페이스나 서브네임스페이스에 있는 모든 클래스를 하나의 PHP 파일에 선언할 필요는 없다. 네임스페이스나 서브네임스페이스를 PHP 파일의 맨 처음에 정해주면 그 파일의 코드는 해당 네임스페이스나 서브네임스페이스의 일부분이 된다. 동일한 네임스페이스에 속하 는 클래스들을 이런 식으로 여러 파일에 나눠서 작성할 수 있다. TIP

가장 중요한 네임스페이스는 벤더 네임스페이스다. 벤더 네임스페이스는 브랜드나 조직을 식별하기 위한 최상 위 네임스페이스며 전역적으로 유일해야만 한다. 서브네임스페이스는 그보다 덜 중요한 반면 프로젝트 코드 를 구성하는 데 도움이 된다.

2.1.3 임포트와 별칭 네임스페이스가 생기기 전까지, PHP 개발자들은 젠드-스타일 클래스명으로 이름 충돌 문제 를 해결했다. 이것은 젠드 프레임워크에 의해 대중화된 클래스 명명 규칙이며 파일시스템 디렉 터리의 구분자를 밑줄로 대체해 PHP 클래스명으로 사용한다. 이 방식을 사용하면 두 가지 효 과를 얻는다. 클래스명의 유일성을 보장할 수 있으며, PHP 클래스명의 밑줄을 파일시스템 디 렉터리 구분자로 치환해 클래스 파일의 경로를 결정하는 단순한 방법으로 오토로딩을 구현할 수 있다. 예를 들어 Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query라는 PHP 클래스 는 Zend/Cloud/DocumentService/Adapter/WindowsAzure/Query.php라는 PHP 파 일에 대응한다. 젠드-스타일 명명 규칙의 부작용은 보다시피 터무니없이 긴 클래스명이다. 날 더러 게으르다 해도, 나로서는 이 클래스명을 한 번 이상 타이핑할 재간이 없다. 모던 PHP 네

2장 기능

37


임스페이스도 비슷한 문제를 보여준다. 예를 들어 symfony\httpfoundation 컴포넌트에 있 는 Response 클래스의 전체 클래스명은 \Symfony\Component\HttpFoundation\Response 다. 다행히 PHP에서는 네임스페이스를 임포트하거나 별칭으로 부를 수 있다. 임포트를 통해 각 PHP 파일에서 어떤 네임스페이스, 클래스, 인터페이스, 함수, 상수를 사용 할 것인지 PHP에 알려준다. 그러면 네임스페이스 전체를 타이핑하지 않고도 이들을 사용할 수 있다. 그리고 별칭을 통해 임포트한 클래스, 인터페이스, 함수, 상수를 축약한 이름으로 참조할 것임 을 PHP에 알려준다. TIP

PHP 5.3부터 클래스와 인터페이스, 네임스페이스를 임포트하거나 별칭을 지정할 수 있다. PHP 5.6부터는 함수와 상수도 임포트하거나 별칭을 지정할 수 있다.

[예제 2-1]은 400 Bad Reqeust HTTP 응답을 생성해 전송하는 코드다. 임포트와 별칭을 사 용하지 않는다. 예제 2-1 별칭이 없는 네임스페이스 <?php $response = new \Symfony\Component\HttpFoundation\Response('앗', 400); $response->send();

이렇게만 보자면 심각해 보이지 않겠지만, 한 파일 안에서 Response 클래스의 인스턴스를 여 러 번 생성해야 한다고 상상해보자. 손가락이 아프기 시작할 것이다. 이제 [예제 2-2]를 보자. 임포트로 같은 작업을 한다. 예제 2-2 기본 별칭을 사용한 네임스페이스 <?php

use Symfony\Component\HttpFoundation\Response; $response = new Response('앗', 400); $response->send();

Symfony\Component\HttpFoundation\Response 클래스를 사용하겠다는 의사를 use 키워드

38

1부 언어 기능


CHAPTER

3

표준

PHP 컴포넌트와 프레임워크는 어마어마하게 많다. 심포니( http://symfony.com )나 라라벨 (http://laravel.com ) 같은 대형 프레임워크가 있는가 하면 사일렉스(http://silex.sensiolabs.

org )나 슬림( http://slimframework.com ) 같은 초소형 프레임워크도 있다. 코드이그나이터 (http://www.codeigniter.com )처럼 PHP 컴포넌트가 존재하기 이전에 만들어진 구형 프레임 워크도 있다. 모던 PHP 생태계는 개발자로 하여금 놀라운 애플리케이션을 만들 수 있게 해주 는 진정한 코드 용광로다. 불행하게도 오래 전에 개발된 PHP 프레임워크들은 고립되어 있으며 다른 PHP 프레임워크와 코드를 공유하지 않는다. 이런 구형 PHP 프레임워크를 프로젝트에 사용하면 프레임워크의 생 태계 안에 꼼짝 못하고 갇히게 된다. 프레임워크의 기능이 만족스럽다면 이런 중앙집중적인 환 경도 나쁘지 않다. 하지만 코드이그나이터 프레임워크를 프로젝트에 사용하던 중에 심포니 프 레임워크의 헬퍼 라이브러리만 선택적으로 사용하고 싶어지면 어떻게 해야 할까? 프로젝트만 의 전용 어댑터를 만드는 것 말고는 달리 방법이 없을 것이다. 이 친구는 말이 안 통하는 친구라고. – 영화 《폭력 탈옥Cool Hand Luke》 중에서

문제점을 알겠는가? 고립된 프레임워크는 다른 프레임워크와 소통하도록 설계되지 않았다. 이 는 (프레임워크로 인해 창조성이 제한된) 개발자와 (어딘가에 이미 있는 코드를 다시 구현해 야 하는) 프레임워크 모두에게 극단적으로 비효율적이다. 하지만 좋은 소식이 있다. PHP 커 뮤니티는 이런 중앙집중적인 프레임워크 모델을 효율적이고, 상호운용 가능하며, 특화된 컴포 넌트 생태계로 진화시켜왔다.

3장 표준

39


3.1 PHP-FIG 구조대 이러한 문제점을 인식한 몇몇 PHP 프레임워크 개발자들이 2009년 php|tek ( http://tek.

phparch.com ) (유명한 PHP 컨퍼런스)에서 만나 대화하기 시작했다. 이들은 프레임워크의 소통과 효율을 향상할 방법을 논의했다. 프레임워크와 강하게 결합된 로깅 클래스를 새로 만드 는 대신 monolog (https://github.com/Seldaek/monolog ) 같은 분리된 로깅 클래스를 서로 공 유할 수 있다면? HTTP 요청과 응답을 처리할 자신만의 클래스를 만드는 대신, 심포니 프레임 워크에 포함된 symfony/httpfoundation (http://bit.ly/symf-docs ) 컴포넌트에서 HTTP 관련 클래스만 가져와 사용할 수 있다면? 이런 일들을 가능하게 하려면 PHP 프레임워크들이 소통 과 공유에 사용할 공통의 언어가 있어야 한다. 다시 말해 표준이 필요하다.

php|tek에서 우연히 만난 PHP 프레임워크 개발자들은 마침내 PHP 프레임워크 인터롭 그 룹(PHP-FIG ) (http://www.php-fig.org )을 결성했다. PHP-FIG 웹 사이트에 따르면 PHP-

FIG는 “프로젝트들이 가진 공통성에 관해 이야기하고 함께 만들어나갈 수 있는 방법을 모색하 는 PHP 프레임워크 대표자들의 모임”이다. PHP-FIG는 PHP 프레임워크 사이의 소통과 공 유를 향상하기 위해 프레임워크 스스로 구현할 수 있는 권장안을 창안했다.

PHP-FIG는 프레임워크 대표자들이 자발적으로 결성한 단체다. 구성원을 뽑는 특별한 방법 은 없다. PHP 커뮤니티 발전에 기꺼이 기여하고자 한다면 누구나 가입을 신청할 수 있고 제안 단계의 권장안에 피드백을 보낼 수도 있다. 통상적으로 PHP-FIG는 가장 규모가 크고 인기 있는 PHP 프레임워크들에 채택되어 구현된다. 여러분도 PHP-FIG에 피드백을 보내 선호하 는 PHP 프레임워크의 미래에 일조할 수 있기를 바란다. PHP-FIG가 제공하는 권장안은 규칙도 요구사항도 아니라는 점을 이해해야 한다. 이 권장안은 신 중히 다듬어진 제안이며 이를 통해 PHP 개발자(그리고 프레임워크 제작자)들의 삶이 한결 편해진다.

3.2 프레임워크 상호운용성 PHP-FIG의 목표는 프레임워크 상호운용성이다. 프레임워크 상호운용성이란 프레임워크들 이 인터페이스, 오토로딩, 스타일을 통해 함께 작동함을 의미한다.

40

2부 모범 사례


3.2.1 인터페이스 PHP 프레임워크는 공유 인터페이스를 통해 함께 작동한다. 인터페이스를 사용하면 프레임워 크가 의존하는 서드파티의 메서드가 어떻게 인터페이스를 구현했는지 걱정하지 않아도 된다. PHP 인터페이스에 대한 상세한 설명은 2장을 참고하도록 한다.

예를 들어 프레임워크는 emergency ( ), alert ( ), critical ( ), error ( ), warning ( ), notice ( ), info ( ), debug ( ) 메서드를 구현한 서드파티 로거 객체를 마음껏 공유할 수 있다.

로거 객체가 이 메서드들을 정확히 어떻게 구현했는지는 상관하지 않는다. 각 프레임워크는 서 드파티가 이 메서드들을 구현했다는 사실 자체에만 관심이 있다.

PHP 개발자들은 인터페이스를 통해 단일 프레임워크 대신 특화된 컴포넌트들을 만들어 공유 하고 사용할 수 있다.

3.2.2 오토로딩 PHP 프레임워크는 오토로딩을 통해 함께 작동한다. 오토로딩은 PHP 인터프리터가 런타임 시 PHP 클래스를 그때그때 자동으로 불러오는 과정이다. PHP 표준이 있기 전, PHP 컴포넌트와 프레임워크들은 특수 메서드인 \__autoload ( ) 혹은 더 최근에 나온 spl_autoload_register ( )를 이용해 각자 고유한 오토로더를 구현했다. 이 때문에 사용자들은 각 컴포넌트와 프레임워크의 오토로더 사용법을 모두 익혀야 했다. 요즘에 는 모던 PHP 컴포넌트와 프레임워크 대부분이 공통 오토로더 표준을 준수한다. 이는 단 하나 의 오토로더로 다수의 PHP 컴포넌트를 필요에 따라 조합할 수 있음을 의미한다.

3.2.3 코드 스타일 PHP 프레임워크는 코드 스타일을 통해 함께 작동한다. 코드 스타일은 (여러 가지 중에서도) 공백, 대소문자, 괄호 위치를 결정한다. PHP 프레임워크들이 표준 코드 스타일 사용에 합의하 면 PHP 개발자들은 새로운 PHP 프레임워크를 사용할 때마다 매번 새로운 스타일을 익힐 필 요가 없어지고, 그 대신 PHP 프레임워크들의 코드는 단숨에 비슷해진다. 또한 표준 코드 스타

3장 표준

41


일은 신규 프로젝트 기여자들의 진입장벽을 낮춰준다. 이들은 낯선 스타일을 익히는 데 들이는 시간을 줄이는 대신 버그를 없애는 데 더 많은 시간을 쓸 수 있다. 표준 코드 스타일을 사용하면 여러분의 프로젝트도 향상된다. 모든 개발자에게는 자신만의 스 타일이 있으며 그중에는 별스러운 습관도 적지 않다. 이런 습관은 많은 개발자가 같은 코드베 이스를 다룰 때 문제가 된다. 표준 코드 스타일을 사용하면 제작자가 누구든 모든 팀 구성원이 같은 코드베이스를 바로 이해할 수 있다.

3.3 PSR PSR은 PHP Standard RecommendationPHP 표준 권장안의 약자다. 최근 PHP 관련 블로그를 읽 었다면 PSR-1, PSR-2, PSR-3 등의 용어를 보았을 것이다. 이 용어들은 PHP-FIG 권장안 을 가리킨다. 권장안의 이름은 PSR-로 시작하고 번호로 끝난다. 각 PHP-FIG 권장안은 PHP 프레임워크 대부분이 빈번하게 맞닥뜨리는 특정 문제를 해결해준다. PHP 프레임워크들은 같 은 문제를 반복적으로 해결하는 대신 PHP-FIG의 권장안을 채택하고 공유된 해결 방법을 사 용할 수 있다.

PHP-FIG는 이 책의 출간 시점까지 다섯 가지 권장안을 공표했다. PSR -1 : 기본 코드 스타일(http ://www.php -fig.org/psr/psr -1/)

PSR -2 : 엄격한 코드 스타일(http ://www.php -fig.org/psr/psr -2/)

PSR -3 : 로거 인터페이스(http ://www.php -fig.org/psr/psr -3/)

PSR -4 : 오토로딩(http ://www.php -fig.org/psr/psr -4/)

네 개밖에 없는 것이 정상이다. PHP-FIG는 첫 번째 권장안이었던 PSR-0(http://www.php-fig.

org/psr/psr-0/)를 폐기했다. 이 권장안은 PSR-4(http://www.php-fig.org/psr/psr-4/) 권장안으로 새롭 게 대체됐다.

권장안의 주제들이 앞서 살펴본 세 가지 상호운용 방법(인터페이스, 오토로딩, 코드 스타일) 과 근사하게 맞아떨어진다는 점에 주목하자. 이것은 우연의 일치가 아니다.

42

2부 모범 사례


나는 PHP-FIG 권장안에 정말로 흥분했다. 이 권장안들은 모던 PHP 생태계를 떠받치는 기반 이며 PHP 컴포넌트와 프레임워크들이 상호운용할 수단을 정의한다. PHP 표준은 분명 가장 참신한 사안은 아니지만, (내 생각에는) 모던 PHP를 이해하기 위한 필수 전제조건이다.

3.4 PSR-1: 기본 코드 스타일 커뮤니티 표준과 호환하는 PHP 코드를 작성하고자 한다면 PSR-1으로 시작하자. 가장 사용하 기 쉬운 PHP 표준이다. 너무 쉬운 나머지 아마 시도하지도 않았는데 이미 사용하고 있을지도 모른다. PSR-1은 최소한의 노력으로도 쉽게 준수할 수 있는 단순한 지침을 제공한다. PSR-1 의 목표는 PSR에 동참하는 PHP 프레임워크에 기준 코드 스타일을 제공하는 것이다. PSR-1 과 호환되게 하려면 다음 요구사항들을 준수해야 한다. PHP 태그

PHP 코드를 감쌀 때는 <?php ?>나 <?= ?>만 사용해야 한다. 다른 어떤 PHP 태그도 사용해서는 안 된다. 인코딩

모든 PHP 파일은 반드시 바이트 순서 표식Byte Order Mark (BOM )이 없는 UTF -8 문자셋으로 인코딩되어 있 어야 한다. 복잡해 보이지만 문서 편집기나 IDE를 이용하면 자동으로 할 수 있다. 목적

하나의 PHP 파일은 심볼(클래스, 트레이트, 함수, 상수 등)을 정의하거나 부차적인 효과(예: 결과를 출력하 거나 데이터를 조작하는)가 발생하는 기능을 수행한다. 둘 중 한 가지 역할만 해야 한다. 간단한 요건이며 약간 의 예측과 계획만 있으면 준수할 수 있다. 오토로딩

PHP 네임스페이스와 클래스들은 PSR -4 오토로더 표준을 지원해야 한다. 여러분이 해야 할 일은 이들의 이름을 적절하게 짓고 이들을 정의한 파일을 올바른 위치에 두는 것뿐이다. PSR -4에 대해서는 곧 이야기할 것이다. 클래스명

클래스명에는 일반적인 낙타 표기법CamelCase, 캐멀케이스을 사용해야 한다. 이 형식은 첫문자 대문자 표기법TitleCase, 라고도 불린다. 예로는 CoffeeGrinder, CoffeeBean, PourOver 등이 있다.

타이틀케이스

상수명

PHP 상수명에는 대문자만 사용해야 한다. 필요하다면 단어를 분리하기 위해 밑줄을 사용할 수 있다. 예로는

WOOT, LET_OUR_POWERS_COMBINE, GREAT_SCOTT 등이 있다. 메서드명

메서드명에는 소문자로 시작하는 낙타 표기법을 사용해야 한다. 메서드명의 첫 글자는 소문자이고 이어

3장 표준

43


지는 각 단어의 첫 글자는 대문자라는 의미다. 예로는 phpIsAwesome , iLoveBacon , tennantIs

MyFavoriteDoctor 등이 있다.

3.5 PSR-2: 엄격한 코드 스타일 PSR-1을 구현했다면 다음 단계는 PSR-2를 구현하는 것이다. PSR-2 표준은 PSR-1보다 엄 격한 PHP 코드 스타일 지침을 정의한다.

PSR-2 코드 스타일은 PHP 프레임워크에 내린 신의 선물과도 같다. PHP 프레임워크에 기여 하는 전 세계적으로 많은 개발자가 있고 저마다 선호하는 고유한 스타일이 있지만, 엄격한 공 통 코드 스타일로 작성한 코드는 작성자가 아닌 다른 기여자들도 쉽고 빠르게 이해할 수 있다.

PSR-1과는 달리 PSR-2 권장안에는 더 엄격한 지침들이 있다. PSR-2 지침 중 일부는 마음 에 들지 않을 수도 있다. 하지만 PSR-2는 다수의 대중적인 PHP 프레임워크가 선호하는 코드 스타일이다. PSR-2를 꼭 사용할 필요는 없다. 하지만 PSR-2를 사용하면 여러분의 코드를 읽 고 사용하고 개선하는 다른 개발자의 생산성이 극적으로 향상된다. 여러분은 PSR-2 코드 스타일을 사용해야 한다. 엄격하다고는 해도 어렵지 않게 작성할 수 있으며 사용하다

TIP

보면 자연스럽게 익숙해질 것이다. 기존 코드를 PSR-2 스타일에 맞게 자동으로 정리해주는 도구들도 있다. PSR -1 구현

PSR -1 코드 스타일 구현은 PSR -2 코드 스타일 구현의 선행 조건이다. 들여쓰기

통상적으로 두 진영으로 갈리는 뜨거운 주제다. 첫 번째 진영은 단일 탭 문자로 들여쓰는 것을 선호한다. 두 번 째 (좀 더 쿨한) 진영은 공백문자열을 이용하는 것을 선호한다. PSR -2 권장안에 따르면 PHP 코드의 들여 쓰기에는 공백문자열 네 개를 사용해야 한다. 개인적인 경험으로는 공백문자열이 들여쓰기에 더 적당하다. 왜냐하면 공백은 여러 코드 편집기들이 동일하게

TIP

표시할 수 있는 확정적인 단위다. 그러나 탭은 코드 편집기마다 너비와 화면 표시가 제각기 다를 수 있다. 코드 의 시각적인 연속성을 최대한 보장하려면 공백문자열 네 개를 이용해 들여쓰도록 하자. 파일과 줄

PHP 파일은 유닉스 개행문자LineFeed (LF )를 사용해야 하고 비어 있는 한 줄로 끝나야 하며 마지막에 ?> 태그 가 없어야 한다. 코드의 각 줄은 80글자를 넘기지 않도록 하며 최대 120글자를 넘기면 안 된다. 각 줄의 끝에 는 공백문자가 오면 안 된다. 손이 많이 갈 것 같지만 전혀 그렇지 않다. 대부분의 코드 편집기는 자동으로 특

44

2부 모범 사례


CHAPTER

4

컴포넌트

모던 PHP는 단일 프레임워크와 관련이 적고, 상호운용할 수 있는 전문 컴포넌트로 구성한 솔 루션에 더 관련되어 있다. 나 역시 PHP 애플리케이션을 새로 만들 때 무작정 라라벨이나 심포 니로 시작하는 경우는 드물다. 그보다는 기존 PHP 컴포넌트 중 어떤 것들을 조합하면 문제를 해결할 수 있을지를 먼저 생각해본다.

4.1 컴포넌트를 사용하는 이유 모던 PHP 컴포넌트는 많은 PHP 프로그래머에게 새로운 개념이다. 나도 몇 년 전까지는 PHP 컴포넌트를 알지 못했다. 그전까지는 애플리케이션을 만들 때 다른 방법을 고려하지 않은 채 무의식적으로 심포니나 코드이그나이터 같은 거대 프레임워크를 사용했다. 단일 프레임워크의 폐쇄된 생태계에 갇힌 채 프레임워크가 제공해주는 도구를 사용했다. 만약 필요한 기능이 프레 임워크에 없으면 어쩔 수 없이 직접 만들어 추가해야 했다. 맞춤 기능이나 서드파티 라이브러 리를 프레임워크에 통합하는 것도 쉽지 않았다. 이들이 공통 인터페이스를 공유하지 않았기 때 문이다. 다행스럽게도 이제는 더이상 단일 프레임워크와 그 폐쇄적인 환경에 의지할 필요가 없 는 시대가 되었다. 오늘날에는 지속적으로 증가하는 방대한 전문 컴포넌트 중에서 필요한 것만 골라 애플리케 이션 제작에 사용한다. guzzle/http ( https://packagist.org/packages/guzzle/http ) 컴포넌

4장 컴포넌트

45


트가 이미 있는데 HTTP 요청, 응답 라이브러리를 코딩하느라 왜 시간을 낭비하는가? aura/ router ( https://packagist.org/packages/aura/router )와 orno/route ( https://packagist.

org /packages /orno /route )라는 훌륭한 컴포넌트가 있는데 왜 새로운 라우터를 만드는 가? aws/aws-sdk-php ( https ://packagist .org /packages /aws /aws -sdk -php )와 league/ flysystem ( https://packagist.org/packages/league/flysystem ) 컴포넌트를 쓸 수 있는데 뭐

하러 시간을 들여 아마존 S3 온라인 스토리지 서비스 어댑터를 코딩하는가? 요점을 말하자면 이렇다. 다른 개발자들이 무수히 많은 시간을 들여 만들고 다듬고 테스트한 전문 컴포넌트들이 이미 있으며, 이런 컴포넌트는 어떤 한 가지 일을 처리하는 데 매우 능숙하다. 이들을 충분히 활용하면 더 나은 애플리케이션을 신속하게 제작할 수 있고 무의미한 일에 시간을 낭비하는 우 를 범하지 않을 수 있다.

4.2 컴포넌트란 무엇인가 컴포넌트는 PHP 애플리케이션의 특정 문제를 해결하도록 도와주는 코드 모음이다. 예를 들어

PHP 애플리케이션에 HTTP 요청을 주고받는 기능이 필요하다면 그런 기능의 컴포넌트를 사 용하면 된다. 그리고 쉼표(, )로 구분된 데이터를 파싱하거나 로그 메시지를 기록하는 등의 기 능이 필요하다면 각각을 수행하는 컴포넌트 역시 존재하므로 그 컴포넌트를 사용하면 된다. 그 러므로 이미 해결된 기능을 다시 만드는 대신 PHP 컴포넌트를 사용함으로써, 프로젝트 본연 의 목적을 달성하는 일에 더 많은 시간을 할애할 수 있다. 기술적으로 말하자면 PHP 컴포넌트는 한 가지 문제를 해결하는 데 관련된 클래스, 인터페이스, 트 레이트 모음이다. 컴포넌트를 이루는 클래스, 인터페이스, 트레이트는 보통 동일한 네임스페이스 하위에 있다.

어느 상점이든 좋은 상품과 나쁜 상품이 있듯이 PHP 컴포넌트에도 같은 개념이 적용된다. 식 료품점에서 사과를 살펴볼 때처럼 PHP 컴포넌트를 볼 때도 좋은 컴포넌트를 알아보기 위한 비결이 있다. 좋은 PHP 컴포넌트의 몇 가지 특징은 다음과 같다. 목적이 정확하다

PHP 컴포넌트는 오직 한 가지 문제를 정밀하게 겨냥하고 이를 능숙하게 처리하기 위해 존재한다. 넓고 얕은 재주를 가진 사람이 아닌 한 분야의 장인인 셈이다. 한 가지 문제를 해결하는 데 온통 사로잡혀 있고, 간결한

46

2부 모범 사례


사용자 인터페이스를 통해 자신의 유능함을 나타낸다. 작다

PHP 컴포넌트는 필요 이상으로 크지 않다. 컴포넌트가 담고 있는 코드는 한 가지 문제를 해결하기 위해 필요 한 최소한의 양이다. 코드량은 경우에 따라 다른데 PHP 컴포넌트에는 PHP 클래스가 하나만 있을 수도 있고 서브네임스페이스로 구성된 PHP 클래스가 여러 개 있을 수도 있다. PHP 컴포넌트에 사용되는 클래스 개수 는 정해져 있지 않다. 그저 문제를 해결할 수 있을 만큼만 사용될 뿐이다. 협력적이다

PHP 컴포넌트들은 서로 잘 어울린다. 결국 이것이 PHP 컴포넌트 존재의 핵심 이유다(다른 컴포넌트들과 협력해 더 큰 솔루션을 구축하는 것이 핵심이다). PHP 컴포넌트는 자신의 코드로 전역 네임스페이스를 오염 시키지 않는다. 대신 자신만의 네임스페이스를 구성해 다른 컴포넌트와 이름 충돌을 피한다. 충분한 테스트를 거쳤다

PHP 컴포넌트는 충분한 테스트를 거쳤는데, 이는 작은 크기 덕분에 갖추게 된 특성이다. 작고 목적이 정확한

PHP 컴포넌트는 테스트하기 아주 쉽다. 고려할 것이 적을 뿐만 아니라 목mock 객체를 통해 의존성을 대체하 기도 쉽다. 최고의 PHP 컴포넌트는 자체적으로 테스트를 제공하며 테스트한 범위도 충분하다. 문서화 수준이 높다

PHP 컴포넌트에는 유용한 문서가 제공된다. 이 문서 덕분에 개발자가 컴포넌트를 쉽게 설치하고 이해하고 사용할 수 있다. PHP 컴포넌트에는 컴포넌트의 용도, 설치 방법, 사용 방법이 설명된 README 파일이 있으 며, 컴포넌트 웹 사이트에서 더욱 상세한 정보를 제공하기도 한다. 소스코드 역시 수준 높은 문서화에 포함된 다. 컴포넌트 클래스, 메서드, 속성에는 코드, 인수, 반환값, 발생 가능한 예외에 대해 설명하는 문서블록docblocks 이 각각 제 위치에 있어야 한다.

4.3 컴포넌트 vs. 프레임워크 (특히 오래된) 프레임워크의 문제는 투자비용이 많이 든다는 점이다. 프레임워크를 선택하는 것은 그 프레임워크의 도구에 투자하는 것과 같다. 프레임워크는 대개 다양한 도구를 뷔페식으 로 제공해준다. 하지만 가끔 프레임워크가 제공하지 않는 특수한 도구가 필요할 때 그에 알맞 는 PHP 라이브러리를 찾아내고 통합하는 일은 우리의 몫이 된다. 서드파티 코드를 프레임워 크에 통합하는 일도 쉽지 않다. 서드파티 코드와 PHP 프레임워크가 공통 인터페이스를 공유 하지 않기 때문이다. 프레임워크를 선택하는 것은 그 프레임워크의 미래에 투자하는 것과 같은데 이 투자는 프레임 워크 핵심 개발팀에 대한 신뢰를 담보로 한다. 우리는 프레임워크 개발자가 지속적으로 자신의 시간을 투자해 프레임워크를 개발하고, 코드를 최신 표준에 맞게 유지해줄 것으로 기대하지만

4장 컴포넌트

47


이런 기대는 종종 어긋난다. 프레임워크는 매우 방대하고, 유지보수에 많은 시간과 노력이 필 요하다. 프로젝트 관리자에게도 자신만의 삶과 일과 관심사가 있으며, 프레임워크에 들이는 시 간과 노력은 그에 따라 달라지기 마련이다. 공정한 관점에서 보자면 규모가 큰 PHP 컴포넌트 역시 버려지고 방치될 위험이 있다. 특히 핵심 개 발자가 한 명일 경우에는 더욱 그렇다.

또한 어떤 프레임워크가 최고의 프레임워크로 남을지는 그 누구도 알 수 없다. 다년간 지속될 큰 프로젝트는 원활한 성능과 균형잡힌 상태를 지금 뿐만 아니라 미래에도 유지해야만 한다. 프레임워크를 잘못 선택하면 이를 보장할 수 없게 되는데 유행에 뒤쳐진 오래된 프레임워크는 커뮤니티의 지원이 끊겨 속도와 사용성이 떨어질 수 있다. 오래된 프레임워크는 보통 최신 객 체지향 코드가 아닌 절차적 코드로 작성됐고, 새로 들어온 팀원은 이런 오래된 프레임워크의 코드베이스에 익숙하지 않을 수도 있다. PHP 프레임워크 사용 여부를 결정할 때에는 고려해 야 할 점이 많다.

4.3.1 모든 프레임워크가 나쁜 것은 아니다 지금까지는 프레임워크의 부정적인 면에 대해서 말했지만 프레임워크가 모두 나쁜 것만은 아 니다. 심포니(http://symfony.com/)는 모던 PHP 프레임워크의 훌륭한 본보기다. 파비앵 보탱 시에와 센시오랩이 만든 심포니 프레임워크는 작게 분리된 심포니 컴포넌트(http://symfony.

com/components )의 결합체다. 심포니 컴포넌트는 한데 모아 프레임워크로 사용할 수도 있고 맞춤 애플리케이션에 개별적으로 사용할 수도 있다. 그 밖에도 이와 유사하게 모던 PHP 컴포넌트로 전환하고 있는 구형 프레임워크가 있다. 콘 텐츠 관리 프레임워크인 드루팔(https://www.drupal.org )이 바로 그 예다. 드루팔 7은 전역

PHP 네임스페이스를 사용하며 절차적 PHP 코드로 작성됐다. 기존 코드베이스와 하위호환을 유지하기 위해 모던 PHP 관행을 무시한다. 하지만 드루팔 8은 모던 PHP를 향한 모범적이고 거대한 도약이라 할 수 있다. 드루팔 8은 여러 PHP 컴포넌트가 가진 장점들을 극대화해 최신 콘텐츠 관리 플랫폼을 제작하는 데 이용된다. 테일러 오트웰이 제작한 라라벨(http://laravel.com ) 역시 인기 있는 PHP 프레임워크다. 심포

48

2부 모범 사례


니처럼 라라벨도 일루미네이트(https://github.com/illuminate )라는 자체적인 컴포넌트 라이 브러리를 기반으로 제작됐다. 하지만 (발표 당시) 라라벨 컴포넌트는 라라벨 이외의 애플리케 이션에 사용하기에는 분리가 쉽지 않았다. 라라벨은 PSR-2 커뮤니티 표준을 사용하지 않으며 유의적 버전 형식(http://semver.org/)을 준수하지 않는다. 하지만 이런 이유로 라라벨 사용을 단념하긴 이르다. 라라벨은 매우 강력한 애플리케이션을 만들 수 있는 뛰어난 프레임워크다. TIP

가장 인기 있는 축에 속하는 모던 PHP 프레임워크 목록은 다음과 같다.

TIP

아우라Aura(http://auraphp.com/framework)

TIP

라라벨Laravel(http://laravel.com/)

TIP

심포니Symfony(http://symfony.com/)

TIP

이Yii(http://www.yiiframework.com/)

TIP

젠드Zend(http://framework.zend.com/)

4.3.2 알맞은 도구를 사용하라 컴포넌트나 프레임워크를 써야 한다면 용도에 맞는 것을 사용하도록 하자. 모던 PHP 프레임 워크 대부분은 그저 PHP 컴포넌트를 기반으로 만든 관례들을 모아 놓은 것에 지나지 않는다.

PHP 컴포넌트들을 정확하게 조합해 해결할 수 있는 소규모 프로젝트를 수행하고자 한다면 컴 포넌트를 사용하면 된다. 컴포넌트를 쓰면 기존 도구를 아주 쉽게 선택하고 사용할 수 있으며, 이로 인해 보일러플레이트 코드1에서 눈을 돌려 현재 당면한 큰 작업에 더욱 집중할 수 있게 된 다. 또한 코드를 가볍고 날렵한 상태로 유지할 수 있다. 꼭 필요한 코드 외에는 컴포넌트로 대 체하고, 프로젝트에 더 잘 맞는 다른 컴포넌트가 있다면 아주 쉽게 교체할 수 있다. 여러 팀원과 함께 큰 프로젝트를 수행하고 있으며 프레임워크가 제공하는 관례, 규율, 구조로 부터 이득을 취할 수 있다면 프레임워크를 사용하면 된다. 프레임워크는 사용자를 대신해 많은 결정을 내리는 한편 프레임워크가 지닌 일련의 관례를 준수할 것을 요구한다. 프레임워크는 유 연성이 떨어지긴 하지만 PHP 컴포넌트를 조합해서 할 수 있는 것과는 완전히 다른 수준의 일 을 할 수 있다. 이런 장단점을 받아들일 수 있다면 프로젝트 개발을 이끌고 가속시키기 위해 얼 마든지 프레임워크를 사용해도 좋다. 1 역자주_ 기능은 간단하지만 분량이 많은 코드다.

4장 컴포넌트

49


4.4 컴포넌트 선택 모던 PHP 컴포넌트는 패키지스트Packagist (https://packagist.org ) (그림 4-1 )에서 찾을 수 있 다. 패키지스트는 사실상 PHP 컴포넌트 디렉터리며 PHP 컴포넌트를 망라하고 키워드 검색 기능을 제공한다. 최고의 PHP 컴포넌트들이 패키지스트에 수록되어 있으며 이토록 귀중한 커 뮤니티 자원을 창조해낸 요르디 보기아노( http://seld.be/)와 이고르 비들러( https://igor.io/

archive.html )에게 고개 숙여 감사한다. TIP

어떤 컴포넌트가 최고의 PHP 컴포넌트라고 생각하냐는 질문을 종종 받는다. 사람마다 다르겠지만 나는 어섬

PHP(https://github.com/ziadoz/awesome-php)에 수록된 컴포넌트 목록에 대체로 동의한다. 이 목록 에는 제이미 요크(https://github.com/ziadoz)가 추천하는 좋은 컴포넌트들이 수록되어 있다.

그림 4-1 패키지스트 웹 사이트

4.4.1 쇼핑 이미 해결된 문제를 다시 해결하려고 시간을 낭비하지 말자. HTTP 메시지를 주고받아야 하는 가? 패키지스트에서 http로 검색해서 제일 먼저 나오는 거즐Guzzle을 사용하라. CSV 파일을 파

50

2부 모범 사례


CHAPTER

5

모범 사례

이번 장에는 PHP 애플리케이션을 만들 때 적용해야 할 모범 사례를 모아놓았다. 모범 사례를 따르면 더욱 빠르고 안정적이며 보안에 강한 애플리케이션을 만들 수 있다. PHP 언어에는 개 별적으로 도입된 도구들이 오랜 시간에 걸쳐 축적되었고, 이런 도구들은 모범 사례를 적용하는 데 사용된다. 시간이 가면 갈수록 점점 더 새롭고 우수한 도구들이 모던 PHP 버전에 도입될 것이다. 불행히도 PHP 언어는 여전히 과거에 도입된 구식 도구를 포함하고 있어서, 주의하지 않으면 이런 낡은 도구로 느리고 보안에 취약한 애플리케이션을 만들게 될 수 있다. 그런 애플 리케이션을 만들지 않으려면 사용할 도구와 무시할 도구를 알아두어야 하는데, 이번 장에서는 그에 대해 다뤄보겠다. 나는 현실과 동떨어진 상아탑 꼭대기에 앉아 ‘모범 사례’를 설파하지는 않을 것이다. 이번 장에 는 내가 모든 프로젝트에서 매일같이 활용하는 유용하고 실용적인 조언이 담겨 있다. 여러분은 이 지식을 여러분의 프로젝트에 바로 적용할 수 있다. 이번 장에 나오는 모범 사례들은 현재 PHP 버전에서만이 아니라 이전 버전들에서도 언제든 구현 할 수 있었다. 하지만 이런 사례를 구현하는 방법은 PHP 언어가 발전함에 따라 함께 변화한다. 모던 PHP 버 전에 도입된 도구들을 사용하면 모범 사례를 좀 더 쉽게 적용할 수 있다. 이번 장에서는 PHP 5.3+에 도입된 최신 도구들을 이용해 모범 사례를 적용하는 방법을 실습해본다.

5장 모범 사례

51


5.1 위험 제거, 유효성 검사, 예외 처리 TV 드라마 《엑스 파일The X-Files》의 남자 주인공 멀더는 “아무도 믿지 말라”는 말을 종종 하곤했 다. 프로그램 세계에서도 자신이 직접 통제하는 출처로부터 나온 데이터가 아니라면 그 어떤 데이터도 절대 믿으면 안 된다. 다음과 같은 몇몇 외부 출처들이 있다. $_GET

$_POST

$_REQUEST

$_COOKIE

$argv

php ://stdin

php ://input

file_get_contents ( )

원격 데이터베이스

원격 API

고객의 데이터

이 모든 외부 데이터 출처는 여러분의 스크립트로 악의적인 데이터를 주입할 수 있는(고의든 우연이든) 잠재적 침입 경로다. 사용자 입력을 받고 결과를 출력하는 스크립트는 쉽게 작성할 수 있다. 하지만 그러한 일을 안전하게 수행하는 스크립트를 작성하기 위해서는 고민이 약간 더 필요하다. 가장 단순하게 충고한다! 입력값의 위험을 제거하고 데이터의 유효성을 검사하고 출력을 예외 처리하라.

5.1.1 입력값 위험 제거 입력값(예: 앞선 목록에 있는 출처로부터 나온 데이터)의 위험을 제거하면 안전하지 않은 문 자가 예외 처리되거나 제거된다. 입력 데이터가 애플리케이션 저장소 계층(예: 레디스Redis나

MySQL )에 도달하기 전에 위험을 제거하는 것이 중요하다. 이것이 첫 번째 방어선이다. 예를 들어 여러분의 웹 사이트 댓글란에 HTML이 허용된다고 가정해보자. 기본적으로 방문자가 다 음과 같은 악성 <script> 태그를 댓글 내용에 포함시키는 것을 막을 방법이 없다.

52

2부 모범 사례


<p> 유용한 게시물입니다! </p> <script>window.location.href = 'http://example.com';</script>

이 댓글의 위험을 제거하지 않으면 악의적인 코드가 데이터베이스에 주입되고 웹 사이트 마크 업으로 출력될 수 있다. 웹 사이트 방문자가 이 댓글이 있는 페이지에 들어가면 유해한 웹 사이 트로 이동하게 된다. 이런 불상사는 자신의 통제 범위 밖에 있는 입력 데이터의 위험을 왜 제거 해야만 하는지 알려주는 단편적인 예시다. 내 경험상 가장 자주 접하는 입력 데이터는 HTML,

SQL 쿼리, 사용자 정보(예: 이메일 주소, 전화번호)다.

HTML HTML 특수문자(예: &, >, ″ )는 htmlentities ( ) 함수(http://php.net/manual/func tion.htmlentities.php )를 이용해서 각각에 해당하는 HTML 엔티티로 교체한다(예제 5-1 ). 이 함수는 대상 문자열에 있는 모든 HTML 문자를 예외 처리하고 애플리케이션 저장소 계층에 안전한 문자열로 변환한다. 하지만 htmlentities ( ) 함수는 우둔하다. HTML 입력을 검증하지 않으며 기본적으로 홑따옴표를 예외 처리하지 않는다. 입력 문자열의 문자 집합을 검출하지도 못한다. html entities ( ) 함수를 사용하는 올바른 방법이 [예제 5-1]에 있다. 첫 번째 인수는 입력 문자열

이다. 두 번째 인수는 ENT_QUOTES 상수며 홑따옴표를 인코딩하도록 지시한다. 세 번째 인수로 는 입력 문자열의 문자 집합을 명시한다. 예제 5-1 htmlentities( ) 함수로 입력 위험 제거하기 <?php $input = '<p><script>alert("나이지리아 복권에 당첨되셨습니다!");</script></p>';

echo htmlentities($input, ENT_QUOTES, 'UTF-8');

HTML 입력의 위험을 좀 더 능수능란하게 제거하고자 한다면 HTML 퓨리파이어( http:// htmlpurifier.org/) 라이브러리를 이용하자. HTML 퓨리파이어는 매우 탄탄하고 보안에 강한 PHP 라이브러리며 제공받은 규칙에 따라 HTML 입력의 위험을 제거해준다. 그렇지만 HTML 퓨리파이어 라이브러리는 속도가 느리고 설정이 어려울 수도 있다는 단점이 있다.

5장 모범 사례

53


preg_replace_all(), preg_replace_callback(), preg_replace() 등의 정규 표현식 함수로 HTML의 위험을 제거하지 않도록 하자. 정규표현식은 복잡하며 입력 HTML이 유효하지 않 을 수도 있기 때문에 오류가 발생할 위험이 높다.

SQL 쿼리 입력 데이터에 기반해서 쿼리를 만들어야 할 때가 있다. 어떤 경우는 HTTP 요청 쿼리 문자열 이 입력 데이터로 사용된다(예: ?user=1 ). 또 어떤 경우는 HTTP 요청 URI의 일부분이 입력 데이터로 사용된다(예: /users/1 ). 주의를 기울이지 않으면 악당들이 고의적으로 SQL 쿼리 를 망가뜨려 데이터베이스에 엄청난 피해를 입힐 수도 있다. 일례로 나는 [예제 5-2]처럼 $_ GET과 $_POST 데이터를 입력받은 그대로 이어붙여 SQL 쿼리를 만드는 초급 PHP 개발자들을

많이 보았다. 예제 5-2 나쁜 SQL 쿼리 $sql = sprintf( 'UPDATE users SET password = "%s" WHERE id = %s', $_POST['password'], $_GET['id'] );

이런 방식은 나쁘다! 만약 누군가가 다음과 같은 HTTP 요청을 PHP 스크립트로 보내면 어떻 게 될까? POST /user?id = 1 HTTP/1.1 Content-Length: 17 Content-Type: application/x-www-form-urlencoded password = abc";--

이 HTTP 요청으로 인해 모든 사용자의 비밀번호가 abc로 바뀌게 된다. 많은 SQL 데이터베이 스가 - -를 주석의 시작으로 간주하고 그 뒤에 이어지는 문자열을 무시하기 때문이다. 위험이 제거되지 않은 입력 데이터는 절대 SQL 쿼리에서 사용하면 안 된다. 만약 SQL 쿼리에 입력

54

2부 모범 사례


데이터를 합쳐야 한다면 준비된 PDO문을 사용하자. PDO는 PHP에 내장된 데이터베이스 추 상화 계층이며 복수 데이터베이스를 단일 인터페이스로 나타낸다. 준비된 PDO문은 SQL 쿼 리에 삽입될 외부 데이터의 위험을 제거하고 안전을 확보해 [예제 5-2]와 같은 문제를 방지하 는 PDO 도구다. 나는 PDO와 PDO문을 극단적으로 중요한 도구라 여기기에 이들에 대해서 는 이번 장에서 나중에 따로 다룰 것이다.

사용자 정보 애플리케이션에 사용자 계정과 관련된 기능이 있다면 이메일 주소, 전화번호, 우편번호 같은 사용자 신상 정보와 맞딱뜨릴게 될 것이다. PHP는 filter_var ( )와 filter_input ( ) 함수 로 이런 시나리오에 대비한다. 이 두 함수는 여러 입력 형식을 나타내는 다양한 플래그를 입력 받아 위험을 제거한다. 이런 형식에는 이메일, 인코딩된 URL 문자열, 정수, 실수, HTML 문자 열, URL, 아스키ASCII 문자 범위 등이 있다. [예제 5-3]은 이메일 주소에서 문자열, 숫자, !#$%&'*+-/=?^_`{|}~@.[] 를 제외한 모 든 글자를 제거하는 방법을 보여준다. 예제 5-3 사용자 이메일 주소 위험 제거 <?php $email = 'john@example.com'; $emailSafe = filter_var($email, FILTER_SANITIZE_EMAIL);

[예제 5-4]는 사용자 소개에서 아스키 번호가 32보다 작은 문자열을 제거하고 127보다 큰 문 자열을 예외 처리하는 방법을 보여준다. 예제 5-4 사용자 프로파일에서의 다국어 문자 제거 <?php $string = "\nIñtërnâtiônàlizætiøn\t "; $safeString = filter_var( $string,

FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW|FILTER_FLAG_ENCODE_HIGH

);

5장 모범 사례

55


더 많은 filter_var() 플래그와 옵션은 http://php.net/manual/function.filter-var.php에 서 찾아볼 수 있다.

5.1.2 유효성 검사 데이터의 유효성을 검사하는 일도 중요하다. 위험 제거와 달리 유효성 검사는 입력 데이터에 서 정보를 제거하지 않는다. 유효성 검사는 오직 입력 데이터가 요구 조건에 맞는지만 확인한 다. 이메일 주소를 기대했다면 입력 데이터가 이메일 주소가 맞는지 확인하고, 전화번호를 기 대했다면 데이터가 전화번호인지 확인한다. 딱 거기까지만이다. 유효성 검사는 애플리케이션 저장소 계층이 정확하고 양식화된 정보를 저장할 수 있도록 보장한다. 만일 부적절한 데이터 를 발견하면 데이터 저장 작업을 중단하고 애플리케이션 사용자에게 적절한 오류 메시지를 노 출한다. 또한 유효성 검사는 잠재적인 데이터베이스 오류를 방지한다. 예를 들어 MySQL에 DATETIME을 입력해야 할 상황에서 next year라는 문자열을 입력하면 MySQL은 오류를 내거

나 기본(부정확한)값을 사용할 것이다. 두 경우 모두 부적절한 데이터로 인해 애플리케이션의 데이터 무결성이 위협받는다. filter_var ( ) 함수에 FILTER_VALIDATE_* 플래그를 써서 사용자 입력의 유효성을 검사할

수 있다. PHP는 불리언, 이메일, 실수, 정수, IP 주소, 정규표현식, URL 등을 검사할 수 있는 플래그를 제공한다. [예제 5-5]는 이메일 주소의 유효성을 검사하는 방법을 보여준다. 예제 5-5 이메일 주소 유효성 검사 <?php $input = 'john@example.com'; $isEmail = filter_var($input, FILTER_VALIDATE_EMAIL); if ($isEmail != = false) { echo "성공"; } else { echo "실패"; }

filter_var ( ) 함수가 반환하는 값을 주의 깊게 살펴보자. 검사에 성공하면 원래 값을 반환하

고 검사에 실패하면 false를 반환한다.

56

2부 모범 사례


CHAPTER

6

호스팅

이제 여러분에게는 PHP 애플리케이션이 있다. 축하할 일이긴 하지만, 여러분도 알다시피 사 용자가 없는 애플리케이션은 그 누구에게도 어떠한 도움도 주지 못한다. 여러분은 애플리케이 션을 서버에 올리고 애플리케이션을 사용할 사람들에게 열어주어야 한다. 일반적으로 PHP 애 플리케이션은 네 가지 방법으로 호스팅할 수 있다. 공유 서버, 가상 사설 서버, 전용 서버, 서비 스로서의 플랫폼(PaaS )이다. 이들은 저마다 나름대로 이점이 있으므로 다양한 애플리케이션 종류와 예산에 맞춰 사용할 수 있다. 웹 호스팅 업체 역시 많아서, 이 방면에 경험이 없는 이들에게는 업체 선택이 난감할 수도 있을 것이다. 호스팅 업체 중에는 공유 서버만 제공하는 업체가 있는가 하면 공유 서버, 가상 사설 서버, 전용 서버를 혼합해서 제공하는 업체도 있다. 이번 장에서는 호스팅 업체보다는 호스팅 방식에 좀 더 초점을 맞춰볼 것이다.

6.1 공유 서버 공유 서버는 가장 저렴한 호스팅 방식으로 비용은 월 1만 원대부터 있다. 공유 호스팅 방식은 피하도록 하자. 공유 호스팅 제공 업체의 고객 지원이나 서비스 품질 때문이 아니다. 좋은 공유 호스팅 업체는 많지만 공유 호스팅 방식 자체가 별로 개발자 친화적이지 않기 때문이다. 이름 에서 알 수 있듯이 공유 서버는 다른 사람들과 자원을 공유하는 서버를 의미한다. 공유 호스팅 방식을 구매하면 여러분은 동일한 물리적 장비를 많은 고객과 함께 쓰게 된다. 만약 이 장비의

6장 호스팅

57


메모리가 2GB로 한정되어 있다면 여러분의 PHP 애플리케이션은 같은 장비를 사용하는 고객 수에 따라 전체 메모리 중 일부만 할당받게 된다. 만약 동일한 장비를 쓰는 다른 계정에서 형편 없는 스크립트를 실행하면 그 결과로 인한 나쁜 영향이 여러분의 애플리케이션에 미칠 수도 있 다. 일부 공유 호스팅 업체는 공유 서버를 과도하게 운영하기도 하는데, 이런 호스팅을 이용하 는 PHP 애플리케이션은 혼잡한 시스템 속에서 자신의 자원을 확보하기 위해 끊임없이 전쟁을 치러야 한다. 공유 서버는 사용자가 원하는 대로 설정하기에는 매우 어렵다. 어쩌면 여러분의 애플리케이션 에 멤캐시드(http://memcached.org )나 레디스(http://redis.io ) 같은 고속 메모리 캐시가 필 요하게 될 수도 있고, 검색 기능을 향상하기 위해 엘라스틱서치( http://www.elasticsearch.

org )를 설치해야 할 상황이 생길 수도 있다. 하지만 불행히도 공유 서버 소프트웨어로는 이런 일들을 마음대로 하기 어렵고, 아예 불가능할 수도 있다. 결과적으로는 애플리케이션이 감당해 야 할 몫만 커지게 된다. 공유 서버는 보통 원격 SSH 접속을 허용하지 않는다. 그 대신 (S )FTP 접속만 제한적으로 허 용하곤 한다. 이런 제약 조건은 PHP 애플리케이션 배포 자동화 작업을 심각하게 제한한다. 예산이 아주 적다거나 여러분의 요구 조건이 극히 사소하다면 공유 서버만으로도 충분할 수도 있다. 그러나 상업적인 웹 사이트 혹은 어느 정도 대중적인 PHP 애플리케이션을 구축하려 한 다면 가상 사설 서버, 전용 서버, PaaS를 이용하는 편이 더 낫다.

6.2 가상 사설 서버 가상 사설 서버(VPS )는 보기에는 마치 단독 서버1처럼 작동하지만 알고 보면 단독 서버가 아 니다. VPS는 단일 혹은 여러 물리적 장비에 걸쳐 분산된 시스템 자원 집합이다. VPS에는 자신 만의 파일시스템, 루트 사용자, 시스템 프로세스, IP 주소가 있다. VPS는 지정된 메모리 용량,

CPU, 대역폭을 할당받으며 여러분은 이런 자원을 온전히 사용할 수 있다. VPS는 공유 서버보다 더 많은 시스템 자원을 제공한다. SSH를 통해 루트 계정으로 VPS에 접 근할 수 있고 제한 없이 소프트웨어를 설치할 수 있지만, 큰 힘에는 큰 책임이 따르는 법이다.

1 역자주_ 베어메탈 서버bare-metal server를 의미하지만 여기서는 분산된 가상 서버의 상대적인 개념이라서 단독 서버로 번역했다.

58

3부 배포, 테스팅, 튜닝


VPS는 순정 운영체제에 대한 루트 접근 권한을 제공하며 여러분은 직접 운영체제를 구성하고 안전하게 관리해야 한다. VPS는 PHP 애플리케이션 대부분에 이상적인 환경이다. 충분한 시 스템 자원(예: CPU, 메모리, 디스크 용량)을 제공하며 필요에 따라 규모를 늘리거나 줄일 수 있다. VPS는 PHP 애플리케이션에 필요한 시스템 자원에 따라 월 1만 원에서 10만 원 가량의 비용이 든다. PHP 애플리케이션의 인기가 엄청나게 올라가(월 방문자 수가 수십만 단위 이 상) VPS에 너무 많은 비용이 들어가게 되면 전용 서버로 업그레이드를 고려해봐야 한다. TIP

VPS를 쓰면 비용, 기능, 유연성 사이에 균형을 조절할 수 있어서 나는 거의 VPS를 선호한다. 내가 애용하는 호스팅 업체는 VPS와 전용 호스팅 방식을 제공하는 리노드(https://linode.com)다. 리노드가 최저가의 업 체는 아니지만 내 경험에 의하면 빠르고 안정적이며, 값진 보물처럼 유용한 튜토리얼을 함께 제공한다.

6.3 전용 서버 전용 서버는 호스팅 업체가 사용자를 대신해 설치, 운영, 관리하는 랙 장착 장비로, 사용자 가 원하는 정확한 사양에 맞춰 구성된다. 전용 서버는 운반, 설치, 관제가 필요한 실제 장비라

VPS만큼 신속하게 구성할 수는 없다. 하지만 전용 서버를 사용하면 PHP 애플리케이션에 필 요한 궁극적인 성능을 낼 수 있다. 전용 서버는 VPS와 비슷하게 움직인다. 여러분은 SSH를 통해 순정 운영체제에 루트 계정으로 접속하며, PHP 애플리케이션에 맞게 운영체제를 설정하고 단속해야 한다. 전용 서버는 비용 대비 효율성 면에서 유리하다. VPS는 시스템 자원 소모가 늘어남에 따라 결과적으로 비용이 너무 많이 든다. 이럴 경우에는 전용 인프라를 직접 구축하는 편이 비용을 더 절감할 수 있다. 전용 서버에 소요되는 비용은 매월 수십만 원 정도며 사양에 따라 다르다. 전용 서버에는 비관 리(즉, 여러분이 직접 관리하는) 서버와 관리(즉, 추가 비용을 내고 호스팅 업체에서 관리하 는) 서버가 있다.

6.4 PaaS 서비스로서의 플랫폼(PaaS, 파스)은 PHP 애플리케이션을 신속하게 실행할 수 있는 수단이 며, 가상 사설 서버나 전용 서버와는 달리 여러분이 직접 관리할 필요가 없다. 여러분은 그저

6장 호스팅

59


PaaS 공급 업체의 제어판에 로그인하고 버튼을 몇 개 클릭하기만 하면 된다. 일부 PaaS 공급 업체는 PHP 애플리케이션을 배포하고 관리할 수 있도록 명령행 혹은 HTTP API를 제공한다. 다음은 많이 알려진 PHP PaaS 공급 업체들이다. 앱포그AppFog (https ://www.appfog.com/)

AWS 엘라스틱 빈스토크AWS Elastic Beanstalk (http ://aws.amazon.com/elasticbeanstalk/)

엔진 야드Engine Yard (https ://www.engineyard.com/products/cloud )

포트래빗Fortrabbit (http ://fortrabbit.com/)

구글 앱 엔진Google App Engine (http ://bit.ly/g -app -engine )

헤로쿠Heroku (https ://devcenter.heroku.com/categories/php )

마이크로소프트 애저Microsoft Azue (http ://www.windowsazure.com/)

파고다 박스Pagoda Box (https ://pagodabox.com/)

레드햇 오픈시프트Red Hat OpenShift (http ://openshift.com/)

젠드 개발자 클라우드Zend Developer Cloud (http ://bit.ly/z -dev -cloud )

PaaS 가격 정책은 공급 업체에 따라 다양하지만 가상 사설 서버와 비슷한 월 1만 원~10만 원 선이다. PHP 애플리케이션에 할당된 시스템 자원에 대한 비용을 지불하며 필요에 따라 시스 템 자원 규모를 늘리거나 줄일 수 있다. 서버를 직접 관리하고 싶지 않은 개발자들에게는 PaaS 호스팅 방식을 추천한다.

6.5 호스팅 선택 호스팅은 시기와 용도에 맞게 적절히 선택하면 된다. 여러분은 언제든지 필요에 따라 호스팅 인프라의 규모를 키우거나 줄일 수 있다. 소형 PHP 애플리케이션이나 프로토타입에는 엔진 야드 또는 헤로쿠 같은 PaaS 공급 업체를 통한 호스팅이 가장 적당하고 빠르다. 서버 구성을 좀 더 제어하고 싶다면 VPS를 이용하면 된다. 여러분의 애플리케이션이 엄청나게 인기를 끌고

VPS가 수백만 명의 방문자로 휘청거리게 된다면(일단 축하부터 하고), 전용 서버를 이용하도 록 하자. 어떤 호스팅 방식을 선택하든 모던 PHP 버전과 더불어 여러분의 PHP 애플리케이션 에 필요한 확장을 제공해주는지 꼭 확인하도록 한다.

60

3부 배포, 테스팅, 튜닝


CHAPTER

7

프로비저닝

애플리케이션 호스트를 선택했으니 이제 PHP 애플리케이션을 올릴 서버를 설정하고 프로비 전할 차례다. 솔직히 말하면 프로비저닝은 과학적인 이론이라기보다는 예술적인 기교에 가깝 다. 서버를 프로비전하는 방법은 전적으로 애플리케이션이 무엇을 필요로 하는가에 달려 있다. PaaS를 이용하는 경우에는 PaaS 공급 업체가 서버 인프라를 관리하기 때문에 PaaS 공급 업체의 지시에 따라 PHP 애플리케이션을 PaaS 플랫폼으로 옮기기만 하면 모든 준비가 끝난다.

PaaS를 사용하지 않는다면 PHP 애플리케이션을 실행할 VPS 혹은 전용 서버를 프로비전해야 만 한다. 서버 프로비저닝은 용어 자체가 주는 느낌만큼 어려운 작업은 아니지만(웃지 말 것), 명령행에 어느 정도 익숙한 사람이어야 수행할 수 있는 작업이다. 도무지 명령행에 적응을 못 하겠다면 엔진 야드나 헤로쿠 같은 PaaS를 이용하는 편이 더 낫다. 나는 시스템 관리자를 자처하지는 않는다. 하지만 기초적인 시스템 관리는 애플리케이션 개발 자에게 대단히 가치 있는 능력이며, 애플리케이션 개발 과정이 더 유연하고 탄탄하게 진행될 수 있도록 뒷받침해준다. 이번 장에서 나는 여러분이 PHP 애플리케이션 서버를 프로비전할 때 마음 편하게 터미널을 열 수 있도록 나의 시스템 관리 지식을 공유해줄 것이다. 또한 말미에 는 여러분이 시스템 관리 스킬을 계속해서 향상하는 데 도움이 될 만한 몇 가지 추가적인 참고 자료도 추천해줄 것이다.

7장 프로비저닝

61


이번 장에서 나는 여러분이 (거의 모든 리눅스 배포판에서 사용 가능한) 나노(http://www.nano-

editor.org)나 빔(http://www.vim.org) 같은 명령행 편집기 사용법을 알고 있다고 간주하겠다. 명령행 편 집기가 아니라면 다른 방법을 통해서라도 서버에 있는 텍스트 파일을 수정할 수 있어야 한다.

7.1 목표 우선 가상 사설 서버 혹은 전용 서버를 준비한다. 다음으로는 HTTP 요청을 수신할 웹 서버를 설치해야 한다. 마지막으로 웹 서버와 통신하며 PHP 요청을 처리할 PHP 프로세스 그룹을 구 성하고 관리해야 한다. 몇 년 전까지만 해도 아파치 웹 서버와 아파치 mod_php 모듈을 설치하는 방식이 일반적이었 다. 아파치 웹 서버는 각 HTTP 요청을 처리할 고유한 자식 프로세스를 생성하고, 아파치 mod_ php 모듈은 각 자식 프로세스(설령 자바스크립트, 이미지, 스타일시트 같은 정적 자산만 제공

하는 프로세스라 해도)에 고유한 PHP 인터프리터를 배정한다. 이런 방식은 시스템 자원이 과 하게 낭비되는 결과를 낳는다. 이제는 이보다 더 효율적인 방법이 있기 때문에, 아파치를 쓰는

PHP 개발자가 점점 줄고 있다. 요즘에는 엔진엑스( http://nginx.org/) 웹 서버를 사용하며, 이를 PHP-FPM 프로세스 집합 전방에 배치하며 PHP 요청을 전달하게 한다. 이런 구성 방식을 이번 장에서 실습해볼 것이다.

7.2 서버 설정 먼저 가상 사설 서버(VPS )를 설정해보자. 나는 리노드(http://linode.com/)를 정말로 좋아한 다. 리노드는 최저가 VPS 공급 업체는 아니지만 가장 신뢰할 만한 업체 중 하나다. 리노드 웹 사이트(혹은 선호하는 공급 업체)에 들어가 VPS를 새로 구입하고 신규 서버에 설치될 리눅스 배포판과 서버 루트 비밀번호를 결정하자. TIP

62

리노드(http://linode.com/)나 디지털 오션(https://www.digitalocean.com)을 포함한 많은 VPS 공급

3부 배포, 테스팅, 튜닝


업체는 시간 단위로 비용을 청구한다. 이 말은 사실상 전혀 비용을 들이지 않고도 VPS를 다뤄볼 수 있다는 의미다.

7.2.1 최초 로그인 우선 신규 서버에 로그인부터 해야 한다. 지금 당장 해보자. 로컬 장비에서 터미널을 열고 다음 ssh 명령을 실행해 서버에 접속한다. IP 주소는 여러분의 서버에 맞게 바꾸도록 한다. ssh root@123.456.78.90

신규 서버에 처음 접속할 때에는 다음과 같은 호스트 진위를 확인하는 메시지가 표시될 수도 있다. yes를 입력하고 <Enter>를 누른다. The authenticity of host '123.456.78.90 (123.456.78.90)' can't be established. RSA key fingerprint is 21:eb:37:f3:a5:d3:c0:77:47:c4:15:3d:3c:dc:3c:d1. Are you sure you want to continue connecting (yes/no)?

다음으로 아래 같은 메시지가 나오면 루트 사용자의 비밀번호를 입력하고 <Enter>를 누른다. root@123.456.78.90's password:

이제 신규 서버에 최초 로그인을 완료했다!

7.2.2 소프트웨어 업데이트 바로 이어서 운영체제 소프트웨어를 업데이트하기 위해 다음 명령을 실행한다. # 우분투

apt-get update; apt-get upgrade; # CentOS yum update

7장 프로비저닝

63


이 명령을 실행하면 운영체제 소프트웨어 업데이트를 내려받고 적용하는데, 그에 따라 상당히 많은 정보가 쏟아져 나온다. 이 과정은 운영체제 기본 소프트웨어에 최신 업데이트와 보안 픽 스security fixes를 적용하는 중요한 첫 번째 단계다.

7.2.3 비루트 사용자 신규 서버는 안전하지 않다. 신규 서버 보안을 강화하기 위한 몇 가지 좋은 관행이 있는데, 우 선 루트가 아닌 일반 사용자를 생성해야 한다. 여러분은 앞으로 이 일반 사용자로 서버에 로그 인해야 한다. 루트 사용자는 서버를 무제한적으로 다룰 권한이 있는 신과 같은 존재며, 어떤 명 령이라도 이의 없이 실행할 수 있다. 여러분은 루트 사용자의 서버 접근을 가능한 한 어렵게 만 들어야 한다.

우분투 [예제 7-1]을 실행해 deploy라는 이름으로 새로운 사용자를 생성한다. 요청에 따라 사용자 비 밀번호를 입력하고 나머지는 화면에 나오는 지시를 따른다. 예제 7-1 우분투에서 비루트 사용자 생성

adduser deploy

그리고 다음 명령을 실행해 deploy 사용자를 sudo 그룹에 할당한다. usermod -a -G sudo deploy

위 명령은 deploy 사용자에 sudo 권한을 부여한다(즉, 특수한 권한이 필요한 작업을 비밀번호 인증을 통해 수행할 수 있다).

CentOS 다음 명령을 실행해 deploy라는 이름으로 새로운 사용자를 생성한다.

64

3부 배포, 테스팅, 튜닝


adduser deploy

다음 명령으로 deploy 사용자에 비밀번호를 지정한다. 요청에 따라 사용자 비밀번호를 입력하 고 확인을 위해 다시 한 번 입력한다. passwd deploy

그리고 다음 명령을 실행해 deploy 사용자를 wheel 그룹에 할당한다. usermod -a -G wheel deploy

위 명령은 deploy 사용자에 sudo 권한을 부여한다(즉, 특수한 권한이 필요한 작업을 비밀번호 인증을 통해 수행할 수 있다).

7.2.4 SSH 키 쌍 인증 로컬 장비에서 다음 명령을 실행해 deploy 사용자로 신규 서버에 로그인 할 수 있다. ssh deploy@123.456.78.90

deploy 사용자의 비밀번호를 입력하라는 요청에 응답하면 서버로 로그인하게 된다. 로그인 과

정을 더욱 안전하게 보호하기 위해 비밀번호 인증을 비활성화시킬 수도 있다. 비밀번호 인증 은 무차별 대입 공격에 취약하다. 무차별 대입 공격이란 타인의 비밀번호를 알아내기 위해 비 밀번호를 바꿔가며 연속적으로 인증을 시도하는 행위다. ssh 서버 접속 시 비밀번호 인증 대신

SSH 키 쌍 인증을 사용해 이런 위협을 방지한다. 키 쌍 인증은 복잡한 주제지만 기본적인 정의는 다음과 같다. 여러분은 로컬 장비에 한 쌍의 키 를 만들 수 있는데 이 중 하나는 (로컬 장비에 저장되는) 개인 키며 다른 하나는 (원격 서버에 저장되는) 공개 키다. 공개 키로 암호화된 메시지는 오직 그에 맞는 개인 키로만 복호화할 수 있고 이들을 키 쌍이라 부른다.

SSH 키 쌍 인증을 이용한 접속 과정은 다음과 같다. 원격 장비로 ssh 접속을 시도하면 원격 장 비는 임의의 메시지를 생성하고 공개 키로 암호화한 다음 로컬 장비로 전송한다. 로컬 장비에

7장 프로비저닝

65


서는 개인 키를 사용해 메시지를 해독하고 이 메시지를 원격 서버로 반환한다. 원격 서버는 반 환된 메시지가 유효한지 검사한 다음 서버 접속을 승인하게 된다. 상당히 개략적인 설명이긴 하지만 요점은 파악할 수 있을 것이다. 원격 서버로 로그인하는 컴퓨터가 많을 때는 SSH 키 쌍 인증을 사용하기 어려울지도 모른다. 모든 로컬 컴퓨터에서 공개/개인 SSH 키 쌍을 생성하고 각 컴퓨터의 공개 키를 원격 서버로 복 사해야 하기 때문이다. 이런 경우에는 비밀번호 인증 방식이 더 나을 수도 있다. 하지만 (많은 개발자가 그러하듯이) 로컬 컴퓨터 한 대에서 원격 서버에 접근하는 경우라면 SSH 키 쌍 인증 이 바람직하다. 다음 명령을 실행하면 로컬 컴퓨터에 SSH 키 쌍을 생성할 수 있다. ssh-keygen

화면에 나오는 지시를 따라 진행하면서 요청받은 정보를 입력한다. 명령을 실행하고 나면 ~/.ssh/id_rsa.pub (공개 키) 파일과 ~/.ssh/id_rsa (개인 키) 파일이 생긴다. 개인 키는 로 컬 컴퓨터에 두고 유출되지 않도록 보호해야 하며 공개 키는 여러분의 신규 서버로 복사해야 한다. scp (보안 복사secure copy ) 명령으로 공개 키를 서버로 복사할 수 있다. scp ~/.ssh/id_rsa.pub deploy@123.456.78.90:

마지막에는 꼭 콜론 문자(: )를 붙여야 한다! 이 명령을 실행하면 공개 키가 원격 서버 사용자 deploy의 홈 디렉터리에 업로드된다. 이제 deploy 사용자로 원격 서버에 로그인한다. 원격 서

버에 로그인하면 ~/.ssh 디렉터리가 존재하는지 확인하고, 없을 경우에는 다음 명령을 실행해 ~/.ssh 디렉터리를 생성한다. mkdir ~/.ssh

그리고 다음 명령으로 ~/.ssh/authorized_keys 파일을 생성한다. touch ~/.ssh/authorized_keys

이 파일은 원격 로그인을 허용할 공개 키 목록을 넣어둘 파일이다. 방금 업로드한 공개 키를 ~/.ssh/authorized_keys 파일에 추가하기 위해 다음 명령을 실행한다.

66

3부 배포, 테스팅, 튜닝


CHAPTER

8

튜닝

이제 여러분의 PHP 애플리케이션은 자신의 PHP-FPM 프로세스 풀을 통해 엔진엑스와 나란 히 실행되고 있다. 하지만 아직 다 끝나지 않았다. 여러분의 애플리케이션과 프로덕션 서버에 알맞게 PHP 설정을 튜닝해야 한다. 설치된 상태 그대로의 PHP는 동네 백화점에서 볼 수 있는 기성 양복과도 같아서, 그럭저럭 맞긴 하지만 아주 잘 맞지는 않는다. 튜닝이 잘 된 PHP는 여 러분의 치수에 딱 맞게 제작된 맞춤 양복이라 할 수 있다. 그렇다고 너무 앞서가지는 말자. PHP 튜닝이 애플리케이션 성능 문제에 대한 만병통치약은 아니다. 이를테면 부적절한 SQL 쿼리나 응답 없는 API 같이 나쁜 코드로 인해 발생하는 문제 는 PHP 튜닝으로 해결할 수 없다. 그렇긴 해도, PHP 튜닝은 PHP 효율과 애플리케이션 성능 을 향상할 수 있는 가장 쉽고 빠른 방법이다.

8.1 php.ini 파일 PHP 인터프리터는 php.ini라는 파일로 설정하며 튜닝한다. 이 파일은 경우에 따라 다른 위치 의 것을 사용한다. 앞서 실습한 방법대로 PHP-FPM을 통해 PHP를 실행한다면 /etc/php5/

fpm/php.ini에 있다. 묘하게도 이 php.ini 파일은 명령행에서 호출한 PHP 인터프리터와는 관계가 없다. 명령행에서 호출하는 PHP는 별도의 php.ini 파일로 제어하며 이 파일은 보통 /

etc/php5/cli/php.ini에 있다. 만일 소스를 이용해 PHP를 설치했다면 소스 설정 단계에서

8장 튜닝

67


지정했던 $PREFIX 디렉터리에 php.ini 파일이 있을 것이다. 나는 여러분이 PHP-FPM을 통 해 PHP를 실행한다고 간주하지만, 앞으로 나올 최적화 방법들은 모든 php.ini 파일에 적용할 수 있다. 여러분의 php.ini 파일이 모범 보안 사례에 적합한지 알아보려면, 크리스 코넛이 제작한 PHP 이니스캔Iniscan

TIP

(https://github.com/psecio/iniscan)으로 php.ini 파일을 검사해보자. php.ini 파일은 INI 형식으로 작성한다. INI 파일 형식에 대해서는 위키백과(https://ko.wikipedia.org/

TIP

wiki/INI_파일)에서 알아볼 수 있다.

8.2 메모리 PHP를 실행할 때 제일 먼저 고려해야 할 사항은 각 PHP 프로세스가 소비하는 메모리양이다. php.ini 파일에 있는 memory_limit 설정은 하나의 PHP 프로세스가 사용할 수 있는 최대 시 스템 메모리를 결정한다. 이 설정의 기본값은 128M인데, 이 정도면 중소 규모 PHP 애플리케이션 대부분에 적당하다. 하지만 초소형 PHP 애플리케이션을 실행할 때는 이 값을 64M 정도로 낮춰 시스템 자원을 절 약할 수 있으며, 메모리 집약적인 PHP 애플리케이션(예: 드루팔 웹 사이트)을 실행할 때는 512M 정도로 올려 성능을 향상할 수도 있다. 구체적인 설정값은 시스템의 가용 메모리에 의해

좌우된다. PHP에 할당된 메모리양을 알아내는 방법은 과학적인 이론이라기보다는 예술적인 기교에 더 가깝다. PHP에 허용할 수 있는 한계 메모리와 최대 PHP-FPM 프로세스 수를 결 정하려면 다음과 같은 질문에 답할 수 있어야 한다. PHP에 할당할 수 있는 총 메모리는 얼마인가

우선 시스템 메모리를 얼마만큼 PHP에 할당할지 결정한다. 예를 들어 내가 사용하는 리노드 가상 컴퓨터의 전체 메모리는 2GB다. 하지만 다른 프로세스(예: 엔진엑스, MySQL, 멤캐시)가 동일한 시스템에서 실행 중 이며 각자 메모리를 소비하고 있어서, PHP용으로 안전하게 확보할 수 있는 메모리는 512MB 정도다. 단일 PHP 프로세스가 소비하는 평균 메모리는 얼마인가

다음으로 하나의 PHP 프로세스가 소비하는 평균 메모리를 결정한다. 이를 위해서는 프로세스의 메모리 사용 량을 지켜봐야 한다. 명령행에서는 top 명령을 실행하면 현재 실행 중인 프로세스에 대한 실시간 통계를 볼 수 있으며, PHP 스크립트 맨 마지막에 memory_get_peak_usage ( ) 함수를 호출하면 해당 스크립트가 소비하는 최대 메모리를 출력할 수도 있다. 어느 쪽이든, 같은 PHP 스크립트를 (캐시가 준비될 때까지) 여러

68

3부 배포, 테스팅, 튜닝


번 실행한 다음 평균 메모리 소비량을 구하면 된다. PHP 프로세스의 메모리 소모량은 보통 5MB~20MB 사이다. 그렇지만 파일 업로드, 이미지 데이터, 메모리 집약적인 애플리케이션 등을 다룬다면 그보다 확연히 높 을 것이다. 얼마나 많은 PHP -FPM 프로세스를 감당할 수 있는가

PHP에 할당된 총 메모리는 512MB이며 각 PHP 프로세스가 평균적으로 소비하는 메모리는 15MB로 정 했다. 총 메모리를 개별 PHP 프로세스 메모리로 나누면 감당할 수 있는 PHP -FPM 프로세스 개수를 알 수 있으며 여기서는 34가 된다. 이 값은 추정치며 실험 과정을 거쳐 개선해야 한다. 시스템 자원은 충분한가

마지막으로 PHP 애플리케이션을 실행하고 예상 웹 트래픽을 처리할 수 있는 충분한 시스템 자원이 있다고 확신하는지 스스로에게 물어봐야 한다. “예”라고 대답할 수 있다면 좋겠지만 그렇지 않다면 서버 메모리 용량 을 업그레이드하고 첫 번째 질문으로 되돌아가야 한다.

프로덕션과 유사한 환경을 구성해 PHP 애플리케이션을 올리고 아파치 벤치(http://bit.ly/apache -bench)나 시즈(http://www.joedog.org/siege-home/)를 이용해 부하 테스트를 수행하라. 프로덕션에 애플리케이션을 올렸을 때 메모리 부족 문제가 발생하지 않도록 사전에 확인해두는 것이 현명한 처사다.

8.3 젠드 오피캐시 메모리 할당량을 계산하고 나면 PHP 젠드 오피캐시Zend OPcache 확장을 설정하고 오피코드OPcode 캐시를 활성화한다. 오피코드 캐시란 무엇인가? 먼저 일반적인 PHP 스크립트가 HTTP 요청 을 처리하는 과정을 살펴보자. 우선 엔진엑스는 PHP-FPM에 HTTP 요청을 전달하고 PHP-

FPM은 자식 PHP 프로세스에 요청을 할당한다. PHP 프로세스는 필요한 PHP 스크립트들 을 찾아서 읽어들이고 오피코드(또는 바이트코드) 형식으로 컴파일한다. 컴파일된 오피코드 는 HTTP 응답을 생성하고 엔진엑스는 이 HTTP 응답을 HTTP 클라이언트로 반환한다. 모든

HTTP 요청에 대해 이와 같은 과정을 반복하면 많은 부하가 발생하게 된다. 각 PHP 스크립트마다 컴파일된 오피코드 캐시를 생성하면 이 과정의 속도를 높일 수 있다. 이 렇게 하면 HTTP 요청마다 PHP 스크립트를 찾고, 읽고, 컴파일하는 대신, 미리 컴파일된 오 피코드를 실행할 수 있다. 젠드 오피캐시 확장은 PHP 5.5.0 이상에 내장되어 있다. 다음은 젠 드 오피캐시 확장을 설정하고 최적화한 나의 php.ini 설정이다.

8장 튜닝

69


opcache.memory_consumption = 64 opcache.interned_strings_buffer = 16 opcache.max_accelerated_files = 4000 opcache.validate_timestamps = 1 opcache.revalidate_freq = 0 opcache.fast_shutdown = 1

opcache.memory_consumption = 64

이 설정은 오피코드 캐시에 할당된 메모리 용량(메가바이트 단위)을 지정한다. 애플리케이션에 있는 모든

PHP 스크립트의 컴파일 오피코드를 저장할 수 있을 만큼 충분히 커야 한다. 스크립트 수가 적은 소형 PHP 애플리케이션이라면 16MB 정도로 낮은 값을 사용하며 스크립트 수가 많은 대형 PHP 애플리케이션이라면

64MB 정도로 큰 값을 사용한다. opcache.interned_strings_buffer = 16

이 설정은 인턴화된interned 문자열을 저장하는 데 사용되는 메모리 용량(메가바이트 단위)이다. 대체 인턴화된 문자열이 무엇인지 나 역시 궁금했다. 막후에서 PHP 인터프리터는 반복적으로 사용되는 문자열 인스턴스를 감지하고 메모리에 저장하며, 일단 저장한 후에는 같은 문자열이 다시 사용될 때마다 포인터를 활용해 메모 리를 절약한다. 이런 과정을 문자열 인턴화라고 한다. PHP의 문자열 인턴화는 기본적으로 각 PHP 프로세 스에 의해 고립되는데, 이 설정을 이용하면 모든 PHP -FPM 풀 프로세스가 인턴화된 문자열을 공유 버퍼에 저장하게 된다. 저장된 인턴화 문자열은 여러 PHP -FPM 풀 프로세스가 동시에 참조할 수 있으며 이런 과정 을 통해 더욱 많은 메모리를 절약할 수 있다. 이 설정의 기본값은 4MB지만 나는 한층 큰 값인 16MB를 선호 한다. opcache.max_accelerated_files = 4000

이 설정은 오피코드 캐시에 저장될 수 있는 PHP 스크립트의 최대 개수다. 200과 100000 사이에서 지정할 수 있으며, 나는 4000을 사용한다. 이 값은 PHP 애플리케이션에 있는 전체 스크립트 파일 수보다 커야 한다. opcache.validate_timestamps = 1

이 설정을 사용하면 PHP는 opcache.revalidate_freq 설정에 지정된 시간 간격마다 변경된 PHP 스 크립트가 있는지 확인한다. 이 설정이 비활성화되어 있으면 PHP가 스크립트 변경 여부를 확인하지 않기 때문 에, 변경된 스크립트의 캐시를 새로 생성하려면 수동으로 오피코드 캐시를 삭제해야 한다. 이 설정은 개발 기 간에만 사용하고 프로덕션 환경에서는 비활성화해두자. opcache.revalidate_freq = 0

이 설정은 컴파일된 PHP 파일의 변경 여부를 얼마나 자주 검사할지 지정한다. 캐시를 사용하면 매 요청마다

PHP 스크립트를 재컴파일하지 않는다는 이점이 있으며, 이 설정값은 캐시의 신선함을 판단할 기준 시간 간 격을 결정한다. 이 시간 간격이 지날 때마다 PHP는 PHP 스크립트 변경 여부를 확인하며, 변경을 감지하면 스크립트를 다시 컴파일하고 캐시를 새로 생성한다. 나는 이 값을 0으로 설정하는데, 이렇게 하면 opcache. validate_timestamps 설정이 활성화됐을 때에 한해서 매 요청마다 PHP 파일을 재검증한다. 다시 말 해 개발하는 동안 매 요청마다 PHP가 파일들을 재검증한다는 의미다(좋은 방법이다). 프로덕션 환경에서는 opcache.validate_timestamps 설정을 비활성화하기 때문에 이 설정은 신경 쓸 필요가 없다.

70

3부 배포, 테스팅, 튜닝


opcache.fast_shutdown = 1

이 설정을 사용하면 오피캐시가 객체의 소멸과 메모리 해제를 젠드 엔진 메모리 관리자에 위임해서 빠른 종료 단계를 거치게 된다. 이 설정에 대한 문서는 많지 않으며, 여러분은 그저 이 설정을 켜둬야 한다는 점만 알아두 면 된다.

8.4 파일 업로드 파일 업로드 기능이 없는 PHP 애플리케이션이라면 애플리케이션 보안을 향상하기 위해 파일 업로드 설정을 꺼두자. 그렇지 않다면 애플리케이션이 허용하는 최대 업로드 파일 크기와 애플 리케이션에 한 번에 업로드할 수 있는 최대 파일 개수를 설정해야 한다. 다음은 내가 사용하는

php.ini 설정이다. file_uploads = 1 upload_max_filesize = 10M max_file_uploads = 3

기본적으로 PHP는 단일 요청에 포함된 업로드를 20개까지 허용하며 각 업로드 파일의 최대 크기는 2MB다. 아마 한 번에 20개까지 업로드를 허용할 필요는 없을 것이다. 나는 단일 요청 에 업로드 세 개를 허용하지만 여러분은 각자 애플리케이션에 맞는 값으로 설정을 변경하자. 파일 업로드 기능이 있는 PHP 애플리케이션이라면 2MB보다 큰 파일 업로드를 허용해야 할 경우도 종종 있다. 그럴 때는 PHP 애플리케이션의 요구 사항에 맞게 upload_max_filesize 값을 10M 혹은 그보다 큰 값으로 설정한다. 너무 큰 값으로 설정하면 여러분의 웹 서버(예: 엔 진엑스)가 HTTP 요청 본문이 너무 크다고 불평하거나 응답 시간을 초과해버릴 수도 있으니 주의하자. 아주 큰 파일 업로드를 허용해야 한다면 웹 서버가 적절하게 구성되어 있는지 확인해야 한다. php.

ini 파일뿐만 아니라 엔진엑스 가상 호스트 설정에서 client_max_body_size(http://bit.ly/max-bodysize)를 조정해야 할 수도 있다.

8장 튜닝

71


8.5 최대 실행 시간 php.ini 파일에 있는 max_execution_time 설정은 단일 PHP 프로세스의 최대 실행 시간을 결정하며, 이 시간이 지나면 PHP 프로세스가 종료된다. 기본값은 30초지만 아무도 PHP 프로 세스를 30초 동안 실행하고 싶어 하지는 않는다. 우리는 애플리케이션 실행 속도가 (밀리초 단 위로 측정되는) 초고속이기를 바란다. 이 설정값은 5초로 지정하자. max_execution_time = 5

이 설정은 set_time_limit()(http://php.net/manual/function.set-time-limit.php) 함수 를 이용해 개별 스크립트 단위로 재정의할 수 있다.

PHP 스크립트를 장시간 실행해야 할 때는 어떻게 하냐고 묻는다면, 그래서는 안 된다고 대답 하겠다. PHP 실행 시간이 길어질수록 웹 애플리케이션 방문자의 대기 시간도 길어질 수밖에 없다. 실행 시간이 많이 걸리는 작업(예를 들어 이미지 크기를 조정하거나 보고서를 생성하는) 이라면 별도의 작업자 프로세스로 해당 작업을 넘겨주자. TIP

나는 exec() PHP 함수를 사용해서 bash 명령어를 호출한다. 이 함수를 이용하면 PHP 프로세스를 지연 시키지 않는 논블로킹 프로세스를 생성해 현재 PHP 스크립트로부터 분리할 수 있다. exec() 함수를 사용하 려면 escapeshellarg(http://php.net/manual/function.escapeshellarg.php) 함수로 셸 인수를 직 접 예외 처리해야 한다.

결과 보고서를 PDF 파일로 생성해야 한다고 가정해보자. 이 작업은 완료까지 10분 정도 걸 린다. PHP 요청이 완료될 때까지 10분 동안 기다리고 있을 사람은 아무도 없다. 대신 우리는

create-report.php라는 파일을 따로 만들고 이 파일을 10분 동안 계속 실행시켜 보고서를 생성한다. 반면 웹 애플리케이션은 백그라운드 프로세스를 분리하고 다음과 같은 HTTP 응답 을 반환하는 데 몇천 분의 1초밖에 걸리지 않는다. <?php

exec('echo "create-report.php" | at now'); echo '보고서 생성 중…';

create-report.php는 단독 스크립트며 백그라운드 프로세스로 실행되고, 실행이 완료되면

72

3부 배포, 테스팅, 튜닝


CHAPTER

9

배포

서버를 프로비전하고 엔진엑스와 PHP-FPM을 실행할 준비를 마쳤다면 이제 PHP 애플리케 이션을 프로덕션 서버로 배포해야 한다. 프로덕션으로 코드를 올리는 방법은 다양하다. 초창기

PHP 개발자들은 주로 FTP를 사용해서 PHP 코드를 배포했지만 오늘날에는 FTP보다 더 안전 하고 예측 가능한 배포 전략들이 있다. 이번 장에서는 단순하고 예측 가능하며 가역적Reversible인 방법으로 배포를 자동화해주는 최신 도구들을 알아본다.

9.1 버전 관리 여러분은 버전 관리를 잘 활용하고 있을 것이다. 만일 그렇지 않다면 하던 일을 멈추고 코드 버전 관리부터 시작해야 한다. 나는 주로 깃(http://git-scm.com )을 이용해 코드를 버전 관리 하지만 깃 외에 머큐리얼Mercurial ( http://mercurial.selenic.com ) 같은 버전 관리 소프트웨어 를 사용할 수도 있다. 깃은 내게 익숙한 도구며 비트버킷(https://bitbucket.org )이나 깃허브 (https://github.com ) 같은 온라인 저장소와도 매끄럽게 연동되기 때문에 나는 깃을 사용한다. 버전 관리는 PHP 애플리케이션 개발자에게 매우 귀중한 도구다. 버전 관리를 통해 코드베이 스의 변경 이력을 추적할 수 있기 때문이다. 버전 관리를 이용하면 코드베이스에 특정 배포 시 점을 지칭하는 태그를 붙이거나 코드베이스를 과거 버전으로 되돌릴 수 있으며, 프로덕션 코드 에 영향을 주지 않고도 새로운 기능을 시험해볼 수 있도록 브랜치를 분리할 수도 있다. 무엇보 다 버전 관리는 PHP 애플리케이션 배포를 자동화하는 데 있어 중요한 역할을 담당한다.

9장 배포

73


9.2 배포 자동화 애플리케이션 배포를 자동화하면 배포 과정이 단순해질 뿐만 아니라 배포 과정을 예측하거나 배포 상태를 이전으로 되돌릴 수도 있게 된다. 이 점이 배포 자동화가 중요한 이유다. 여러분에 게 가장 피하고 싶은 작업이 있다면 바로 복잡한 과정이 수반된 배포 작업일 것이다. 복잡한 배 포 과정은 부담스럽고, 부담스러운 작업은 누구나 기피하기 마련이다.

9.2.1 단순하게 배포 과정은 명령어 한 줄로 처리할 수 있을 정도로 단순해야 한다. 배포 과정이 단순해지면 배 포 작업에 대한 부담이 줄고 프로덕션으로 코드를 올리는 일이 좀 더 수월해진다.

9.2.2 예측 가능하게 배포 과정은 예측할 수 있어야 한다. 무슨 일이 벌어질지 정확히 알고 있으면 배포 과정에 대한 부담이 한층 더 줄어든다. 배포 과정에는 예기치 못한 부작용이 없어야 하며, 만약 오류가 발생 하더라도 즉시 작업을 중단하고 기존 코드베이스를 유지해야 한다.

9.2.3 가역적으로 배포 과정은 가역적이어야 한다. 좋지 않은 코드가 뜻하지 않게 프로덕션으로 배포됐다 하더라 도 간단한 명령어 한 줄만으로 이전 안정화 버전으로 되돌릴 수 있어야 하며, 가역적인 배포 과 정이 이러한 안전망의 역할을 한다. 배포 과정을 되돌릴 수 있다면 프로덕션에 코드를 올리는 일을 즐기게 즉, 두려워하지 않게 된다. 뭔가 망치더라도 이전 버전으로 되돌려버리면 그만이 기 때문이다.

9.3 카피스트라노 카피스트라노(http://capistranorb.com/)는 애플리케이션 배포를 단순하고 예측 가능하며 가 역적인 방법으로 자동화해주는 소프트웨어다. 카피스트라노는 로컬 컴퓨터에서 실행하며 SSH

74

3부 배포, 테스팅, 튜닝


를 통해 원격 서버와 소통한다. 카피스트라노는 원래 루비 애플리케이션을 배포하기 위해 제작 됐지만 PHP를 포함한 다른 모든 프로그래밍 언어에도 마찬가지로 유용하다.

9.3.1 작동 카피스트라노는 로컬 워크스테이션에 설치하는 도구다. 카피스트라노는 로컬 워크스테이션으 로부터 원격 서버로 SSH 명령을 내릴 수 있으며 이를 이용해 PHP 애플리케이션을 원격 서버 에 배포한다. 원격 서버에는 애플리케이션 배포 버전들로 구성된 카피스트라노 관리 디렉터리 가 생성되는데, 이전 버전으로 되돌려야 할 경우를 대비해 5개 이상의 애플리케이션 배포 디렉 터리가 유지된다. 또한 카피스트라노는 애플리케이션의 현재 배포 버전 디렉터리를 가리키는 심볼릭 링크인 current/ 디렉터리를 생성한다. [예제 9-1]은 프로덕션 서버에 구성된 카피스 트라노 관리 디렉터리의 예시 구조다. 예제 9-1 예제 디렉터리 구조 /

home/ deploy/ apps/ my_app/ current/ releases/ release1/ release2/ release3/ release4/ release5/

프로덕션에 새 애플리케이션 버전을 배포할 때 카피스트라노는 먼저 깃 저장소에서 애플리케 이션 코드의 최신 버전을 검색한다. 다음으로 신규 버전 디렉터리에 애플리케이션 코드를 배치 하고, 마지막으로 심볼릭 링크 디렉터리 current/를 신규 버전 디렉터리와 연결한다. 애플리케 이션을 이전 버전으로 되돌릴 때는 current/ 링크가 가리키는 대상을 이전 버전 디렉터리로 변 경만 하면 된다. 이처럼 카피스트라노는 우아하면서도 간결한 배포 솔루션이며, 카피스트라노 를 통해 단순하고, 예측 가능하며, 가역적인 방법으로 PHP 애플리케이션을 배포할 수 있다.

9장 배포

75


9.3.2 설치 카피스트라노는 로컬 장비에 설치하며 원격 서버에는 설치하지 않는다. 카피스트라노를 설치 하려면 ruby와 gem이 필요한데, OS X에는 기본적으로 설치되어 있으며 리눅스에는 패키지 관 리자로 설치할 수 있다. ruby와 gem을 설치하고 나면 다음 명령을 실행해 카피스트라노를 설 치한다. gem install capistrano

9.3.3 설정 카피스트라노를 설치한 다음에는 카피스트라노로 배포할 프로젝트를 초기화해야 한다. 터미널 을 열고 프로젝트 최상위 디렉터리로 이동해 다음 명령을 실행한다. cap install

이 명령을 실행하면 Capfile 파일을 비롯해 config/ 및 lib/ 디렉터리가 생성된다. 프로젝트 최상위 디렉터리에는 이제 다음과 같은 파일과 디렉터리들이 있을 것이다. Capfile config/ deploy/ production.rb staging.rb deploy.rb lib/ capistrano/ tasks/

Capfile 파일은 카피스트라노의 중앙 설정 파일이며 config/ 디렉터리에 있는 설정 파일들을 취합한다. config/ 디렉터리에는 각 원격 서버 환경(예: 테스트, 스테이징, 프로덕션)에 대한 설정 파일이 있다. 카피스트라노 설정 파일은 루비 언어로 작성되어 있지만 편집하거나 이해하는 데는 불편함이 없다.

76

3부 배포, 테스팅, 튜닝


기본적으로 카피스트라노는 한 애플리케이션이 다양한 환경에서 실행된다고 간주한다. 예를 들어 스테이징 환경과 프로덕션 환경이 분리되어 있다면 애플리케이션도 두 환경에 모두 배포 되어야 한다. 카피스트라노는 각 환경별로 설정 파일을 제공하며 이 설정 파일들은 config/

deploy/ 디렉터리에 있다. 또한 config/deploy.rb 파일에는 모든 환경에 공통적으로 적용되 는 설정이 있다. 카피스트라노는 각 환경을 구성하는 서버들을 서버 역할이라는 개념으로 분류한다. 예를 들면 프로덕션 환경은 최전방 웹 서버(web 역할), 애플리케이션 서버(app 역할), 데이터베이스 서 버(db 역할)로 구성된다. 이런 구조는 대규모 애플리케이션에만 사용되며 소형 PHP 애플리 케이션 환경에서는 일반적으로 웹 서버(엔진엑스), 애플리케이션 서버(PHP-FPM ), 데이터 베이스 서버(마리아DBMariaDB )가 모두 하나의 장비에서 실행된다. 앞으로 실습할 예제에서는 web 역할만 사용하고 app과 db 역할은 무시한다. 서버 역할을 활용 하면 배포 작업을 구분하고 특정 역할에 속한 서버에서만 실행되도록 구성할 수 있다. 여기서 는 서버 역할에 대해서는 다루지 않지만 서버 환경에 대한 개념은 준수할 것이다. 앞으로 나올 과정들은 프로덕션 환경을 대상으로 하며, 다른 환경(예: 스테이징staging 또는 테스팅testing )에도 동일하게 적용할 수 있다.

config/deploy.rb 파일 config/deploy.rb 파일을 살펴보자. 이 파일에 지정된 설정들은 모든 환경(예: 스테이징과 프로덕션)에 공통적으로 적용된다. 카피스트라노 설정 대부분이 이 파일에 있다. 즐겨 쓰는 편 집기로 config/deploy.rb 파일을 열고 다음 설정들을 수정해보자. :application

PHP 애플리케이션명을 지정한다. 애플리케이션명에는 문자, 숫자, 밑줄만 사용할 수 있다. :repo_url

깃 저장소 URL을 지정한다. 올바른 깃 저장소 URL이어야만 하며 원격 서버에서 접근할 수 있어야 한다. :deploy_to

PHP 애플리케이션이 배포될 원격 서버의 디렉터리 절대 경로를 지정한다. [예제 9 - 1]에서는 /home/

deploy/apps/my_app을 사용한다. :keep_releases

이전 배포 버전을 몇 개까지 보관할 것인지 지정한다. 보관된 버전들은 애플리케이션을 이전 버전으로 되돌릴 때 사용된다.

9장 배포

77


config/deploy/production.rb 파일 이 파일에는 프로덕션 환경에 대한 설정이 있다. 이 파일은 프로덕션 환경의 역할을 정의하고 각 역할에 속한 서버를 나열한다. 우리는 web 역할만 사용하며 이 역할에 속한 서버는 한 대다.

7장에서 프로비전한 서버를 사용하자. config/deploy/production.rb 파일 내용 전체를 다 음 내용으로 교체하고, IP 주소는 여러분에게 맞게 수정한다. role :web, %w{deploy@123.456.78.90}

9.3.4 인증 카피스트라노로 애플리케이션을 배포하기에 앞서 로컬 컴퓨터와 원격 서버, 원격 서버와 깃 저 장소 사이에 인증을 수립해야 한다. 우리는 앞서 로컬 컴퓨터와 원격 서버 사이에 SSH 키 쌍 인증을 설정하는 방법을 알아보았다. 이제 원격 서버와 자식 저장소 사이에 SSH 키 쌍 인증을 수립해보자. 앞서 설명한 지침을 따라 각 원격 서버에 SSH 공개 키와 개인 키 쌍을 생성한다. 깃 저장소는 각 원격 서버의 공개 키에 접근할 수 있어야 하는데, 깃허브와 비트버킷 모두 공개 SSH 키를 사용자 계정에 여러 개 등록할 수 있다. 이런 과정을 거쳐 궁극적으로는 암호를 입력하지 않고 도 원격 서버에 깃 저장소를 복제clone 할 수 있어야 한다.

9.3.5 원격 서버 애플리케이션을 배포할 준비가 거의 끝났다. 이제 원격 서버를 준비해야 한다. SSH로 원격 서 버에 로그인해서 PHP 애플리케이션을 배포할 디렉터리를 생성한다. 이 디렉터리는 deploy 사용자가 읽고 쓸 수 있어야 한다. 나는 다음과 같이 deploy 사용자의 홈 디렉터리에 애플리케 이션 디렉터리를 만든다. /

home/ deploy/ apps/ my_app/

78

3부 배포, 테스팅, 튜닝


CHAPTER

10

테스팅

테스팅은 PHP 애플리케이션 개발 과정의 중요한 일부분이지만 종종 도외시되곤 한다. 많은

PHP 개발자가 테스트를 하지 않는데, 테스트를 해봤자 소요 시간에 비해 얻을 수 있는 이익이 많지 않으며 오히려 불필요한 부담만 가중된다고 여기기 때문이다. 한편으로는 다양한 테스팅 도구와 가파른 학습곡선 때문에 테스트 방법을 습득하지 못하는 개발자들도 있다. 이번 장에서 나는 이러한 오해를 불식시키고자 한다. 나는 여러분이 편안하고 즐거운 마음으로

PHP 코드를 테스트하기 바란다. 또한 테스팅이 애플리케이션 개발 과정의 엄연한 일부분이며 개발 과정의 시작과 중간과 마지막을 함께하는 작업이라고 여기기 바란다.

10.1 테스트를 하는 이유 테스트를 작성하는 이유는 PHP 애플리케이션이 우리의 기대에 따라 지속적으로 작동하도록 보장하기 위해서다. 단지 그뿐이다. 여러분은 프로덕션으로 애플리케이션을 배포하고 나서 불 안에 떨어야 했던 경험이 얼마나 있는가? 예전에는 나도 코드를 테스트하지 않았으며 새로운 코드를 프로덕션으로 올리는 일에 두려움을 느꼈다. 코드가 제대로 작동할지 문제가 생기지는 않을지 걱정하면서도 그저 아무 일 없이 무사하기만을 두 손 모아 기도할 수밖에 없었다. 이런 방식은 코드에 전혀 도움이 되지 못하며 두려움과 스트레스를 유발할 뿐만 아니라 대개의 경우 실망스러운 결과를 야기한다. 하지만 테스트를 이용하면 불확실성을 줄이고 코드 작성과 배포 에 확신이 생긴다.

10장 테스팅

79


여러분의 상사는 테스트를 작성할 시간적인 여유가 없다고 항변할지 모르지만, 결국 시간은 돈 이라는 관점에서 보자면 이는 근시안적인 주장이다. 테스팅 인프라를 갖추고 테스트 코드를 작 성하는 일에는 시간이 걸리지만 이 과정은 장래에 수령할 배당금이 보장된 현명한 투자와도 같 다. 테스트를 이용하면 처음부터 잘 작동하는 코드를 작성할 수 있을 뿐만 아니라 이를 지속적 으로 반복하면서도 기존 코드에 문제를 일으키지 않게 된다. 테스트를 수행하면 개발 속도가 지연될 수도 있지만, 미처 발견하지 못했던 버그를 수정하고 리팩토링하느라 낭비될지도 모를 무수한 개발 시간을 미리 아낄 수 있다. 장기적으로는 테스트를 통해 비용을 절감하고 서비스 중단 사태를 방지하며 자신감을 고취할 수 있다.

10.2 테스트 시점 많은 개발자가 뒤늦은 시점에 테스트 코드를 작성한다. 이런 개발자들은 테스트가 중요하다는 사실을 알고는 있지만, 원치 않게 의무적으로 테스트를 해야 한다고 여긴다. 이들은 테스트를 개발 과정 맨 나중으로 미뤄 두었다가, 관리팀의 평가 요건을 맞추기 위해 한두 개 뚝딱 만들어 통과시키고는 이내 손을 떼버린다. 이런 방식은 옳지 않다. 테스트는 개발 전, 개발 도중, 개발 후를 통틀어 전면적인 관심사로 취급되어야 한다.

10.2.1 개발 전 애플리케이션을 개발하기에 앞서 테스팅 도구를 설치하고 구성해야 한다. 어떤 테스팅 도구를 선택하든지 애플리케이션에 필수적인 의존성이 있는 것처럼 설치해야 하며, 이런 방식은 개발 하는 동안 애플리케이션을 테스트하는 데 있어 물리적, 심리적 측면으로 도움이 된다. 또한 이 시기는 프로젝트 관리자와 함께 애플리케이션의 행동을 높은 수준에서 정의하기에 적절하다.

10.2.2 개발 도중 애플리케이션의 각 부분을 만들 때마다 테스트를 작성하고 실행한다. 새로운 PHP 클래스를 추가했다면 그 즉시 테스트를 만들어 실행해야 한다. 나중으로 미뤘다간 테스트를 하지 않을 수도 있기 때문이다. 개발 과정에서 테스트를 병행하면 견고하고 안정적인 코드를 구축할 수

80

3부 배포, 테스팅, 튜닝


있으며 새로운 코드로 인해 기존 기능성이 침해되는 부분을 신속하게 찾아내고 리팩토링을 할 수 있다.

10.2.3 개발 후 개발 과정에서 애플리케이션의 모든 행동을 예상하고 테스트하지 못할 수도 있다. 애플리케이 션 출시 후 버그를 발견하면 버그 픽스를 만들어야 하며, 버그 픽스의 올바른 동작을 보장하기 위한 새로운 테스트도 함께 작성해야 한다. 테스트는 일회성 작업이 아니며 애플리케이션과 마 찬가지로 지속적인 수정과 개선이 필요하다. 애플리케이션 코드를 수정하면 그에 따른 영향을 받는 테스트 역시 수정되어야 한다.

10.3 테스트 대상 테스트를 수행할 대상은 애플리케이션을 구성하는 가장 작은 조각들이다. 미시적인 관점에서 볼 때 PHP 애플리케이션에는 PHP 클래스, 메서드, 함수가 있다. 우리는 공개된 클래스, 메서 드, 함수를 테스트해야 하며 이들이 고립된 상태에서 우리가 원하는 대로 행동하는지 확인해야 한다. 각 조각들이 저마다 잘 작동하면 전체 애플리케이션으로 통합된 후에도 잘 작동한다고 확신할 수 있다. 이러한 테스트를 단위 테스트라 부른다. 불행히도 애플리케이션의 개별적인 조각들이 각각 테스트를 거친다 해도 전체 애플리케이션이 제대로 작동한다고 보장할 수는 없다. 이 점이 자동화된 도구로 애플리케이션을 테스트하는 이 유다. 자동화된 도구를 이용하면 애플리케이션의 상위 수준 행동을 거시적인 관점에서 검증할 수 있다. 이러한 테스트를 기능 테스트라 부른다.

10.4 테스트 방법 지금까지 왜, 언제, 무엇을 테스트할지 알아보았다. 이제 더욱 중요한 요소인 코드 테스트 방법 을 이야기해보자. PHP 개발자들은 몇 가지 대표적인 방법을 통해 테스팅에 대한 개념에 접근

10장 테스팅

81


한다. 단위 테스트를 선호하는 개발자가 있는가 하면, 테스트 주도 개발(TDD )을 선호하는 개 발자가 있으며, 행위 주도 개발(BDD )을 선호하는 개발자도 있다. 이런 테스트 방법론들은 상 호 배타적인 관계에 있지 않다.

10.4.1 단위 테스트 PHP 애플리케이션 테스트에 대한 가장 대중적인 접근 방식은 단위 테스트unit test다. 앞서 설명 한 바와 같이 단위 테스트는 큰 애플리케이션에 포함된 클래스, 메서드, 함수를 고립시킨 상태 로 검증하는 테스트 방식이다. 세바스찬 버그만( https://sebastianbergmann.de/)이 제작한

PHP유닛(https://phpunit.de/)은 사실상 표준 PHP 단위 테스트 프레임워크다. PHP유닛 프 레임워크는 xUnit1 테스트 아키텍처를 준수한다.

PHP스펙PHPSpec 같은 대체 프레임워크를 사용해서 단위 테스트를 수행해도 되지만, 가장 널리 쓰이는 PHP 프레임워크들은 대부분 PHP유닛 테스트를 제공한다. PHP 컴포넌트를 개선하 거나 배포하려면 PHP유닛 테스트를 읽고 작성하고 실행하는 방법을 필수적으로 알아야 한다.

PHP 단위 테스트를 설치하고, 작성하고, 실행하는 방법은 이번 장 끝 부분에 나와 있다.

10.4.2 테스트 주도 개발(TDD) 테스트 주도 개발Test-Driven Development (TDD )은 테스트 작성이 애플리케이션 코드 작성보다 선 행되는 테스트 방법론이다. 이 테스트는 의도적인 실패를 통해 애플리케이션의 행동 방식을 묘 사하고, 애플리케이션의 기능이 갖춰지고 나서야 성공적으로 수행된다. TDD는 목표 지향적 인 개발 방법론이며, 무엇을 만들어야 할지, 결과물은 어떻게 작동해야 할지를 사전에 인지할 수 있게 도와준다. 테스트를 전부 작성하기 전까지 애플리케이션 코드를 작성하면 안 된다는 의미는 아니다. 테스 트를 일부 작성하고 그에 관련된 기능을 구현하면 된다. TDD는 테스트 작성과 기능 구현이 계 속 반복되는 과정이며 이 과정은 애플리케이션이 완성될 때까지 점진적으로 진행된다.

1 역자주_ JUnit, NUnit 등 Smaltalk의 SUnit을 계승한 테스트 프레임워크를 통칭하는 용어다.

82

3부 배포, 테스팅, 튜닝


10.4.3 행위 주도 개발(BDD) 행위 주도 개발Behavior-Driven Development ( BDD )은 애플리케이션이 행동하는 방식을 이야기처럼 묘사하는 개발 방법론이다. BDD에는 스펙BDDSpecBDD와 스토리BDDStoryBDD 유형이 있다. 스펙BDD는 인간 친화적인 우아한 언어로 애플리케이션 구현을 묘사하는 단위 테스트 유형이 다. 스펙BDD를 적용한 단위 테스트 도구는 PHP유닛과 동일한 역할을 수행하며, PHP유닛 이 사용하는 xUnit 아키텍처와는 달리 사람이 이야기하는 것처럼 애플리케이션의 행동을 묘 사한다. 예를 들어 PHP유닛으로 작성한 테스트 메서드명이 testRenderTemplate ( )이라면 이에 상응하는 스펙BDD 테스트 메서드명은 itRendersTheTemplate ( )이 된다. 스펙BDD 테스트는 헬퍼 메서드도 이와 유사하게 $this->shouldReturn ( ), $this->shouldBe ( ), $this->shouldThrow ( )처럼 이름을 짓는다. 스펙BDD 테스트는 이처럼 xUnit 계열 도구보

다 훨씬 읽고 이해하기 쉬운 언어를 사용한다. 대표적인 스펙BDD 테스트 도구로는 PHP스펙 PHPSpec

(http://www.phpspec.net/)이 있다.

스토리BDD 도구는 스펙BDD 테스트처럼 인간 친화적인 이야기를 사용하지만 하위 수준 구 현보다는 상위 수준 행동에 관심이 있다. 예를 들자면 스토리BDD 테스트는 여러분의 코드가

PDF 보고서를 작성하고 이메일로 발송하는지 검증한다. 스펙BDD 테스트라면 이 경우 PDF 생성 클래스 메서드가 매개변수를 입력받아 올바르게 PDF 파일을 생성하는지 검증할 것이다. 둘 사이의 차이는 바로 테스트 영역이다. 스토리BDD는 프로젝트 관리자의 관점에서 작성한 이야기(예: “보고서를 생성하고 나에게 이메일로 보내야 함”)와 비슷하고 스펙BDD 테스트는 개발자의 관점에서 작성한 이야기(예: “이 클래스 메서드는 데이터 배열을 전달받아 PDF 파 일에 기록해야 함”)와 비슷하다. 스토리BDD와 스펙BDD 도구는 상호 배타적이지 않으며 좀 더 포괄적인 테스트셋을 구축하기 위해 종종 함께 쓰인다. 스토리BDD 테스트는 보통 포괄적 인 애플리케이션 동작을 정의하기 위해 프로젝트 관리자와 함께 작성하며, 스펙BDD 테스트 는 애플리케이션 구현을 설계하고 구축할 때 작성한다. 대표적인 스토리BDD 테스트 도구로 는 비햇Behat (http://behat.org/)이 있다. TIP

스토리BDD 테스트는 구체적인 구현이 아닌 비즈니스 로직을 묘사하는 테스트다. 좋은 스토리BDD 테스 트는 “장바구니에 상품을 추가할 때 증가하는 결제 금액”을 검증하고, 나쁜 스토리BDD 테스트는 “본문이

product_id=1&quantity=2인 HTTP PUT 요청을 /cart URL에 보낼 때 증가하는 결제 금액”을 검증한 다. 전자는 상위 수준에서 비즈니스 로직만을 포괄적으로 설명하는 반면 후자는 특정 구현에 대해 너무 구체 적으로 묘사하고 있다.

10장 테스팅

83


w w w. h a n b i t . c o . k r

Hanbit eBook

Realtime w w w. h a n b i t . c o . k r / e b o o k

DRM free! 어떤 디바이스에서도 자유롭게

eBook Oriented! 전자책에 꼭 맞는 최적의 내용과 디자인

Hanbit eBook

Hanbit eBook

Realtime 70

Realtime 89 49

MFC 프로그래밍 주식분석 프로그램 만들기 김세훈 지음

Hanbit eBook

Hanbit eBook

Realtime 90

Realtime 92 49

자바 개발자를 위한

Vert.x JavaScript Promise​ azu​지음 /​주우영​옮김

애플리케이션 개발 모바일/웹 메시징 STOMP와 MQTT로 개발하는 IoT 모바일/웹 애플리케이션 Mobile and Web Messaging 제프 메스닐 지음 / 조건희 옮김

이연복 지음


w w w. h a n b i t . c o . k r

즐거운 상상이 가득! 2015년 화제의 신간

즐거운 상상이 가득! 2015년 화제의 신간

전자부품 백과사전 vol.1 찰스 플랫 지음 / 배지은 옮김 / 30,000원

취미공학에 필요한 핵심 전자부품을 사전식으로 정리한 안내서.

전자부품 백과사전 vol.1 찰스 플랫 지음 / 배지은 옮김 / 30,000원

처음 시작하는 센서

취미공학에 필요한 핵심 전자부품을 사전식으로 정리한 안내서.

전자부품 백과사전 vol.2

찰스 플랫 지음 / 가격미정

키모 카르비넨, 테로 카르비넨 지음 임지순 옮김 / 13,000원

세상을 수치로 읽어내는

<전자부품 백과사전> 시리즈의 두 번째 도서다.

부품인 센서를 알려주 는 책. 이 책을 통해 자신 만의 프로젝트에 다양한 처음 센서를 사용해보자.

Zero to Maker

: 누구나 메이커가 될 수 있다 데이비드 랭 지음 / 장재웅 옮김 / 14,000원

전자부품 백과사전 vol.2

찰스 플랫 지음 / 가격미정

일반인에서 메이커로. 날백수에서 무인 잠

<전자부품 백과사전> 시리즈의 수정 회사 CEO 가 된 사나이, 데이비드두 번째 도서다. 랭의 메이커 도전기.

Make: 센서

시작하는 센서

키모 카르비넨, 테로 카르비넨 지음 임지순 옮김 / 13,000원

세상을 수치로 읽어내는 부품인 센서를 알려주

키모 카르비넨, 테로 카르비 넨, 빌 발토카리 지음 는 책. 이 책을 통해 자신 / 가격미정

만의 프로젝트에 다양한

필수 전자부품인 센서를

센서를 사용해보자. 마이크로 컨트롤러 보드

Zero to Maker

: 누구나 메이커가 될 수 있다

에 응용하는 방법을 담

데이비드 랭 지음 / 장재웅 옮김 / 14 ,000원 Maker Pro

았다.

베이첼 지음 / 가격미정 일반인에서 메이커로.존날백수에서 무인 잠

메이커라면 반드시 읽어야 할 필수 계발

수정 회사 CEO가 된 사나이, 데이비드 서. 프로 메이커들과의 인터뷰 및 에세이 랭의 메이커 도전기. 수록.

프로젝트로 배우는 라즈베리 파이

도날드 노리스 지음 / 임지순 옮김

다양한 실전 프로젝트를 통해 라즈베리 파이를 쉽고 재미있게 배워본다.

Maker Pro 존 베이첼 지음 / 가격미정

메이커라면 반드시 읽어야 할 필수 계발

Make: 센서 키모 카르비넨, 테로 카르비 넨, 빌 발토카리 지음 / 가격미정

필수 전자부품인 센서를 마이크로 컨트롤러 보드 에 응용하는 방법을 담 았다.


새로운 패러다임의 최신 PHP를 만나다

PHP는 르네상스를 맞이했다. 객체지향, 네임스페이스, 트레이트, 클로저 등의 현대적 기능과 풍부한 컴포넌트 라이 브러리로 원숙하고 완전한 모던 언어로 다시 태어났다. 하지만 인터넷에는 아직도 낡은 PHP 튜토리얼이 넘쳐난다. 이 책은 ‘PHP The Right Way’의 창안자로 유명한 조시 록하트가 현대화된 PHP의 세련된 기능을 설명하고 올 바른 개발 습관을 길러주는 모범 사례들을 담은 실용서다. PHP에 대한 기본적인 이해가 있으며 자신의 기량을 강 화하고 싶은 모든 개발자를 위한 책이다.

•네임스페이스, 트레이트, 제너레이터, 클로저 등의 모던 PHP 기능 •PHP 컴포넌트를 검색, 사용, 작성하는 방법 •애플리케이션 보안, 데이터베이스 작업, 에러와 예외 등에 대한 모범 사례 •배포, 튜닝, 테스팅, 프로파일링에 필요한 도구와 기술 •페이스북이 선보인 HHVM과 Hack이 최신 PHP에 미친 영향 •프로덕션 서버에 대응하는 로컬 개발 환경 구축

“나는 PHP 언어와 커뮤니티의 현 상황을 제대로 반영한 서적을 찾느라 수년을 보냈다. 이제 주저하지 않고 『Modern PHP』 를 추천한다.” - 에드 핀클러, 개발자 겸 블로거(funkatron.com)

“프로그래밍에서 절대 변하지 않는 진리는 ‘프로그래밍은 변한다’는 사실뿐이다. PHP는 변하고 있고 여러분의 개발 방법 역시 변해야만 한다. 조시는 최신 PHP로 작성하기 위해 알아야 할 도구와 개념을 제시한다.” - 캘 에번스, E.I.C.C. CEO

예제 소스 http://git.io/vchsm

웹 / PHP

한빛미디어와 오라일리의 웹사이트로 오세요. www.hanbit.co.kr www.oreilly.com

정가 22,000원


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.